2015년 4월 22일 수요일

SUNDB Auto Increment 컬럼 사용하기



1. Auto Increment (Identity Column) 사용하기


Table 생성시 Column 속성에 GENERATED ALWAYS AS IDENTITY을 사용한다.


1.1. Auto Increment Column을 가진 Table 생성하기


# T1 tableAuto Increment Column (c1)을 사용하도록 생성한다.

gSQL> CREATE TABLE t1 (c1 BIGINT GENERATED ALWAYS AS IDENTITY, c2 VARCHAR(200));

Table created.

gSQL> \DESC t1;

COLUMN_NAME TYPE                   IS_NULLABLE
----------- ---------------------- -----------
C1          NUMBER(19,0)           FALSE     
C2          CHARACTER VARYING(200) TRUE      


# Auto Increment Column(c1)을 제외한 나머지 column에 데이터 입력

gSQL> INSERT INTO t1 (c2) VALUES ('aaa');

1 row created.

gSQL> INSERT INTO t1 (c2) VALUES ('bbb'), ('ccc'), ('ddd');

3 rows created.

gSQL> SELECT * FROM t1;

C1 C2
-- ---
 1 aaa
 2 bbb
 3 ccc
 4 ddd

4 rows selected.

gSQL>





1.2. 일반 ColumnAuto Increment Column 으로 변경하기


데이터가 입력되어 있는 상태에서는 일반컬럼을 Auto Increment 컬럼으로 변경하는 것은 불가능하며, 별도의 Auto Increment 컬럼을 추가하여 사용한다.


# 일반적인 속성을 가진 Table 생성
gSQL> CREATE TABLE t1 (c1 INTEGER, c2 VARCHAR(100));

Table created.

gSQL> COMMIT;

Commit complete.

gSQL> INSERT INTO t1 VALUES (3, 'aaa'), (5, 'bbb'), (9, 'ccc');

3 rows created.

gSQL> SELECT * FROM t1;

C1 C2
-- ---
 3 aaa
 5 bbb
 9 ccc

3 rows selected.


# T1 tableAuto Increment 컬럼 (c3)을 추가한다.
gSQL> ALTER TABLE t1 ADD COLUMN c3 INTEGER GENERATED ALWAYS AS IDENTITY;

Table altered.

gSQL> \DESC t1;

COLUMN_NAME TYPE                   IS_NULLABLE
----------- ---------------------- -----------
C1          NUMBER(10,0)           TRUE      
C2          CHARACTER VARYING(100) TRUE      
C3          NUMBER(10,0)           FALSE     


# Auto Increment 컬럼(c3)을 추가하면 자동으로 Increment 값이 저장된다.
gSQL> SELECT * FROM t1;

C1 C2  C3
-- --- --
 3 aaa  1
 5 bbb  2
 9 ccc  3

3 rows selected.


# 만일 기존에 사용중인 일반 컬럼(c1)을 더 이상 사용하지 않는 다면 unused 속성을 부여한다. (이것은 대량의 데이터가 입력되어 있을 경우 drop column 보다 효율적이다)

gSQL> ALTER TABLE t1 SET UNUSED COLUMN c1;

Table altered.

gSQL> \DESC t1;

COLUMN_NAME TYPE                   IS_NULLABLE
----------- ---------------------- -----------
C2          CHARACTER VARYING(100) TRUE      
C3          NUMBER(10,0)           FALSE     


gSQL> SELECT * FROM t1;

C2  C3
--- --
aaa  1
bbb  2
ccc  3

3 rows selected.


# 새로 추가한 Auto Increment 컬럼(c3)의 컬럼명을 변경하여 사용할수 있다.
gSQL> ALTER TABLE t1 RENAME COLUMN c3 TO c1;

Table altered.

gSQL> \DESC t1;

COLUMN_NAME TYPE                   IS_NULLABLE
----------- ---------------------- -----------
C2          CHARACTER VARYING(100) TRUE      
C1          NUMBER(10,0)           FALSE     


gSQL> SELECT * FROM t1;

C2  C1
--- --
aaa  1
bbb  2
ccc  3

3 rows selected.

# 지금부터는 Auto Increment 컬럼을 제외한 나머지 컬럼에만 데이터를 입력한다.
gSQL> INSERT INTO t1 (c2) VALUES ('ddd'), ('eee');

2 rows created.

gSQL> SELECT * FROM t1;

C2  C1
--- --
aaa  1
bbb  2
ccc  3
ddd  4
eee  5

5 rows selected.

gSQL>



2015년 4월 20일 월요일

sundb 사용자 권한 분리


SUNDB 사용자의 권한 분리










-- 권한부여 작업은 sysdba 계정을 사용한다.

[sunje@symphony conf]$ gsql --as sysdba

 Copyright (c) 2010, 2014, SUNJESOFT Inc. All rights reserved.
 Release Mercury.2.2.2 revision(14773)

Connected to SUNDB Database.

gSQL>

gSQL> \set linesize 300
gSQL> \set pagesize 1000
gSQL> 


-- 사용할 Tablespace를 생성한다.
gSQL> CREATE TABLESPACE USR_DATA_TBS DATAFILE 'USR_DATA_TBS.dbf' SIZE 10M;
gSQL> CREATE TEMPORARY TABLESPACE USR_INDX_TBS MEMORY 'USR_INDX_TBS' SIZE 10m;
gSQL> 


