2015년 4월 22일 수요일

SUNDB Auto Increment 컬럼 사용하기



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


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


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


# T1 table을 Auto 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. 일반 Column을 Auto 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 table에 Auto 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;
}