-- 관리자용 계정을 (app_adm) 생성한다. 계정생성시 Schema도 자동 생성한다.
gSQL> CREATE USER app_adm IDENTIFIED BY app_adm DEFAULT TABLESPACE USR_DATA_TBS TEMPORARY TABLESPACE MEM_TEMP_TBS WITH SCHEMA app_schema;
gSQL> 


-- 사용자용 계정을 (app_usr) 생성한다. (Schema를 제외하고 생성한다)
gSQL> CREATE USER app_usr IDENTIFIED BY app_usr DEFAULT TABLESPACE USR_DATA_TBS TEMPORARY TABLESPACE MEM_TEMP_TBS WITHOUT SCHEMA;
gSQL> 


-- 관리자 계정에 권한을 부여 한다. 
gSQL> GRANT CREATE SESSION ON DATABASE TO app_adm;
gSQL> GRANT CREATE TABLE, CREATE INDEX, CREATE VIEW, CREATE SEQUENCE, ADD CONSTRAINT ON SCHEMA app_schema TO app_adm;
gSQL> GRANT CREATE OBJECT ON TABLESPACE USR_DATA_TBS TO app_adm;
gSQL> GRANT CREATE OBJECT ON TABLESPACE USR_INDX_TBS TO app_adm;
gSQL> 


-- 사용자 계정에 권한을 부여한다.
gSQL> GRANT CREATE SESSION ON DATABASE TO app_usr;
gSQL> GRANT SELECT TABLE, INSERT TABLE, DELETE TABLE, UPDATE TABLE ON SCHEMA app_schema TO app_usr;
gSQL> 


-- 생성된 권한을 확인해 본다.
gSQL> SELECT
  A.GRANTOR_ID,
  A.GRANTEE_ID,
  B.AUTHORIZATION_NAME,
  A.SCHEMA_ID,
  C.SCHEMA_NAME,
  A.PRIVILEGE_TYPE
FROM
  SCHEMA_PRIVILEGES A,
  AUTHORIZATIONS B,
  DEFINITION_SCHEMA.SCHEMATA C
WHERE 1=1
AND A.GRANTEE_ID = B.AUTH_ID
AND A.SCHEMA_ID = C.SCHEMA_ID
;

GRANTOR_ID GRANTEE_ID AUTHORIZATION_NAME SCHEMA_ID SCHEMA_NAME             PRIVILEGE_TYPE 
---------- ---------- ------------------ --------- ----------------------- ---------------
         1          2 SYS                        1 DEFINITION_SCHEMA       SELECT TABLE   
         1          2 SYS                        2 FIXED_TABLE_SCHEMA      SELECT TABLE   
         1          2 SYS                        3 DICTIONARY_SCHEMA       SELECT TABLE   
         1          2 SYS                        4 INFORMATION_SCHEMA      SELECT TABLE   
         1          2 SYS                        5 PERFORMANCE_VIEW_SCHEMA SELECT TABLE   
         1          2 SYS                        6 PUBLIC                  SELECT TABLE   
         1          5 PUBLIC                     6 PUBLIC                  CREATE TABLE   
         1          5 PUBLIC                     6 PUBLIC                  CREATE VIEW    
         1          5 PUBLIC                     6 PUBLIC                  CREATE SEQUENCE
         1          5 PUBLIC                     6 PUBLIC                  CREATE INDEX   
         1          5 PUBLIC                     6 PUBLIC                  ADD CONSTRAINT 
         1          5 PUBLIC                     1 DEFINITION_SCHEMA       SELECT TABLE   
         1          5 PUBLIC                     2 FIXED_TABLE_SCHEMA      SELECT TABLE   
         1         25 APP_ADM                   27 APP_SCHEMA              CREATE TABLE   
         1         25 APP_ADM                   27 APP_SCHEMA              CREATE VIEW    
         1         25 APP_ADM                   27 APP_SCHEMA              CREATE SEQUENCE
         1         25 APP_ADM                   27 APP_SCHEMA              CREATE INDEX   
         1         25 APP_ADM                   27 APP_SCHEMA              ADD CONSTRAINT 
         1         26 APP_USR                   27 APP_SCHEMA              SELECT TABLE   
         1         26 APP_USR                   27 APP_SCHEMA              INSERT TABLE   
         1         26 APP_USR                   27 APP_SCHEMA              DELETE TABLE   
         1         26 APP_USR                   27 APP_SCHEMA              UPDATE TABLE   

22 rows selected.


gSQL> 

2015년 4월 8일 수요일

SUNDB DA+TCP Connection 동시에 사용하기



하나의 프로세스에서 DA Connection 과 TCP Connection을 동시에 사용하기




/*
 * da_tcp_example2.c
 *
 *  Created on: 2015. 4. 8.
 */

// #include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>

/* include sunDB ODBC header */
#include <sundb.h>


#define THREAD_CNT  2

/* struct to hold data to be passed to a thread
 this shows how multiple data items can be passed to a thread */
typedef struct _argv
{
int id;
char name[32];
int argc;
char** argv;
int ret;
int conn_type;
} argv_t;

struct timeval tv_s, tv_e;

SQLHENV     gsEnv[THREAD_CNT];
SQLHDBC     gsDbc[THREAD_CNT];

/* User-specific Definitions */
#define  BUF_LEN          100
#define  MAX_COLUMN_COUNT 1024

#define SUNDB_SQL_THROW( aLabel )               \
    goto aLabel;

#define SUNDB_SQL_TRY( aExpression )            \
    do                                          \
    {                                           \
        if( !(SQL_SUCCEEDED( aExpression ) ) )  \
        {                                       \
            goto SUNDB_FINISH_LABEL;            \
        }                                       \
    } while( 0 )

#define SUNDB_FINISH                            \
    goto SUNDB_FINISH_LABEL;                    \
    SUNDB_FINISH_LABEL:

/* Column structure is as follows. */
typedef struct COLUMN_STRUCT
{
    SQLCHAR      ColName[BUF_LEN];
    SQLSMALLINT  ColNameLen;
    SQLSMALLINT  ColType;
    SQLULEN      ColSize;
    SQLSMALLINT  ColDecimalDigits;
    SQLSMALLINT  ColNullablePtr;
    SQLLEN       ColOctetLength;
    SQLINTEGER   ColLeadingPrecision;
}COLUMN_STRUCT;

/* Data structure is as follows. */
typedef struct DATA_STRUCT
{
    SQLLEN       DataInd;
    SQLSMALLINT  DataType;
    union
    {
        SQLCHAR                            DataChar[BUF_LEN];
        SQLSMALLINT                        DataSmallInt;
        SQLINTEGER                         DataInteger;
        SQLBIGINT                          DataBigInt;
        SQLREAL                            DataReal;
        SQLDOUBLE                          DataDouble;
        SQL_NUMERIC_STRUCT                 DataNumeric;
        SQLBOOLEAN                         DataBoolean;
        SQL_DATE_STRUCT                    DataDate;
        SQL_TIME_STRUCT                    DataTime;
        SQL_TIME_WITH_TIMEZONE_STRUCT      DataTimeTZ;
        SQL_TIMESTAMP_STRUCT               DataTimeStamp;
        SQL_TIMESTAMP_WITH_TIMEZONE_STRUCT DataTimeStampTZ;
        SQL_INTERVAL_STRUCT                DataInterval;
    } Data;
}DATA_STRUCT;

/* Column Data structure is as follows. */
typedef struct COLUMN_DATA_STRUCT
{
    COLUMN_STRUCT  ColInformation;
    DATA_STRUCT    DataValue;
}COLUMN_DATA_STRUCT;

/* Print diagnostic record to console  */
void PrintDiagnosticRecord( SQLSMALLINT aHandleType, SQLHANDLE aHandle )
{
    SQLCHAR       sSQLState[6];
    SQLINTEGER    sNaiveError;
    SQLSMALLINT   sTextLength;
    SQLCHAR       sMessageText[SQL_MAX_MESSAGE_LENGTH];
    SQLSMALLINT   sRecNumber = 1;
    SQLRETURN     sReturn;

    /* SQLGetDiagRec returns the currrent values that contains error, warning */
    while( 1 )
    {
        sReturn = SQLGetDiagRec( aHandleType,
                                 aHandle,
                                 sRecNumber,
                                 sSQLState,
                                 &sNaiveError,
                                 sMessageText,
                                 100,
                                 &sTextLength );

        if( sReturn == SQL_NO_DATA )
        {
            break;
        }

        SUNDB_SQL_TRY( sReturn );

        printf("\n=============================================\n" );
        printf("SQL_DIAG_SQLSTATE     : %s\n", sSQLState );
        printf("SQL_DIAG_NATIVE       : %d\n", sNaiveError );
        printf("SQL_DIAG_MESSAGE_TEXT : %s\n", sMessageText );
        printf("=============================================\n" );

        sRecNumber++;
    }

    return;

    SUNDB_FINISH;

    printf("SQLGetDiagRec() failure.\n" );

    return;
}

/*
 * Code that implements the conversion from little endian mode to the
 * scaled integer.
 *
 * Please note that it is up to the application developer to implement this
 * functionality. The example here is just one of the many possible ways.
 *
 * http://support.microsoft.com/kb/222831
 */

long strtohextoval( SQL_NUMERIC_STRUCT * aNumStr )
{
    long value = 0;

    int  i =1;

    int  last =1;
    int  current;

    int  a = 0;
    int  b = 0;

    for( i = 0; i <= 15; i++ )
    {
        current = (int)aNumStr->val[i];
        a       = current % 16; //Obtain LSD
        b       = current / 16; //Obtain MSD

        value += last* a;
        last   = last * 16;
        value += last* b;
        last   = last * 16;
    }

    return value;
}

/* Select funtion */
SQLRETURN testSelect( SQLHDBC aDbc )
{
    SQLHSTMT                sStmt                           = NULL;
    SQLHDESC                sARD                            = NULL;
    SQLHDESC                sIRD                            = NULL;
    SQLINTEGER              sState                          = 0;
    SQLPOINTER              sData                           = NULL;
    COLUMN_DATA_STRUCT      sColData[MAX_COLUMN_COUNT];
    SQLSMALLINT             sColCount                       = 0;
    SQLCHAR                 sDataBuffer[BUF_LEN];
    SQLLEN                  sCount                          = 0;
    SQLRETURN               sReturn;
    int                     i                               = 0;
    int                     j                               = 0;
    int                     sSign                           = 1;
    long                    sNumericValue                   = 0;
    long                    sDivisor                        = 1;
    float                   sFinalValue                     = 0;

    SUNDB_SQL_TRY( SQLAllocHandle( SQL_HANDLE_STMT,
                                   aDbc,
                                   &sStmt ) );
    sState = 1;

    /* SQLGetStmtAttr returns the current setting of a statement attribute. */
    SUNDB_SQL_TRY( SQLGetStmtAttr( sStmt,
                                   SQL_ATTR_APP_ROW_DESC,
                                   &sARD,
                                   SQL_IS_POINTER,
                                   NULL )
                    == SQL_SUCCESS );

    SUNDB_SQL_TRY( SQLGetStmtAttr( sStmt,
                                   SQL_ATTR_IMP_ROW_DESC,
                                   &sIRD,
                                   SQL_IS_POINTER,
                                   NULL )
                    == SQL_SUCCESS );

     /* SQLExecDirect is way to submit an SQL statement for one-time execution */
    SUNDB_SQL_TRY( SQLExecDirect( sStmt,
                                  (SQLCHAR*)"SELECT * FROM Deposit",
                                  SQL_NTS ) );

    /* SQLNumResultCols returns the number of columns in a result set. */
    SUNDB_SQL_TRY( SQLNumResultCols( sStmt,
                                     &sColCount ) );

    /* SQLDescribeCol returns the result descriptor ? column name,type,
     * column size, decimal digits, and nullability ? for one column in the result set. */
    for( i = 1; i <= sColCount; i ++ )
    {
        SUNDB_SQL_TRY( SQLDescribeCol( sStmt,
                                       i,
                                       sColData[i].ColInformation.ColName,
                                       BUF_LEN,
                                       &sColData[i].ColInformation.ColNameLen,
                                       &sColData[i].ColInformation.ColType,
                                       &sColData[i].ColInformation.ColSize,
                                       &sColData[i].ColInformation.ColDecimalDigits,
                                       &sColData[i].ColInformation.ColNullablePtr ) );

        SUNDB_SQL_TRY( SQLGetDescField( sIRD,
                                        i,
                                        SQL_DESC_OCTET_LENGTH,
                                        &sColData[i].ColInformation.ColOctetLength,
                                        0,
                                        NULL )
                        == SQL_SUCCESS );
    }

    for( i = 1; i <= sColCount; i ++ )
    {
        /* Conversion type(SQL type -> SQL_C type), and specify variables. */

        /*
         *  C Data Types :
         * http://msdn.microsoft.com/en-us/library/windows/desktop/ms714556%28v=vs.85%29.aspx
         * Converting Data from C to SQL Data Types :
         * http://msdn.microsoft.com/en-us/library/windows/desktop/ms716298%28v=vs.85%29.aspx
         */
        switch( sColData[i].ColInformation.ColType )
        {
            case SQL_CHAR:
                /* FALL_THROUGH */ /* Variables used 'SQLCHAR type' is. */
            case SQL_VARCHAR:
                /* FALL_THROUGH */ /* Variables used 'SQLCHAR type' is. */
            case SQL_BINARY:
                /* FALL_THROUGH */ /* Variables used 'SQLCHAR type' is. */
            case SQL_VARBINARY:
                /* FALL_THROUGH */ /* Variables used 'SQLCHAR type' is. */
            case SQL_ROWID:
                sColData[i].DataValue.DataType = SQL_C_CHAR;
                sData = &sColData[i].DataValue.Data.DataChar;
                break;
            case SQL_SMALLINT: /* 'SQL_SMALLINT' type */
                sColData[i].DataValue.DataType = SQL_C_SHORT;
                sData = &sColData[i].DataValue.Data.DataSmallInt;
                break;
            case SQL_INTEGER: /* 'SQL_INTEGER' type */
                sColData[i].DataValue.DataType = SQL_C_LONG;
                sData = &sColData[i].DataValue.Data.DataInteger;
                break;
            case SQL_BIGINT: /* 'SQL_BIGINT' type */
                sColData[i].DataValue.DataType = SQL_C_SBIGINT;
                sData = &sColData[i].DataValue.Data.DataBigInt;
                break;
            case SQL_NUMERIC: /* 'SQL_NUMERIC' type */
                sColData[i].DataValue.DataType = SQL_C_NUMERIC;
                sData = &sColData[i].DataValue.Data.DataNumeric;
                break;
            case SQL_REAL: /* 'SQL_REAL' type */
                sColData[i].DataValue.DataType = SQL_C_FLOAT;
                sData = &sColData[i].DataValue.Data.DataReal;
                break;
            case SQL_DOUBLE: /* 'SQL_DOUBLE' type */
                sColData[i].DataValue.DataType = SQL_C_DOUBLE;
                sData = &sColData[i].DataValue.Data.DataDouble;
                break;
            case SQL_BOOLEAN: /* 'SQL_BOOLEAN' type */
                sColData[i].DataValue.DataType = SQL_C_BOOLEAN;
                sData = &sColData[i].DataValue.Data.DataBoolean;
                break;
            case SQL_TYPE_DATE: /* 'SQL_TYPE_DATE' type */
                sColData[i].DataValue.DataType = SQL_C_TYPE_DATE;
                sData = &sColData[i].DataValue.Data.DataDate;
                break;
            case SQL_TYPE_TIME: /* 'SQL_TYPE_TIME' type */
                sColData[i].DataValue.DataType = SQL_C_TYPE_TIME;
                sData = &sColData[i].DataValue.Data.DataTime;
                break;
            case SQL_TYPE_TIME_WITH_TIMEZONE: /* 'SQL_TYPE_TIME_WITH_TIMEZONE' type */
                sColData[i].DataValue.DataType = SQL_C_TYPE_TIME_WITH_TIMEZONE;
                sData = &sColData[i].DataValue.Data.DataTimeTZ;
                break;
            case SQL_TYPE_TIMESTAMP: /* 'SQL_TYPE_TIMESTAMP' type */
                sColData[i].DataValue.DataType = SQL_C_TYPE_TIMESTAMP;
                sData = &sColData[i].DataValue.Data.DataTimeStamp;
                break;
            case SQL_TYPE_TIMESTAMP_WITH_TIMEZONE: /* 'SQL_TYPE_TIMESTAMP_WITH_TIMEZONE' type */
                sColData[i].DataValue.DataType = SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE;
                sData = &sColData[i].DataValue.Data.DataTimeStampTZ;
                break;
            case SQL_INTERVAL_YEAR: /* 'SQL_INTERVAL_YEAR' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_YEAR;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_MONTH: /* 'SQL_INTERVAL_MONTH' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_MONTH;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_DAY: /* 'SQL_INTERVAL_DAY' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_DAY;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_HOUR: /* 'SQL_INTERVAL_HOUR' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_HOUR;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_MINUTE: /* 'SQL_INTERVAL_MINUTE' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_MINUTE;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_SECOND: /* 'SQL_INTERVAL_SECOND' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_SECOND;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_YEAR_TO_MONTH: /* 'SQL_INTERVAL_YEAR_TO_MONTH' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_YEAR_TO_MONTH;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_DAY_TO_HOUR: /* 'SQL_INTERVAL_DAY_TO_HOUR' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_DAY_TO_HOUR;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_DAY_TO_MINUTE: /* 'SQL_INTERVAL_DAY_TO_MINUTE' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_DAY_TO_MINUTE;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_DAY_TO_SECOND: /* 'SQL_INTERVAL_DAY_TO_SECOND' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_DAY_TO_SECOND;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_HOUR_TO_MINUTE: /* 'SQL_INTERVAL_HOUR_TO_MINUTE' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_HOUR_TO_MINUTE;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_HOUR_TO_SECOND: /* 'SQL_INTERVAL_HOUR_TO_SECOND' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_HOUR_TO_SECOND;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            case SQL_INTERVAL_MINUTE_TO_SECOND: /* 'SQL_INTERVAL_MINUTE_TO_SECOND' type */
                sColData[i].DataValue.DataType = SQL_C_INTERVAL_MINUTE_TO_SECOND;
                sData = &sColData[i].DataValue.Data.DataInterval;
                break;
            default: /* Unknown data type */
                SUNDB_SQL_THROW( SUNDB_FINISH_LABEL );
                break;
        }

        /*
         * SQLBindCol binds application data buffers to columns in the result set.
         *
         * If the TargetType argument is an interval data type,
         * the default interval leading precision (2) and the default interval seconds precision (6),
         * as set in the SQL_DESC_DATETIME_INTERVAL_PRECISION and SQL_DESC_PRECISION fields of the ARD,
         * respectively, are used for the data.
         *
         * If the TargetType argument is SQL_C_NUMERIC, the default precision (driver-defined) and default scale (0),
         * as set in the SQL_DESC_PRECISION and SQL_DESC_SCALE fields of the ARD, are used for the data.
         *
         * If any default precision or scale is not appropriate,
         * the application should explicitly set the appropriate descriptor field by a call to SQLSetDescField or SQLSetDescRec.
         */
        SUNDB_SQL_TRY( SQLBindCol( sStmt,
                                   i,
                                   sColData[i].DataValue.DataType,
                                   sData,
                                   sColData[i].ColInformation.ColOctetLength,
                                   &sColData[i].DataValue.DataInd ) );

        switch( sColData[i].DataValue.DataType )
        {
            case SQL_C_NUMERIC :
                /*
                 * Set the datatype, precision and scale fields of the descriptor for the numeric column.
                 * Otherwise the default precision (driver defined) and scale (0) are returned.
                 */
                SUNDB_SQL_TRY( SQLSetDescField( sARD,
                                                i,
                                                SQL_DESC_PRECISION,
                                                (SQLPOINTER)sColData[i].ColInformation.ColSize,
                                                0 ) );

                SUNDB_SQL_TRY( SQLSetDescField( sARD,
                                                i,
                                                SQL_DESC_SCALE,
                                                (SQLPOINTER)(long)sColData[i].ColInformation.ColDecimalDigits,
                                                0 ) );
                break;
            case SQL_INTERVAL_YEAR:
            case SQL_INTERVAL_MONTH:
            case SQL_INTERVAL_DAY:
            case SQL_INTERVAL_HOUR:
            case SQL_INTERVAL_MINUTE:
            case SQL_INTERVAL_SECOND:
            case SQL_INTERVAL_YEAR_TO_MONTH:
            case SQL_INTERVAL_DAY_TO_HOUR:
            case SQL_INTERVAL_DAY_TO_MINUTE:
            case SQL_INTERVAL_DAY_TO_SECOND:
            case SQL_INTERVAL_HOUR_TO_MINUTE:
            case SQL_INTERVAL_HOUR_TO_SECOND:
            case SQL_INTERVAL_MINUTE_TO_SECOND:
                SUNDB_SQL_TRY( SQLGetDescField( sIRD,
                                                i,
                                                SQL_DESC_DATETIME_INTERVAL_PRECISION,
                                                (void*)&sColData[i].ColInformation.ColLeadingPrecision,
                                                SQL_IS_INTEGER,
                                                0 ) );

                SUNDB_SQL_TRY( SQLSetDescField( sARD,
                                                i,
                                                SQL_DESC_DATETIME_INTERVAL_PRECISION,
                                                (void*)sColData[i].ColInformation.ColLeadingPrecision,
                                                0 ) );
            case SQL_TYPE_TIME:
            case SQL_TYPE_TIME_WITH_TIMEZONE:
            case SQL_TYPE_TIMESTAMP:
            case SQL_TYPE_TIMESTAMP_WITH_TIMEZONE:
                SUNDB_SQL_TRY( SQLSetDescField( sARD,
                                                i,
                                                SQL_DESC_PRECISION,
                                                (void*)sColData[i].ColInformation.ColDecimalDigits,
                                                0 ) );
            default:
                break;
        }
    }

    /* Column names will be printed. */
    printf( "\n" );
    for( i = 1; i <= sColCount; i ++ )
    {
            printf( "%-15s  ", sColData[i].ColInformation.ColName );
    }
    printf( "\n" );

    for( i = 1; i <= sColCount; i ++ )
    {
            printf( "---------------  " );
    }
    printf( "\n" );

    /* Data will be printed. */
    while( 1 )
    {
        sReturn = SQLFetch( sStmt );

        if( sReturn == SQL_NO_DATA )
        {
            break;
        }

        SUNDB_SQL_TRY( sReturn );

        for( i = 1; i <= sColCount; i ++ )
        {
            /* The output format depends on the type of data. */
            switch( sColData[i].DataValue.DataType )
            {
                case SQL_C_CHAR:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%-15s  ", sColData[i].DataValue.Data.DataChar );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_SHORT:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%15d  ", sColData[i].DataValue.Data.DataSmallInt );
                    }
                    else
                    {
                        printf( "%15s  ", "(null)" );
                    }
                    break;
                case SQL_C_LONG:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%15d  ", sColData[i].DataValue.Data.DataInteger );
                    }
                    else
                    {
                        printf( "%15s  ", "(null)" );
                    }
                    break;
                case SQL_C_SBIGINT:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%15ld  ", sColData[i].DataValue.Data.DataBigInt );
                    }
                    else
                    {
                        printf( "%15s  ", "(null)" );
                    }
                    break;
                case SQL_C_NUMERIC:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        /*
                         * Call to convert the little endian mode data into numeric data.
                         */
                        sNumericValue = strtohextoval( &sColData[i].DataValue.Data.DataNumeric );

                        /*
                         * The returned value in the above code is scaled to the value specified
                         * in the scale field of the numeric structure. For example 25.212 would
                         * be returned as 25212. The scale in this case is 3 hence the integer
                         * value needs to be divided by 1000.
                         */
                        sDivisor = 1;

                        if( sColData[i].DataValue.Data.DataNumeric.scale > 0 )
                        {
                            for( j = 0; j <  sColData[i].DataValue.Data.DataNumeric.scale; j++ )
                            {
                                sDivisor = sDivisor * 10;
                            }

                            sFinalValue = (float)sNumericValue / (float)sDivisor;
                        }
                        else
                        {
                            for( j = sColData[i].DataValue.Data.DataNumeric.scale; j < 0; j++ )
                            {
                                sDivisor = sDivisor * 10;
                            }

                            sFinalValue = (float)sNumericValue * (float)sDivisor;
                        }

                        /*
                         * Examine the sign value returned in the sign field for the numeric structure.
                         * NOTE: The ODBC 3.0 spec required drivers to return the sign as
                         * 1 for positive numbers and 2 for negative number. This was changed in the
                         * ODBC 3.5 spec to return 0 for negative instead of 2.
                         */

                        if( sColData[i].DataValue.Data.DataNumeric.sign == 0 )
                        {
                            sSign = -1;
                        }
                        else
                        {
                            sSign = 1;
                        }

                        sFinalValue *= sSign;

                        printf( "%15.3f  ", sFinalValue );
                    }
                    else
                    {
                        printf( "%15s  ", "(null)" );
                    }
                    break;
                case SQL_C_FLOAT:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%15.3f  ", sColData[i].DataValue.Data.DataReal );
                    }
                    else
                    {
                        printf( "%15s  ", "(null)" );
                    }
                    break;
                case SQL_C_DOUBLE:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%15.3f  ", sColData[i].DataValue.Data.DataDouble );
                    }
                    else
                    {
                        printf( "%15s  ", "(null)" );
                    }
                    break;
                case SQL_C_BOOLEAN:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        printf( "%-15s  ",
                                sColData[i].DataValue.Data.DataBoolean ? "true" : "false" );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_TYPE_DATE:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%-4d-%02d-%02d",
                                        sColData[i].DataValue.Data.DataDate.year,
                                        sColData[i].DataValue.Data.DataDate.month,
                                        sColData[i].DataValue.Data.DataDate.day );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_TYPE_TIME:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%02d:%02d:%02d",
                                        sColData[i].DataValue.Data.DataTime.hour,
                                        sColData[i].DataValue.Data.DataTime.minute,
                                        sColData[i].DataValue.Data.DataTime.second );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_TYPE_TIME_WITH_TIMEZONE:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%02u:%02u:%02u.%u +%02d:%02d",
                                        sColData[i].DataValue.Data.DataTimeTZ.hour,
                                        sColData[i].DataValue.Data.DataTimeTZ.minute,
                                        sColData[i].DataValue.Data.DataTimeTZ.second,
                                        sColData[i].DataValue.Data.DataTimeTZ.fraction,
                                        sColData[i].DataValue.Data.DataTimeTZ.timezone_hour,
                                        sColData[i].DataValue.Data.DataTimeTZ.timezone_minute );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_TYPE_TIMESTAMP:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%d-%02d-%02d %02d:%02d:%02d.%u",
                                        sColData[i].DataValue.Data.DataTimeStamp.year,
                                        sColData[i].DataValue.Data.DataTimeStamp.month,
                                        sColData[i].DataValue.Data.DataTimeStamp.day,
                                        sColData[i].DataValue.Data.DataTimeStamp.hour,
                                        sColData[i].DataValue.Data.DataTimeStamp.minute,
                                        sColData[i].DataValue.Data.DataTimeStamp.second,
                                        sColData[i].DataValue.Data.DataTimeStamp.fraction );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%u-%02u-%02u %02u:%02u:%02u.%u +%02d:%02d",
                                        sColData[i].DataValue.Data.DataTimeStampTZ.year,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.month,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.day,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.hour,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.minute,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.second,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.fraction,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.timezone_hour,
                                        sColData[i].DataValue.Data.DataTimeStampTZ.timezone_minute );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_INTERVAL_YEAR:
                    /* FALL_THROUGH */ /* 'Interval_year_month' series use the same format */
                case SQL_C_INTERVAL_MONTH:
                    /* FALL_THROUGH */ /* 'Interval_year_month' series use the same format */
                case SQL_C_INTERVAL_YEAR_TO_MONTH:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%d-%02d",
                                        sColData[i].DataValue.Data.DataInterval.intval.year_month.year,
                                        sColData[i].DataValue.Data.DataInterval.intval.year_month.month );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                case SQL_C_INTERVAL_DAY:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_HOUR:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_MINUTE:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_SECOND:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_DAY_TO_HOUR:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_DAY_TO_MINUTE:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_DAY_TO_SECOND:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_HOUR_TO_MINUTE:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_HOUR_TO_SECOND:
                    /* FALL_THROUGH */ /* 'Interval_day_second' series use the same format */
                case SQL_C_INTERVAL_MINUTE_TO_SECOND:
                    /* check null data */
                    if( sColData[i].DataValue.DataInd != SQL_NULL_DATA )
                    {
                        (void)snprintf( (char*)sDataBuffer,
                                        BUF_LEN,
                                        "%d %02d:%02d:%02d",
                                        sColData[i].DataValue.Data.DataInterval.intval.day_second.day,
                                        sColData[i].DataValue.Data.DataInterval.intval.day_second.hour,
                                        sColData[i].DataValue.Data.DataInterval.intval.day_second.minute,
                                        sColData[i].DataValue.Data.DataInterval.intval.day_second.second );
                        printf( "%-15s  ", sDataBuffer );
                    }
                    else
                    {
                        printf( "%-15s  ", "(null)" );
                    }
                    break;
                default : /* Unknown data type */
                    printf( "Unknown data type : %d\n", sColData[i].DataValue.DataType );
                    SUNDB_SQL_THROW( SUNDB_FINISH_LABEL );
                    break;
            }

            if( i == sColCount )
            {
                printf( "\n");
            }
        }

        /* SQLFetch () is the result of 'SQL_SUCCESS_WITH_INFO', then the error message is output. */
        if( sReturn == SQL_SUCCESS_WITH_INFO )
        {
            PrintDiagnosticRecord( SQL_HANDLE_STMT, sStmt );
        }

        sCount ++;
    }
    printf( "\n%ld rows selected.\n\n", sCount );

    /* SQLFreeHandleStmt frees resources associated with a connection */
    sState = 0;
    SUNDB_SQL_TRY( SQLFreeHandle( SQL_HANDLE_STMT, sStmt ) );

    sStmt = NULL;

    return SQL_SUCCESS;

    SUNDB_FINISH;

    switch(sState)
    {
        case 1:
            PrintDiagnosticRecord( SQL_HANDLE_STMT, sStmt );
            (void)SQLFreeHandle( SQL_HANDLE_STMT, sStmt );
            sStmt = NULL;
        default:
            break;
    }

    return SQL_ERROR;
}

// int thread_proc(int argc, char **argv)
int thread_proc(void* ptr)
{

    argv_t* arg;
    arg = (argv_t*) ptr;

    printf("[%s] start\n", arg->name);

    int conn_type = 0;

    if (arg->argc != 1)
    {
        printf("argc count error\n");
        return (0);
    }

    // connection type (0:DA, 1:TCP)
    conn_type = arg->conn_type;


    SQLHENV     sEnv = NULL;
    SQLHDBC     sDbc = NULL;
    SQLINTEGER  sState = 0;

    sEnv = gsEnv[arg->id];
    sDbc = gsDbc[arg->id];

    /* If you call SQLAllocEnv() that is included in sunDB ODBC*/
    SUNDB_SQL_TRY( SQLAllocHandle( SQL_HANDLE_ENV,
                                    NULL,
                                    &sEnv ) );
    sState = 1;

    /* SQLSetEnvAttr is sets attributes that govern aspects of environments */
    SUNDB_SQL_TRY( SQLSetEnvAttr( sEnv,
                                  SQL_ATTR_ODBC_VERSION,
                                  (SQLPOINTER)SQL_OV_ODBC3,
                                  0 ) );

    /* If you call SQLAllocDbc that is mapped in the Driver Manager to SQLConnect */
    SUNDB_SQL_TRY( SQLAllocHandle( SQL_HANDLE_DBC,
                                   sEnv,
                                   &sDbc ) );
    sState = 2;

    /* SQLConnect establishes connections to a driver and a data source */
/*
    SUNDB_SQL_TRY( SQLConnect( sDbc,
                               (SQLCHAR*)"SUNDB",
                               SQL_NTS,
                               (SQLCHAR*)"test",
                               SQL_NTS,
                               (SQLCHAR*)"test",
                               SQL_NTS) );
*/

    if (conn_type == 0) {
        SUNDB_SQL_TRY( SQLDriverConnect( sDbc,
                               NULL,
                               (SQLCHAR*)"PROTOCOL=DA;UID=TEST;PWD=test",
                               SQL_NTS,
                               NULL,
                               0,
                               NULL,
                               SQL_DRIVER_NOPROMPT) );
    } else {
        // HOST=127.0.0.1;PORT=22581;
        SUNDB_SQL_TRY( SQLDriverConnect( sDbc,
                                   NULL,
                                   (SQLCHAR*)"PROTOCOL=TCP;HOST=192.168.0.13;PORT=32581;UID=TEST;PWD=test",
                                   SQL_NTS,
                                   NULL,
                                   0,
                                   NULL,
                                   SQL_DRIVER_NOPROMPT) );
    }

    sState = 3;

    /* If you SQL_SUCCESS that is Select funtion success */
    SUNDB_SQL_TRY( testSelect( sDbc ) );

    /* SQLDisconnect cloese the connection associated with a specific connection handle */
    sState = 2;
    SUNDB_SQL_TRY( SQLDisconnect( sDbc ) );

    /* SQLFreeHandleDbc frees resources associated with a connection */
    sState = 1;
    SUNDB_SQL_TRY( SQLFreeHandle( SQL_HANDLE_DBC,
                                  sDbc ) );

    sDbc = NULL;

    /* SQLFreeHandleEnv frees resources associated with a environment */
    sState = 0;
    SUNDB_SQL_TRY( SQLFreeHandle( SQL_HANDLE_ENV,
                                  sEnv ) );

    sEnv = NULL;

    printf("(SELECT_SUCCESS)\n");

    printf("end:%s\n", arg->name);
    arg->ret = arg->id;
    pthread_exit(&arg->ret);

    return EXIT_SUCCESS;

    SUNDB_FINISH;

    if( sDbc != NULL)
    {
        PrintDiagnosticRecord( SQL_HANDLE_DBC, sDbc );
    }
    if( sEnv != NULL)
    {
        PrintDiagnosticRecord( SQL_HANDLE_ENV, sEnv );
    }

    switch( sState )
    {
        case 3:
            /* SQLDisconnect cloese the connection associated with a specific connection handle */
            (void)SQLDisconnect( sDbc );
        case 2:
            /* SQLFreeHandleDbc frees resources associated with a connection */
            (void)SQLFreeHandle( SQL_HANDLE_DBC, sDbc );
            sDbc = NULL;
        case 1:
            /* SQLFreeHandleEnv frees resources associated with a environment */
            (void)SQLFreeHandle( SQL_HANDLE_ENV, sEnv );
            sEnv = NULL;
        default:
            break;
    }

    printf("(SELECT_FAILURE)\n");

    printf("end:%s\n", arg->name);
    arg->ret = arg->id;
    pthread_exit(&arg->ret);


    return EXIT_FAILURE;

}

int main(int argc, char **argv)
{
int i = 0;
int thread_count = THREAD_CNT;

pthread_t pthread[THREAD_CNT];
argv_t args[THREAD_CNT];
int* pthread_ret[THREAD_CNT] = { 0x00, };

memset( &gsEnv, 0x00, sizeof(gsEnv));
memset( &gsDbc, 0x00, sizeof(gsDbc));

for (i = 0; i < thread_count; i++)
{
args[i].id = i;
sprintf(args[i].name, "thread-%02d", args[i].id);
args[i].argc = argc;
args[i].argv = argv;

// conn_type (0=DA, 1=TCP)
if (i == 0) {
args[i].conn_type = 0;
} else {
args[i].conn_type = 1;
}
}

for (i = 0; i < thread_count; i++)
{
pthread_create(&pthread[i], NULL, (void*) &thread_proc,
(void*) &args[i]);
}

for (i = 0; i < thread_count; i++)
{
pthread_join(pthread[i], (void**) &pthread_ret[i]);
}

printf("[%d] ========= free.\n", 111);

for (i = 0; i < thread_count; i++)
{
//        printf("[%s] exit->[%d]\n", args[i].name, *pthread_ret[i]);
}

return 0;
}