From f1f5c0c4796ec51a57b90a376fca7c429f7311ae Mon Sep 17 00:00:00 2001 From: freemine Date: Sat, 10 Oct 2020 22:12:15 +0800 Subject: [PATCH] 1. add SQLDriverConnect to let ODBC-aware software to communicate with such as pyodbc 2. SQLDescribeCol 3. more DATA-TYPE-convertions in SQLGetData --- src/CMakeLists.txt | 2 +- src/connector/odbc/src/todbc.c | 2278 +++++++++++++++++++++++++------ src/connector/odbc/tests/main.c | 4 +- src/inc/taoserror.h | 12 +- 4 files changed, 1860 insertions(+), 436 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f619edd221..2ed56d4f81 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,5 +21,5 @@ ADD_SUBDIRECTORY(wal) ADD_SUBDIRECTORY(cq) ADD_SUBDIRECTORY(dnode) ADD_SUBDIRECTORY(connector/odbc) -ADD_SUBDIRECTORY(connector/jdbc) +# ADD_SUBDIRECTORY(connector/jdbc) diff --git a/src/connector/odbc/src/todbc.c b/src/connector/odbc/src/todbc.c index 2c4c0f90bf..6eaaba762f 100644 --- a/src/connector/odbc/src/todbc.c +++ b/src/connector/odbc/src/todbc.c @@ -25,6 +25,7 @@ #include #include #include +#include #define D(fmt, ...) \ @@ -87,6 +88,16 @@ do { \ obj->err.sql_state[0] = '\0'; \ } while (0) +#define SET_UNSUPPORT_ERROR(obj, sqlstate, err_fmt, ...) \ +do { \ + SET_ERROR(obj, sqlstate, TSDB_CODE_COM_OPS_NOT_SUPPORT, err_fmt, ##__VA_ARGS__); \ +} while (0) \ + +#define SET_HANDLE_INVALID(obj, sqlstate, err_fmt, ...) \ +do { \ + SET_ERROR(obj, sqlstate, TSDB_CODE_QRY_INVALID_QHANDLE, err_fmt, ##__VA_ARGS__); \ +} while (0); + #define SDUP(s,n) (s ? (s[n] ? (const char*)strndup((const char*)s,n) : (const char*)s) : strdup("")) #define SFRE(x,s,n) \ do { \ @@ -108,6 +119,25 @@ do { \ r_091c = SQL_SUCCESS; \ } while (0) +#define PROFILING 0 + +#define PROFILE(statement) \ +do { \ + if (!PROFILING) { \ + statement; \ + break; \ + } \ + struct timeval tv0, tv1; \ + gettimeofday(&tv0, NULL); \ + statement; \ + gettimeofday(&tv1, NULL); \ + double delta = difftime(tv1.tv_sec, tv0.tv_sec); \ + delta *= 1000000; \ + delta += (tv1.tv_usec-tv0.tv_usec); \ + delta /= 1000000; \ + D("%s: elapsed: [%.6f]s", #statement, delta); \ +} while (0) + typedef struct env_s env_t; typedef struct conn_s conn_t; typedef struct sql_s sql_t; @@ -116,8 +146,13 @@ typedef struct param_bind_s param_bind_t; struct param_bind_s { SQLUSMALLINT ParameterNumber; + SQLSMALLINT ValueType; + SQLSMALLINT ParameterType; + SQLULEN LengthPrecision; + SQLSMALLINT ParameterScale; SQLPOINTER ParameterValue; - SQLLEN *StrLen_or_Ind; + SQLLEN *StrLen_or_Ind; + unsigned int valid; }; @@ -158,13 +193,23 @@ struct sql_s { taos_error_t err; }; +typedef struct c_target_s c_target_t; +struct c_target_s { + SQLUSMALLINT col; + SQLSMALLINT ct; // c type: SQL_C_XXX + char *ptr; + SQLLEN len; + SQLLEN *soi; +}; + static pthread_once_t init_once = PTHREAD_ONCE_INIT; static void init_routine(void); static int do_field_display_size(TAOS_FIELD *field); static void do_convert(SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrLen_or_Ind, TAOS_FIELD *field, void *row); -SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) { +static SQLRETURN doSQLAllocEnv(SQLHENV *EnvironmentHandle) +{ pthread_once(&init_once, init_routine); env_t *env = (env_t*)calloc(1, sizeof(*env)); @@ -178,7 +223,15 @@ SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) { return SQL_SUCCESS; } -SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) { +SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) +{ + SQLRETURN r; + r = doSQLAllocEnv(EnvironmentHandle); + return r; +} + +static SQLRETURN doSQLFreeEnv(SQLHENV EnvironmentHandle) +{ env_t *env = (env_t*)EnvironmentHandle; if (!env) return SQL_ERROR; @@ -197,8 +250,16 @@ SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) { return SQL_SUCCESS; } -SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, - SQLHDBC *ConnectionHandle) { +SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) +{ + SQLRETURN r; + r = doSQLFreeEnv(EnvironmentHandle); + return r; +} + +static SQLRETURN doSQLAllocConnect(SQLHENV EnvironmentHandle, + SQLHDBC *ConnectionHandle) +{ env_t *env = (env_t*)EnvironmentHandle; if (!env) return SQL_ERROR; @@ -208,7 +269,7 @@ SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, do { conn = (conn_t*)calloc(1, sizeof(*conn)); if (!conn) { - SET_ERROR(env, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to alloc connection handle"); + SET_ERROR(env, "HY000", TSDB_CODE_ODBC_OOM, "failed to alloc connection handle"); break; } @@ -225,7 +286,16 @@ SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, return SQL_ERROR; } -SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) { +SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, + SQLHDBC *ConnectionHandle) +{ + SQLRETURN r; + r = doSQLAllocConnect(EnvironmentHandle, ConnectionHandle); + return r; +} + +static SQLRETURN doSQLFreeConnect(SQLHDBC ConnectionHandle) +{ conn_t *conn = (conn_t*)ConnectionHandle; if (!conn) return SQL_ERROR; @@ -250,10 +320,18 @@ SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) { return SQL_SUCCESS; } -SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, +SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) +{ + SQLRETURN r; + r = doSQLFreeConnect(ConnectionHandle); + return r; +} + +static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle, SQLCHAR *ServerName, SQLSMALLINT NameLength1, SQLCHAR *UserName, SQLSMALLINT NameLength2, - SQLCHAR *Authentication, SQLSMALLINT NameLength3) { + SQLCHAR *Authentication, SQLSMALLINT NameLength3) +{ conn_t *conn = (conn_t*)ConnectionHandle; if (!conn) return SQL_ERROR; @@ -267,15 +345,16 @@ SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, const char *auth = SDUP(Authentication, NameLength3); do { - if (!serverName || !userName || !auth) { - SET_ERROR(conn, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to connect to database"); + if ((ServerName && !serverName) || (UserName && !userName) || (Authentication && !auth)) { + SET_ERROR(conn, "HY000", TSDB_CODE_ODBC_OOM, "failed to allocate resources"); break; } + // TODO: data-race // TODO: shall receive ip/port from odbc.ini conn->taos = taos_connect("localhost", userName, auth, NULL, 0); if (!conn->taos) { - SET_ERROR(conn, "HY000", terrno, "failed to connect to database"); + SET_ERROR(conn, "HY000", terrno, "failed to connect to data source"); break; } } while (0); @@ -287,7 +366,20 @@ SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, return conn->taos ? SQL_SUCCESS : SQL_ERROR; } -SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) { +SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, + SQLCHAR *ServerName, SQLSMALLINT NameLength1, + SQLCHAR *UserName, SQLSMALLINT NameLength2, + SQLCHAR *Authentication, SQLSMALLINT NameLength3) +{ + SQLRETURN r; + r = doSQLConnect(ConnectionHandle, ServerName, NameLength1, + UserName, NameLength2, + Authentication, NameLength3); + return r; +} + +static SQLRETURN doSQLDisconnect(SQLHDBC ConnectionHandle) +{ conn_t *conn = (conn_t*)ConnectionHandle; if (!conn) return SQL_ERROR; @@ -299,8 +391,16 @@ SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) { return SQL_SUCCESS; } -SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, - SQLHSTMT *StatementHandle) { +SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) +{ + SQLRETURN r; + r = doSQLDisconnect(ConnectionHandle); + return r; +} + +static SQLRETURN doSQLAllocStmt(SQLHDBC ConnectionHandle, + SQLHSTMT *StatementHandle) +{ conn_t *conn = (conn_t*)ConnectionHandle; if (!conn) return SQL_ERROR; @@ -309,7 +409,7 @@ SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, do { sql_t *sql = (sql_t*)calloc(1, sizeof(*sql)); if (!sql) { - SET_ERROR(conn, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to alloc statement handle"); + SET_ERROR(conn, "HY000", TSDB_CODE_ODBC_OOM, "failed to alloc statement handle"); break; } @@ -326,13 +426,23 @@ SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, return SQL_ERROR; } -SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, - SQLUSMALLINT Option) { +SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, + SQLHSTMT *StatementHandle) +{ + SQLRETURN r; + r = doSQLAllocStmt(ConnectionHandle, StatementHandle); + return r; +} + +static SQLRETURN doSQLFreeStmt(SQLHSTMT StatementHandle, + SQLUSMALLINT Option) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; + if (Option == SQL_CLOSE) return SQL_SUCCESS; if (Option != SQL_DROP) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "failed to free statement"); + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "free statement with Option[%x] not supported yet", Option); return SQL_ERROR; } @@ -370,12 +480,29 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, return SQL_SUCCESS; } -SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength) { +SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, + SQLUSMALLINT Option) +{ + SQLRETURN r; + r = doSQLFreeStmt(StatementHandle, Option); + return r; +} + +static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle, + SQLCHAR *StatementText, SQLINTEGER TextLength) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } if (sql->rs) { taos_free_result(sql->rs); @@ -404,7 +531,7 @@ SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, SQLRETURN r = SQL_ERROR; do { if (!stxt) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to query"); + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_OOM, "failed to allocate resources"); break; } sql->rs = taos_query(sql->conn->taos, stxt); @@ -416,13 +543,34 @@ SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, return r; } -SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle, - SQLSMALLINT *ColumnCount) { +SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, + SQLCHAR *StatementText, SQLINTEGER TextLength) +{ + SQLRETURN r; + r = doSQLExecDirect(StatementHandle, StatementText, TextLength); + return r; +} + +static SQLRETURN doSQLNumResultCols(SQLHSTMT StatementHandle, + SQLSMALLINT *ColumnCount) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->rs) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->rs) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no result set cached or not ready"); + return SQL_ERROR; + } int fields = taos_field_count(sql->rs); if (ColumnCount) { @@ -432,13 +580,35 @@ SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle, return SQL_SUCCESS; } -SQLRETURN SQL_API SQLRowCount(SQLHSTMT StatementHandle, - SQLLEN *RowCount) { +SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle, + SQLSMALLINT *ColumnCount) +{ + SQLRETURN r; + r = doSQLNumResultCols(StatementHandle, ColumnCount); + return r; +} + +static SQLRETURN doSQLRowCount(SQLHSTMT StatementHandle, + SQLLEN *RowCount) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->rs) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->rs) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no result set cached or not ready"); + return SQL_ERROR; + } + int rows = taos_affected_rows(sql->rs); if (RowCount) { *RowCount = rows; @@ -446,20 +616,60 @@ SQLRETURN SQL_API SQLRowCount(SQLHSTMT StatementHandle, return SQL_SUCCESS; } -SQLRETURN SQL_API SQLColAttribute(SQLHSTMT StatementHandle, - SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, - SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength, SQLLEN *NumericAttribute ) { +SQLRETURN SQL_API SQLRowCount(SQLHSTMT StatementHandle, + SQLLEN *RowCount) +{ + SQLRETURN r; + r = doSQLRowCount(StatementHandle, RowCount); + return r; +} + +static SQLRETURN doSQLColAttribute(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, + SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength, SQLLEN *NumericAttribute ) +{ + D("......"); sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->rs) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->rs) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no result set cached or not ready"); + return SQL_ERROR; + } + int nfields = taos_field_count(sql->rs); TAOS_FIELD *fields = taos_fetch_fields(sql->rs); - if (nfields==0 || fields==NULL) return SQL_ERROR; - if (ColumnNumber>nfields) return SQL_ERROR; + if (nfields==0 || fields==NULL) { + SET_ERROR(sql, "HY000", TSDB_CODE_MND_FIELD_NOT_EXIST, "no fields in result set"); + return SQL_ERROR; + } + + if (ColumnNumber<0) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_APP_ERROR, "ColumnNumber[%d] underflow", ColumnNumber); + return SQL_ERROR; + } + + if (ColumnNumber==0) { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "ColumnNumber[0] not supported"); + return SQL_ERROR; + } + + if (ColumnNumber>nfields) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_APP_ERROR, "ColumnNumber[%d] overflow", ColumnNumber); + return SQL_ERROR; + } TAOS_FIELD *field = fields + ColumnNumber-1; @@ -468,65 +678,454 @@ SQLRETURN SQL_API SQLColAttribute(SQLHSTMT StatementHandle, *NumericAttribute = do_field_display_size(field); } break; case SQL_COLUMN_LABEL: { - strncpy(CharacterAttribute, field->name, field->bytes); + size_t n = sizeof(field->name); + strncpy(CharacterAttribute, field->name, (n>BufferLength ? BufferLength : n)); + } break; + case SQL_COLUMN_UNSIGNED: { + *NumericAttribute = SQL_FALSE; } break; default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "ColumnNumber[%d] FieldIdentifier[%d] not supported yet", + ColumnNumber, FieldIdentifier); return SQL_ERROR; } break; } return SQL_SUCCESS; } -SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle, +SQLRETURN SQL_API SQLColAttribute(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, + SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength, SQLLEN *NumericAttribute ) +{ + SQLRETURN r; + r = doSQLColAttribute(StatementHandle, ColumnNumber, FieldIdentifier, + CharacterAttribute, BufferLength, + StringLength, NumericAttribute); + return r; +} + +static SQLRETURN conv_tsdb_bool_to_c_bit(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_tinyint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_short(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_bool_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b); +static SQLRETURN conv_tsdb_v1_to_c_tinyint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_short(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v1_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1); +static SQLRETURN conv_tsdb_v2_to_c_short(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v2_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v2_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v2_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v2_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v2_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v2_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2); +static SQLRETURN conv_tsdb_v4_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4); +static SQLRETURN conv_tsdb_v4_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4); +static SQLRETURN conv_tsdb_v4_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4); +static SQLRETURN conv_tsdb_v4_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4); +static SQLRETURN conv_tsdb_v4_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4); +static SQLRETURN conv_tsdb_v4_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4); +static SQLRETURN conv_tsdb_v8_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8); +static SQLRETURN conv_tsdb_v8_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8); +static SQLRETURN conv_tsdb_v8_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8); +static SQLRETURN conv_tsdb_v8_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8); +static SQLRETURN conv_tsdb_v8_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8); +static SQLRETURN conv_tsdb_f4_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4); +static SQLRETURN conv_tsdb_f4_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4); +static SQLRETURN conv_tsdb_f4_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4); +static SQLRETURN conv_tsdb_f4_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4); +static SQLRETURN conv_tsdb_f8_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, double f8); +static SQLRETURN conv_tsdb_f8_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, double f8); +static SQLRETURN conv_tsdb_f8_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, double f8); +static SQLRETURN conv_tsdb_ts_to_c_v8(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts); +static SQLRETURN conv_tsdb_ts_to_c_str(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts); +static SQLRETURN conv_tsdb_ts_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts); +static SQLRETURN conv_tsdb_ts_to_c_ts(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts); +static SQLRETURN conv_tsdb_bin_to_c_str(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const unsigned char *bin); +static SQLRETURN conv_tsdb_bin_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const unsigned char *bin); +static SQLRETURN conv_tsdb_str_to_c_bit(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_v1(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_v2(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_v4(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_v8(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_f4(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_f8(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_str(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); +static SQLRETURN conv_tsdb_str_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str); + +static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLPOINTER TargetValue, SQLLEN BufferLength, - SQLLEN *StrLen_or_Ind) { + SQLLEN *StrLen_or_Ind) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->rs) return SQL_ERROR; - if (!sql->row) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->rs) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no result set cached or not ready"); + return SQL_ERROR; + } + + if (!sql->row) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no rows cached or not ready"); + return SQL_ERROR; + } + + DASSERT(TargetValue); + int nfields = taos_field_count(sql->rs); TAOS_FIELD *fields = taos_fetch_fields(sql->rs); - if (nfields==0 || fields==NULL) return SQL_ERROR; - if (ColumnNumber>nfields) return SQL_ERROR; + if (nfields==0 || fields==NULL) { + SET_ERROR(sql, "HY000", TSDB_CODE_MND_FIELD_NOT_EXIST, "no fields in result set"); + return SQL_ERROR; + } + + if (ColumnNumber<0) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_APP_ERROR, "ColumnNumber[%d] underflow", ColumnNumber); + return SQL_ERROR; + } + + if (ColumnNumber==0) { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "ColumnNumber[0] not supported"); + return SQL_ERROR; + } + + if (ColumnNumber>nfields) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_APP_ERROR, "ColumnNumber[%d] overflow", ColumnNumber); + return SQL_ERROR; + } TAOS_FIELD *field = fields + ColumnNumber-1; + void *row = sql->row[ColumnNumber-1]; - switch (TargetType) { - case SQL_CHAR: { - if (sql->row[ColumnNumber-1]) { - do_convert(TargetValue, BufferLength, StrLen_or_Ind, field, sql->row[ColumnNumber-1]); - *StrLen_or_Ind = SQL_NTS; - } else { - *StrLen_or_Ind = SQL_NULL_DATA; + if (!row) { + if (StrLen_or_Ind) { + *StrLen_or_Ind = SQL_NULL_DATA; + } + return SQL_SUCCESS; + } + + c_target_t target = {0}; + target.col = ColumnNumber; + target.ct = TargetType; + target.ptr = TargetValue; + target.len = BufferLength; + target.soi = StrLen_or_Ind; + + SQLRETURN r = SQL_ERROR; + + switch (field->type) { + case TSDB_DATA_TYPE_BOOL: { + int8_t v = *(int8_t*)row; + if (v) v = 1; + switch (target.ct) { + case SQL_C_BIT: return conv_tsdb_bool_to_c_bit(sql, &target, field, v); + case SQL_C_TINYINT: return conv_tsdb_bool_to_c_tinyint(sql, &target, field, v); + case SQL_C_SHORT: return conv_tsdb_bool_to_c_short(sql, &target, field, v); + case SQL_C_LONG: return conv_tsdb_bool_to_c_long(sql, &target, field, v); + case SQL_C_SBIGINT: return conv_tsdb_bool_to_c_sbigint(sql, &target, field, v); + case SQL_C_FLOAT: return conv_tsdb_bool_to_c_float(sql, &target, field, v); + case SQL_C_DOUBLE: return conv_tsdb_bool_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_bool_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_bool_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_TINYINT: { + int8_t v = *(int8_t*)row; + switch (target.ct) { + case SQL_C_TINYINT: return conv_tsdb_v1_to_c_tinyint(sql, &target, field, v); + case SQL_C_SHORT: return conv_tsdb_v1_to_c_short(sql, &target, field, v); + case SQL_C_LONG: return conv_tsdb_v1_to_c_long(sql, &target, field, v); + case SQL_C_SBIGINT: return conv_tsdb_v1_to_c_sbigint(sql, &target, field, v); + case SQL_C_FLOAT: return conv_tsdb_v1_to_c_float(sql, &target, field, v); + case SQL_C_DOUBLE: return conv_tsdb_v1_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_v1_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_v1_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_SMALLINT: { + int16_t v = *(int16_t*)row; + switch (target.ct) { + case SQL_C_SHORT: return conv_tsdb_v2_to_c_short(sql, &target, field, v); + case SQL_C_LONG: return conv_tsdb_v2_to_c_long(sql, &target, field, v); + case SQL_C_SBIGINT: return conv_tsdb_v2_to_c_sbigint(sql, &target, field, v); + case SQL_C_FLOAT: return conv_tsdb_v2_to_c_float(sql, &target, field, v); + case SQL_C_DOUBLE: return conv_tsdb_v2_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_v2_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_v2_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_INT: { + int32_t v = *(int32_t*)row; + switch (target.ct) { + case SQL_C_LONG: return conv_tsdb_v4_to_c_long(sql, &target, field, v); + case SQL_C_SBIGINT: return conv_tsdb_v4_to_c_sbigint(sql, &target, field, v); + case SQL_C_FLOAT: return conv_tsdb_v4_to_c_float(sql, &target, field, v); + case SQL_C_DOUBLE: return conv_tsdb_v4_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_v4_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_v4_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_BIGINT: { + int64_t v = *(int64_t*)row; + switch (target.ct) { + case SQL_C_SBIGINT: return conv_tsdb_v8_to_c_sbigint(sql, &target, field, v); + case SQL_C_FLOAT: return conv_tsdb_v8_to_c_float(sql, &target, field, v); + case SQL_C_DOUBLE: return conv_tsdb_v8_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_v8_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_v8_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_FLOAT: { + float v = *(float*)row; + switch (target.ct) { + case SQL_C_FLOAT: return conv_tsdb_f4_to_c_float(sql, &target, field, v); + case SQL_C_DOUBLE: return conv_tsdb_f4_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_f4_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_f4_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_DOUBLE: { + double v = *(double*)row; + switch (target.ct) { + case SQL_C_DOUBLE: return conv_tsdb_f8_to_c_double(sql, &target, field, v); + case SQL_C_CHAR: return conv_tsdb_f8_to_c_char(sql, &target, field, v); + case SQL_C_BINARY: return conv_tsdb_f8_to_c_binary(sql, &target, field, v); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_TIMESTAMP: { + TIMESTAMP_STRUCT ts = {0}; + int64_t v = *(int64_t*)row; + time_t t = v/1000; + struct tm tm = {0}; + localtime_r(&t, &tm); + ts.year = tm.tm_year + 1900; + ts.month = tm.tm_mon + 1; + ts.day = tm.tm_mday; + ts.hour = tm.tm_hour; + ts.minute = tm.tm_min; + ts.second = tm.tm_sec; + ts.fraction = v%1000; + switch (target.ct) { + case SQL_C_SBIGINT: return conv_tsdb_ts_to_c_v8(sql, &target, field, &ts); + case SQL_C_CHAR: return conv_tsdb_ts_to_c_str(sql, &target, field, &ts); + case SQL_C_BINARY: return conv_tsdb_ts_to_c_bin(sql, &target, field, &ts); + case SQL_C_TIMESTAMP: return conv_tsdb_ts_to_c_ts(sql, &target, field, &ts); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_BINARY: { + const unsigned char *bin = (const unsigned char *)row; + switch (target.ct) { + case SQL_C_CHAR: return conv_tsdb_bin_to_c_str(sql, &target, field, bin); + case SQL_C_BINARY: return conv_tsdb_bin_to_c_bin(sql, &target, field, bin); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } + } + } break; + case TSDB_DATA_TYPE_NCHAR: { + const char *str = (const char *)row; + switch (target.ct) { + case SQL_C_BIT: return conv_tsdb_str_to_c_bit(sql, &target, field, str); + case SQL_C_TINYINT: return conv_tsdb_str_to_c_v1(sql, &target, field, str); + case SQL_C_SHORT: return conv_tsdb_str_to_c_v2(sql, &target, field, str); + case SQL_C_LONG: return conv_tsdb_str_to_c_v4(sql, &target, field, str); + case SQL_C_SBIGINT: return conv_tsdb_str_to_c_v8(sql, &target, field, str); + case SQL_C_FLOAT: return conv_tsdb_str_to_c_f4(sql, &target, field, str); + case SQL_C_DOUBLE: return conv_tsdb_str_to_c_f8(sql, &target, field, str); + case SQL_C_CHAR: return conv_tsdb_str_to_c_str(sql, &target, field, str); + case SQL_C_BINARY: return conv_tsdb_str_to_c_bin(sql, &target, field, str); + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "from TSDB_DATA_TYPE [%d] to SQL_C_TYPE [%d] not supported", field->type, target.ct); + return SQL_ERROR; + } } } break; default: { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_CONV_NOT_SUPPORT, "field [@%d] type [%d] not supported yet", ColumnNumber, field->type); return SQL_ERROR; } break; } + + if (1) return r; + + switch (TargetType) { + case SQL_C_CHAR: { + do_convert(TargetValue, BufferLength, StrLen_or_Ind, field, row); + } break; + case SQL_C_TIMESTAMP: { + TIMESTAMP_STRUCT ts = {0}; + DASSERT(BufferLength == sizeof(ts)); + int64_t v = *(int64_t*)row; + time_t t = v/1000; + struct tm tm = {0}; + localtime_r(&t, &tm); + ts.year = tm.tm_year + 1900; + ts.month = tm.tm_mon + 1; + ts.day = tm.tm_mday; + ts.hour = tm.tm_hour; + ts.minute = tm.tm_min; + ts.second = tm.tm_sec; + ts.fraction = 0; + + memcpy(TargetValue, &ts, sizeof(ts)); + } break; + case SQL_C_LONG: { + int32_t v = *(int32_t*)row; + DASSERT(BufferLength == sizeof(v)); + memcpy(TargetValue, &v, sizeof(v)); + } break; + case SQL_C_SBIGINT: { + int64_t v = *(int64_t*)row; + DASSERT(BufferLength == sizeof(v)); + memcpy(TargetValue, &v, sizeof(v)); + } break; + case SQL_C_FLOAT: { + float v = *(float*)row; + DASSERT(BufferLength == sizeof(v)); + memcpy(TargetValue, &v, sizeof(v)); + } break; + case SQL_C_DOUBLE: { + double v = *(double*)row; + DASSERT(BufferLength == sizeof(v)); + memcpy(TargetValue, &v, sizeof(v)); + } break; + case SQL_C_BINARY: { + if (StrLen_or_Ind) { + if (field->type == TSDB_DATA_TYPE_NCHAR) { + *StrLen_or_Ind = strnlen((const char*)row, field->bytes); + } else { + *StrLen_or_Ind = field->bytes; + } + } + size_t n = field->bytes; + if (n>BufferLength) n = BufferLength; + memcpy(TargetValue, (const char*)row, n); + } break; + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "ColumnNumber[%d] TargetType[%d] BufferLength[%ld] not supported yet", + ColumnNumber, TargetType, BufferLength); + return SQL_ERROR; + } break; + } + return SQL_SUCCESS; } -SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) { +SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, + SQLPOINTER TargetValue, SQLLEN BufferLength, + SQLLEN *StrLen_or_Ind) +{ + SQLRETURN r; + r = doSQLGetData(StatementHandle, ColumnNumber, TargetType, + TargetValue, BufferLength, + StrLen_or_Ind); + return r; +} + +static SQLRETURN doSQLFetch(SQLHSTMT StatementHandle) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->rs) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->rs) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no result set cached or not ready"); + return SQL_ERROR; + } + sql->row = taos_fetch_row(sql->rs); return sql->row ? SQL_SUCCESS : SQL_NO_DATA; } -SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength) { +SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) +{ + SQLRETURN r; + r = doSQLFetch(StatementHandle); + return r; +} + +static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle, + SQLCHAR *StatementText, SQLINTEGER TextLength) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } if (sql->rs) { taos_free_result(sql->rs); @@ -568,12 +1167,33 @@ SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle, return sql->stmt ? SQL_SUCCESS : SQL_ERROR; } -SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) { +SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle, + SQLCHAR *StatementText, SQLINTEGER TextLength) +{ + SQLRETURN r; + r = doSQLPrepare(StatementHandle, StatementText, TextLength); + return r; +} + +static SQLRETURN doSQLExecute(SQLHSTMT StatementHandle) +{ sql_t *sql = (sql_t*)StatementHandle; if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->stmt) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->stmt) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_SQL, "no statement cached or not ready"); + return SQL_ERROR; + } if (sql->rs) { taos_free_result(sql->rs); @@ -635,20 +1255,20 @@ SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) { } if (sql->n_params > 0) { - r = taos_stmt_bind_param(sql->stmt, sql->binds); + PROFILE(r = taos_stmt_bind_param(sql->stmt, sql->binds)); if (r) { SET_ERROR(sql, "HY000", r, "failed to bind parameters"); return SQL_ERROR; } - r = taos_stmt_add_batch(sql->stmt); + PROFILE(r = taos_stmt_add_batch(sql->stmt)); if (r) { SET_ERROR(sql, "HY000", r, "failed to add batch"); return SQL_ERROR; } } - r = taos_stmt_execute(sql->stmt); + PROFILE(r = taos_stmt_execute(sql->stmt)); if (r) { SET_ERROR(sql, "HY000", r, "failed to execute statement"); return SQL_ERROR; @@ -656,25 +1276,48 @@ SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) { SQLRETURN ret = SQL_ERROR; - sql->rs = taos_stmt_use_result(sql->stmt); + PROFILE(sql->rs = taos_stmt_use_result(sql->stmt)); CHK_RS(ret, sql, "failed to use result"); return ret; } -SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, +SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) +{ + SQLRETURN r; + PROFILE(r = doSQLExecute(StatementHandle)); + return r; +} + +static SQLRETURN doSQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength) { + SQLSMALLINT *StringLength) +{ // if this function is not exported, isql will never call SQLGetDiagRec return SQL_ERROR; } -SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, +SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, + SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, + SQLPOINTER DiagInfo, SQLSMALLINT BufferLength, + SQLSMALLINT *StringLength) +{ + SQLRETURN r; + r = doSQLGetDiagField(HandleType, Handle, + RecNumber, DiagIdentifier, + DiagInfo, BufferLength, + StringLength); + return r; +} + +static SQLRETURN doSQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR *MessageText, - SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) { + SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) +{ if (RecNumber>1) return SQL_NO_DATA; + switch (HandleType) { case SQL_HANDLE_ENV: { env_t *env = (env_t*)Handle; @@ -698,9 +1341,204 @@ SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, } break; } + // how to return error? return SQL_ERROR; } +SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, + SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, + SQLINTEGER *NativeError, SQLCHAR *MessageText, + SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) +{ + SQLRETURN r; + r = doSQLGetDiagRec(HandleType, Handle, + RecNumber, Sqlstate, + NativeError, MessageText, + BufferLength, TextLength); + return r; +} + +static SQLRETURN doSQLBindParameter( + SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT fParamType, + SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, + SQLULEN LengthPrecision, + SQLSMALLINT ParameterScale, + SQLPOINTER ParameterValue, + SQLLEN cbValueMax, // ignore for now, since only SQL_PARAM_INPUT is supported now + SQLLEN *StrLen_or_Ind) +{ + sql_t *sql = (sql_t*)StatementHandle; + if (!sql) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->stmt) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_SQL, "no statement cached or not ready"); + return SQL_ERROR; + } + + if (fParamType != SQL_PARAM_INPUT) { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "non-input parameter [@%d] not supported yet", ParameterNumber); + return SQL_ERROR; + } + + int buffer_type = 0; + + // ref: https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/converting-data-from-c-to-sql-data-types?view=sql-server-ver15 + switch (ValueType) { + case SQL_C_BIT: { + switch (ParameterType) { + case SQL_BIT: buffer_type = TSDB_DATA_TYPE_BOOL; break; + case SQL_TINYINT: buffer_type = TSDB_DATA_TYPE_TINYINT; break; + case SQL_SMALLINT: buffer_type = TSDB_DATA_TYPE_SMALLINT; break; + case SQL_INTEGER: buffer_type = TSDB_DATA_TYPE_INT; break; + case SQL_BIGINT: buffer_type = TSDB_DATA_TYPE_BIGINT; break; + case SQL_FLOAT: buffer_type = TSDB_DATA_TYPE_FLOAT; break; + case SQL_DOUBLE: buffer_type = TSDB_DATA_TYPE_DOUBLE; break; + case SQL_VARCHAR: buffer_type = TSDB_DATA_TYPE_NCHAR; break; + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "parameter[@%d] no conversion from [%d] to [%d]", + ParameterNumber, ValueType, ParameterType); + return SQL_ERROR; + } break; + } + } break; + case SQL_C_TINYINT: + case SQL_C_SHORT: + case SQL_C_LONG: + case SQL_C_SBIGINT: + case SQL_C_FLOAT: + case SQL_C_DOUBLE: + case SQL_C_NUMERIC: { + switch (ParameterType) { + case SQL_BIT: buffer_type = TSDB_DATA_TYPE_BOOL; break; + case SQL_TINYINT: buffer_type = TSDB_DATA_TYPE_TINYINT; break; + case SQL_SMALLINT: buffer_type = TSDB_DATA_TYPE_SMALLINT; break; + case SQL_INTEGER: buffer_type = TSDB_DATA_TYPE_INT; break; + case SQL_BIGINT: buffer_type = TSDB_DATA_TYPE_BIGINT; break; + case SQL_FLOAT: buffer_type = TSDB_DATA_TYPE_FLOAT; break; + case SQL_DOUBLE: buffer_type = TSDB_DATA_TYPE_DOUBLE; break; + case SQL_VARCHAR: buffer_type = TSDB_DATA_TYPE_NCHAR; break; + case SQL_TIMESTAMP: buffer_type = TSDB_DATA_TYPE_TIMESTAMP; break; // extention to taos + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "parameter[@%d] no conversion from [%d] to [%d]", + ParameterNumber, ValueType, ParameterType); + return SQL_ERROR; + } break; + } + } break; + case SQL_C_DATE: + case SQL_C_TIME: + case SQL_C_TIMESTAMP: { + switch (ParameterType) { + case SQL_VARCHAR: buffer_type = TSDB_DATA_TYPE_NCHAR; break; + case SQL_TIMESTAMP: buffer_type = TSDB_DATA_TYPE_TIMESTAMP; break; // extention to taos + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "parameter[@%d] no conversion from [%d] to [%d]", + ParameterNumber, ValueType, ParameterType); + return SQL_ERROR; + } break; + } + } break; + case SQL_C_CHAR: { + switch (ParameterType) { + case SQL_BIT: buffer_type = TSDB_DATA_TYPE_BOOL; break; + case SQL_TINYINT: buffer_type = TSDB_DATA_TYPE_TINYINT; break; + case SQL_SMALLINT: buffer_type = TSDB_DATA_TYPE_SMALLINT; break; + case SQL_INTEGER: buffer_type = TSDB_DATA_TYPE_INT; break; + case SQL_BIGINT: buffer_type = TSDB_DATA_TYPE_BIGINT; break; + case SQL_FLOAT: buffer_type = TSDB_DATA_TYPE_FLOAT; break; + case SQL_DOUBLE: buffer_type = TSDB_DATA_TYPE_DOUBLE; break; + case SQL_VARCHAR: buffer_type = TSDB_DATA_TYPE_NCHAR; break; + case SQL_VARBINARY: buffer_type = TSDB_DATA_TYPE_BINARY; break; + case SQL_TIMESTAMP: buffer_type = TSDB_DATA_TYPE_TIMESTAMP; break; // extention to taos + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "parameter[@%d] no conversion from [%d] to [%d]", + ParameterNumber, ValueType, ParameterType); + return SQL_ERROR; + } break; + } + } break; + case SQL_C_BINARY: { + switch (ParameterType) { + case SQL_BIT: buffer_type = TSDB_DATA_TYPE_BOOL; break; + case SQL_TINYINT: buffer_type = TSDB_DATA_TYPE_TINYINT; break; + case SQL_SMALLINT: buffer_type = TSDB_DATA_TYPE_SMALLINT; break; + case SQL_INTEGER: buffer_type = TSDB_DATA_TYPE_INT; break; + case SQL_BIGINT: buffer_type = TSDB_DATA_TYPE_BIGINT; break; + case SQL_FLOAT: buffer_type = TSDB_DATA_TYPE_FLOAT; break; + case SQL_DOUBLE: buffer_type = TSDB_DATA_TYPE_DOUBLE; break; + case SQL_VARCHAR: buffer_type = TSDB_DATA_TYPE_NCHAR; break; + case SQL_VARBINARY: buffer_type = TSDB_DATA_TYPE_BINARY; break; + case SQL_TIMESTAMP: buffer_type = TSDB_DATA_TYPE_TIMESTAMP; break; // extention to taos + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "parameter[@%d] no conversion from [%d] to [%d]", + ParameterNumber, ValueType, ParameterType); + return SQL_ERROR; + } break; + } + } break; + default: { + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, + "parameter[@%d] no conversion from [%d] to [%d]", + ParameterNumber, ValueType, ParameterType); + return SQL_ERROR; + } break; + } + + param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); + TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); + if (!ar || !binds) { + SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_OOM, "failed to allocate resources for Parameter[%d]", ParameterNumber); + if (ar) sql->params = ar; + if (binds) sql->binds = binds; + return SQL_ERROR; + } + sql->params = ar; + sql->binds = binds; + if (sql->n_paramsn_params = ParameterNumber; + } + + param_bind_t *pb = ar + ParameterNumber - 1; + TAOS_BIND *b = binds + ParameterNumber - 1; + + b->buffer_type = buffer_type; + b->buffer_length = LengthPrecision; + b->buffer = NULL; + b->length = NULL; + b->is_null = NULL; + b->is_unsigned = 0; + b->error = NULL; + + pb->ParameterNumber = ParameterNumber; + pb->ValueType = ValueType; + pb->ParameterType = ParameterType; + pb->LengthPrecision = LengthPrecision; + pb->ParameterScale = ParameterScale; + pb->ParameterValue = ParameterValue; + pb->StrLen_or_Ind = StrLen_or_Ind; + + pb->valid = 1; + return SQL_SUCCESS; +} + SQLRETURN SQL_API SQLBindParameter( SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, @@ -711,362 +1549,252 @@ SQLRETURN SQL_API SQLBindParameter( SQLSMALLINT ParameterScale, SQLPOINTER ParameterValue, SQLLEN cbValueMax, // ignore for now, since only SQL_PARAM_INPUT is supported now - SQLLEN *StrLen_or_Ind) { - sql_t *sql = (sql_t*)StatementHandle; - if (!sql) return SQL_ERROR; - if (!sql->conn) return SQL_ERROR; - if (!sql->conn->taos) return SQL_ERROR; - if (!sql->stmt) return SQL_ERROR; + SQLLEN *StrLen_or_Ind) +{ + SQLRETURN r; + r = doSQLBindParameter(StatementHandle, ParameterNumber, fParamType, ValueType, ParameterType, + LengthPrecision, ParameterScale, ParameterValue, cbValueMax, StrLen_or_Ind); + return r; +} - if (fParamType != SQL_PARAM_INPUT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "non-input parameter [@%d] not supported yet", ParameterNumber); +static SQLRETURN doSQLDriverConnect( + SQLHDBC hdbc, + SQLHWND hwnd, + SQLCHAR *szConnStrIn, + SQLSMALLINT cbConnStrIn, + SQLCHAR *szConnStrOut, + SQLSMALLINT cbConnStrOutMax, + SQLSMALLINT *pcbConnStrOut, + SQLUSMALLINT fDriverCompletion) +{ + conn_t *conn = (conn_t*)hdbc; + if (!conn) return SQL_ERROR; + + if (fDriverCompletion!=SQL_DRIVER_NOPROMPT) { + SET_ERROR(conn, "HY000", TSDB_CODE_TSC_APP_ERROR, "option[%d] other than SQL_DRIVER_NOPROMPT not supported yet", fDriverCompletion); return SQL_ERROR; } - switch (ParameterType) { - case SQL_BIT: { // TSDB_DATA_TYPE_BOOL - if (ValueType!=SQL_C_BIT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_BOOL; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_TINYINT: { // TSDB_DATA_TYPE_TINYINT - if (ValueType!=SQL_C_TINYINT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_TINYINT; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_SMALLINT: { // TSDB_DATA_TYPE_SMALLINT - if (ValueType!=SQL_C_SHORT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_SMALLINT; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_INTEGER: { // TSDB_DATA_TYPE_INT - if (ValueType!=SQL_C_LONG) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_INT; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_BIGINT: { // TSDB_DATA_TYPE_BIGINT - if (ValueType!=SQL_C_SBIGINT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_BIGINT; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_FLOAT: { // TSDB_DATA_TYPE_FLOAT - if (ValueType!=SQL_C_FLOAT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_FLOAT; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_DOUBLE: { // TSDB_DATA_TYPE_DOUBLE - if (ValueType!=SQL_C_DOUBLE) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_DOUBLE; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_TIMESTAMP: { // TSDB_DATA_TYPE_TIMESTAMP - if (ValueType!=SQL_C_SBIGINT) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - // LengthPrecision ignored; - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_TIMESTAMP; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_VARBINARY: { // TSDB_DATA_TYPE_BINARY - if (ValueType!=SQL_C_BINARY) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - if (LengthPrecision <=0) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching length precision", ParameterNumber); - return SQL_ERROR; - } - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_BINARY; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - case SQL_VARCHAR: { // TSDB_DATA_TYPE_NCHAR - if (ValueType!=SQL_C_CHAR) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching value type", ParameterNumber); - return SQL_ERROR; - } - if (LengthPrecision <=0) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "parameter [@%d] not matching length precision", ParameterNumber); - return SQL_ERROR; - } - // ParameterScale ignored; - param_bind_t *ar = (param_bind_t*)(sql->n_params>=ParameterNumber ? sql->params : realloc(sql->params, ParameterNumber * sizeof(*ar))); - TAOS_BIND *binds = (TAOS_BIND*)(sql->n_params>=ParameterNumber ? sql->binds : realloc(sql->binds, ParameterNumber * sizeof(*binds))); - if (!ar || !binds) { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to bind parameter [@%d]", ParameterNumber); - if (ar) sql->params = ar; - if (binds) sql->binds = binds; - return SQL_ERROR; - } - sql->params = ar; - sql->binds = binds; - if (sql->n_paramsn_params = ParameterNumber; - } - param_bind_t *pb = ar + ParameterNumber - 1; - TAOS_BIND *b = binds + ParameterNumber - 1; - b->buffer_type = TSDB_DATA_TYPE_NCHAR; - b->buffer_length = LengthPrecision; - b->buffer = NULL; - b->length = NULL; - b->is_null = NULL; - b->is_unsigned = 0; - b->error = NULL; - pb->ParameterValue = ParameterValue; - pb->StrLen_or_Ind = StrLen_or_Ind; - pb->valid = 1; - } break; - default: { - SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "xdoes not support parameter type[%x]", ParameterType); - return SQL_ERROR; - } break; + + if (conn->taos) { + SET_ERROR(conn, "HY000", TSDB_CODE_TSC_APP_ERROR, "connection still in use"); + return SQL_ERROR; } + + // DSN=; UID=; PWD= + + const char *connStr = SDUP(szConnStrIn, cbConnStrIn); + + char *serverName = NULL; + char *userName = NULL; + char *auth = NULL; + int bytes = 0; + + do { + if (szConnStrIn && !connStr) { + SET_ERROR(conn, "HY000", TSDB_CODE_ODBC_OOM, "failed to allocate resources"); + break; + } + + int n = sscanf((const char*)connStr, "DSN=%m[^;]; UID=%m[^;]; PWD=%m[^;] %n", &serverName, &userName, &auth, &bytes); + if (n<1) { + SET_ERROR(conn, "HY000", TSDB_CODE_RPC_NETWORK_UNAVAIL, "unrecognized connection string: [%s]", (const char*)szConnStrIn); + break; + } + + D("DSN:[%s];UID:[%s];PWD:[%s]", serverName, userName, auth); + + // TODO: data-race + // TODO: shall receive ip/port from odbc.ini + conn->taos = taos_connect("localhost", userName, auth, NULL, 0); + if (!conn->taos) { + SET_ERROR(conn, "HY000", terrno, "failed to connect to data source"); + break; + } + + if (szConnStrOut) { + snprintf((char*)szConnStrOut, cbConnStrOutMax, "%s", connStr); + } + if (pcbConnStrOut) { + *pcbConnStrOut = cbConnStrIn; + } + + } while (0); + + if (serverName) free(serverName); + if (userName) free(userName); + if (auth) free(auth); + + SFRE(connStr, szConnStrIn, cbConnStrIn); + + return conn->taos ? SQL_SUCCESS : SQL_ERROR; +} + +SQLRETURN SQL_API SQLDriverConnect( + SQLHDBC hdbc, + SQLHWND hwnd, + SQLCHAR *szConnStrIn, + SQLSMALLINT cbConnStrIn, + SQLCHAR *szConnStrOut, + SQLSMALLINT cbConnStrOutMax, + SQLSMALLINT *pcbConnStrOut, + SQLUSMALLINT fDriverCompletion) +{ + SQLRETURN r; + r = doSQLDriverConnect(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion); + return r; +} + +static SQLRETURN doSQLSetConnectAttr(SQLHDBC ConnectionHandle, + SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER StringLength) +{ + conn_t *conn = (conn_t*)ConnectionHandle; + if (!conn) return SQL_ERROR; + + if (Attribute != SQL_ATTR_AUTOCOMMIT) { + SET_ERROR(conn, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "Attribute other than SQL_ATTR_AUTOCOMMIT not supported yet"); + return SQL_ERROR; + } + if (Value != (SQLPOINTER)SQL_AUTOCOMMIT_ON) { + SET_ERROR(conn, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "Attribute Value other than SQL_AUTOCOMMIT_ON not supported yet[%p]", Value); + return SQL_ERROR; + } + return SQL_SUCCESS; } +SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC ConnectionHandle, + SQLINTEGER Attribute, SQLPOINTER Value, + SQLINTEGER StringLength) +{ + SQLRETURN r; + r = doSQLSetConnectAttr(ConnectionHandle, Attribute, Value, StringLength); + return r; +} + +static SQLRETURN doSQLDescribeCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, + SQLSMALLINT BufferLength, SQLSMALLINT *NameLength, + SQLSMALLINT *DataType, SQLULEN *ColumnSize, + SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) +{ + sql_t *sql = (sql_t*)StatementHandle; + if (!sql) return SQL_ERROR; + + if (!sql->conn) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection yet"); + return SQL_ERROR; + } + + if (!sql->conn->taos) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_INVALID_CONNECTION, "no connection to data source yet"); + return SQL_ERROR; + } + + if (!sql->rs) { + SET_ERROR(sql, "HY000", TSDB_CODE_TSC_QUERY_CACHE_ERASED, "no result set cached or not ready"); + return SQL_ERROR; + } + + TAOS_FIELD *fields = taos_fetch_fields(sql->rs); + if (!fields) { + SET_ERROR(sql, "HY000", TSDB_CODE_MND_FIELD_NOT_EXIST, "fields not ready or unavailable"); + return SQL_ERROR; + } + int nfields = taos_field_count(sql->rs); + if (ColumnNumber<1 || ColumnNumber>nfields) { + SET_ERROR(sql, "HY000", TSDB_CODE_MND_FIELD_NOT_EXIST, "ColumnNumber not in valid range"); + return SQL_ERROR; + } + + TAOS_FIELD *field = fields + ColumnNumber - 1; + if (ColumnName) { + size_t n = sizeof(field->name); + if (n>BufferLength) n = BufferLength; + strncpy((char*)ColumnName, field->name, n); + } + if (NameLength) { + *NameLength = strnlen(field->name, sizeof(field->name)); + } + if (DataType) { + switch (field->type) { + case TSDB_DATA_TYPE_BOOL: { + *DataType = SQL_C_TINYINT; + } break; + + case TSDB_DATA_TYPE_TINYINT: { + *DataType = SQL_C_TINYINT; + } break; + + case TSDB_DATA_TYPE_SMALLINT: { + *DataType = SQL_C_SHORT; + } break; + + case TSDB_DATA_TYPE_INT: { + *DataType = SQL_C_LONG; + } break; + + case TSDB_DATA_TYPE_BIGINT: { + *DataType = SQL_BIGINT; + } break; + + case TSDB_DATA_TYPE_FLOAT: { + *DataType = SQL_C_FLOAT; + } break; + + case TSDB_DATA_TYPE_DOUBLE: { + *DataType = SQL_C_DOUBLE; + } break; + + case TSDB_DATA_TYPE_TIMESTAMP: { + *DataType = SQL_C_TIMESTAMP; + } break; + + case TSDB_DATA_TYPE_NCHAR: { + *DataType = SQL_C_CHAR; // unicode ? + } break; + + case TSDB_DATA_TYPE_BINARY: { + *DataType = SQL_C_BINARY; + } break; + + default: + SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "unknown TSDB_DATA_TYPE [%x]", field->type); + return SQL_ERROR; + break; + } + } + if (ColumnSize) { + *ColumnSize = field->bytes; + } + if (DecimalDigits) { + if (field->type == TSDB_DATA_TYPE_TIMESTAMP) { + *DecimalDigits = 3; + } else { + *DecimalDigits = 0; + } + } + if (Nullable) { + *Nullable = SQL_NULLABLE_UNKNOWN; + } + + return SQL_SUCCESS; +} + +SQLRETURN SQL_API SQLDescribeCol(SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, + SQLSMALLINT BufferLength, SQLSMALLINT *NameLength, + SQLSMALLINT *DataType, SQLULEN *ColumnSize, + SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) +{ + SQLRETURN r; + r = doSQLDescribeCol(StatementHandle, ColumnNumber, ColumnName, + BufferLength, NameLength, + DataType, ColumnSize, + DecimalDigits, Nullable); + return r; +} + static void init_routine(void) { @@ -1096,7 +1824,7 @@ static int do_field_display_size(TAOS_FIELD *field) { } break; case TSDB_DATA_TYPE_DOUBLE: { - return 12; + return 20; } break; case TSDB_DATA_TYPE_BINARY: @@ -1105,7 +1833,7 @@ static int do_field_display_size(TAOS_FIELD *field) { } break; case TSDB_DATA_TYPE_TIMESTAMP: - return 22; + return 26; break; case TSDB_DATA_TYPE_BOOL: @@ -1162,6 +1890,7 @@ static void do_convert(SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrL } if (n>0) *p = '\0'; ((char*)TargetValue)[BufferLength-1] = '\0'; + *StrLen_or_Ind = BufferLength - n; } break; case TSDB_DATA_TYPE_TIMESTAMP: @@ -1175,3 +1904,692 @@ static void do_convert(SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrL } } +// convertion from TSDB_DATA_TYPE_XXX to SQL_C_XXX +static SQLRETURN conv_tsdb_bool_to_c_bit(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + int8_t v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_tinyint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + int8_t v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_short(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + int16_t v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + int32_t v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + int64_t v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + float v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + double v = b; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + DASSERT(target->len>0); + *target->soi = 1; + if (target->ptr) { + target->ptr[0] = '0' + b; + if (target->len>1) { + target->ptr[1] = '\0'; + } + } + + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bool_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t b) +{ + DASSERT(target->len>0); + *target->soi = 1; + target->ptr[0] = '0' + b; + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_tinyint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + int8_t v = v1; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_short(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + int16_t v = v1; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + int32_t v = v1; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + int64_t v = v1; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + float v = v1; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + double v = v1; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v1_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%d", v1); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>=target->len ? target->len : n+1)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_TINYINT -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_v1_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int8_t v1) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%d", v1); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>target->len ? target->len : n)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_TINYINT -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_v2_to_c_short(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + int16_t v = v2; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v2_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + int32_t v = v2; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v2_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + int64_t v = v2; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v2_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + float v = v2; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v2_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + double v = v2; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v2_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%d", v2); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>=target->len ? target->len : n+1)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_SMALLINT -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_v2_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int16_t v2) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%d", v2); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>target->len ? target->len : n)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_SMALLINT -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + + +static SQLRETURN conv_tsdb_v4_to_c_long(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4) +{ + int32_t v = v4; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v4_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4) +{ + int64_t v = v4; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v4_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4) +{ + float v = v4; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v4_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4) +{ + double v = v4; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v4_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%d", v4); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>=target->len ? target->len : n+1)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_INTEGER -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_v4_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int32_t v4) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%d", v4); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>target->len ? target->len : n)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_INTEGER -> SQL_C_BINARY"); + return SQL_SUCCESS_WITH_INFO; +} + + +static SQLRETURN conv_tsdb_v8_to_c_sbigint(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8) +{ + int64_t v = v8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v8_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8) +{ + float v = v8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v8_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8) +{ + double v = v8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_v8_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%ld", v8); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>=target->len ? target->len : n+1)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_BIGINT -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_v8_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, int64_t v8) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%ld", v8); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>target->len ? target->len : n)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_BIGINT -> SQL_C_BINARY"); + return SQL_SUCCESS_WITH_INFO; +} + + +static SQLRETURN conv_tsdb_f4_to_c_float(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4) +{ + float v = f4; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_f4_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4) +{ + double v = f4; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_f4_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%g", f4); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>=target->len ? target->len : n+1)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_FLOAT -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_f4_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, float f4) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%g", f4); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>target->len ? target->len : n)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_FLOAT -> SQL_C_BINARY"); + return SQL_SUCCESS_WITH_INFO; +} + + +static SQLRETURN conv_tsdb_f8_to_c_double(sql_t *sql, c_target_t *target, TAOS_FIELD *field, double f8) +{ + double v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_f8_to_c_char(sql_t *sql, c_target_t *target, TAOS_FIELD *field, double f8) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%.6f", f8); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>=target->len ? target->len : n+1)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_DOUBLE -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_f8_to_c_binary(sql_t *sql, c_target_t *target, TAOS_FIELD *field, double f8) +{ + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%g", f8); + DASSERT(nsoi = n; + if (target->ptr) strncpy(target->ptr, buf, (n>target->len ? target->len : n)); + if (n<=target->len) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_DOUBLE -> SQL_C_BINARY"); + return SQL_SUCCESS_WITH_INFO; +} + + +static SQLRETURN conv_tsdb_ts_to_c_v8(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts) +{ + struct tm tm = {0}; + tm.tm_sec = ts->second; + tm.tm_min = ts->minute; + tm.tm_hour = ts->hour; + tm.tm_mday = ts->day; + tm.tm_mon = ts->month - 1; + tm.tm_year = ts->year - 1900; + time_t t = mktime(&tm); + DASSERT(sizeof(t) == sizeof(int64_t)); + int64_t v = (int64_t)t; + v *= 1000; + v += ts->fraction % 1000; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_ts_to_c_str(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts) +{ + struct tm tm = {0}; + tm.tm_sec = ts->second; + tm.tm_min = ts->minute; + tm.tm_hour = ts->hour; + tm.tm_mday = ts->day; + tm.tm_mon = ts->month - 1; + tm.tm_year = ts->year - 1900; + + char buf[64]; + int n = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); + DASSERT(n < sizeof(buf)); + + *target->soi = n; + + if (target->ptr) { + snprintf(target->ptr, target->len, "%s.%03d", buf, ts->fraction); + } + + if (n <= target->len) { + return SQL_SUCCESS; + } + + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_TIMESTAMP -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_ts_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts) +{ + struct tm tm = {0}; + tm.tm_sec = ts->second; + tm.tm_min = ts->minute; + tm.tm_hour = ts->hour; + tm.tm_mday = ts->day; + tm.tm_mon = ts->month - 1; + tm.tm_year = ts->year - 1900; + + char buf[64]; + int n = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); + DASSERT(n < sizeof(buf)); + + *target->soi = n; + + if (target->ptr) memcpy(target->ptr, buf, (n>target->len ? target->len : n)); + + if (n <= target->len) { + return SQL_SUCCESS; + } + + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_TIMESTAMP -> SQL_C_BINARY"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_ts_to_c_ts(sql_t *sql, c_target_t *target, TAOS_FIELD *field, TIMESTAMP_STRUCT *ts) +{ + if (target->ptr) memcpy(target->ptr, ts, sizeof(*ts)); + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_bin_to_c_str(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const unsigned char *bin) +{ + size_t n = field->bytes; + *target->soi = n; + if (target->ptr) memcpy(target->ptr, bin, (n>target->len ? target->len : n)); + if (n <= target->len) return SQL_SUCCESS; + + SET_ERROR(sql, "01004", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_BINARY -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_bin_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const unsigned char *bin) +{ + size_t n = field->bytes; + *target->soi = n; + if (target->ptr) memcpy(target->ptr, bin, (n>target->len ? target->len : n)); + if (n <= target->len) return SQL_SUCCESS; + + SET_ERROR(sql, "01004", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_BINARY -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_bit(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + int8_t v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 1; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; + } + + char buf[64]; + snprintf(buf, sizeof(buf), "%d", v); + + if (strcmp(buf, str)==0) { + if (v==0 || v==1) return SQL_SUCCESS; + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; + } + + if (f8>0 || f8<2) { + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; + } + + if (f8<0 || f8>2) { + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; + } + + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_BIT"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_v1(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + int8_t v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 1; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_TINYINT"); + return SQL_SUCCESS_WITH_INFO; + } + + char buf[64]; + snprintf(buf, sizeof(buf), "%d", v); + + if (strcmp(buf, str)==0) return SQL_SUCCESS; + + if (f8>INT8_MAX || f8 SQL_C_TINYINT"); + return SQL_SUCCESS_WITH_INFO; + } + + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_TINYINT"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_v2(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + int16_t v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 2; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_SHORT"); + return SQL_SUCCESS_WITH_INFO; + } + + char buf[64]; + snprintf(buf, sizeof(buf), "%d", v); + + if (strcmp(buf, str)==0) return SQL_SUCCESS; + + if (f8>INT16_MAX || f8 SQL_C_SHORT"); + return SQL_SUCCESS_WITH_INFO; + } + + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_SHORT"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_v4(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + int32_t v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 4; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_LONG"); + return SQL_SUCCESS_WITH_INFO; + } + + char buf[64]; + snprintf(buf, sizeof(buf), "%d", v); + + if (strcmp(buf, str)==0) return SQL_SUCCESS; + + if (f8>INT32_MAX || f8 SQL_C_LONG"); + return SQL_SUCCESS_WITH_INFO; + } + + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_LONG"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_v8(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + int64_t v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 8; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_SBIGINT"); + return SQL_SUCCESS_WITH_INFO; + } + + char buf[64]; + snprintf(buf, sizeof(buf), "%ld", v); + + if (strcmp(buf, str)==0) return SQL_SUCCESS; + + if (f8>INT64_MAX || f8 SQL_C_SBIGINT"); + return SQL_SUCCESS_WITH_INFO; + } + + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_SBIGINT"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_f4(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + float v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 4; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_FLOAT"); + return SQL_SUCCESS_WITH_INFO; + } + + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_str_to_c_f8(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + int bytes = 0; + double f8 = 0; + int n = sscanf(str, "%lf%n", &f8, &bytes); + + float v = f8; + if (target->ptr) memcpy(target->ptr, &v, sizeof(v)); + + *target->soi = 8; + + if (n!=1 || bytes!=strlen(str)) { + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_UNDEF, "TSDB_DATA_TYPE_NCHAR -> SQL_C_DOUBLE"); + return SQL_SUCCESS_WITH_INFO; + } + + return SQL_SUCCESS; +} + +static SQLRETURN conv_tsdb_str_to_c_str(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + size_t n = strlen(str); + *target->soi = n; + if (target->ptr) strncpy(target->ptr, str, (n < target->len ? n+1 : target->len)); + + if (n < target->len) return SQL_SUCCESS; + + SET_ERROR(sql, "01004", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_CHAR"); + return SQL_SUCCESS_WITH_INFO; +} + +static SQLRETURN conv_tsdb_str_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIELD *field, const char *str) +{ + size_t n = strlen(str); + *target->soi = n; + if (target->ptr) memcpy(target->ptr, str, (n < target->len ? n : target->len)); + + if (n <= target->len) return SQL_SUCCESS; + + SET_ERROR(sql, "01004", TSDB_CODE_ODBC_CONV_TRUNC, "TSDB_DATA_TYPE_NCHAR -> SQL_C_BINARY"); + return SQL_SUCCESS_WITH_INFO; +} + diff --git a/src/connector/odbc/tests/main.c b/src/connector/odbc/tests/main.c index aa4ce7a05a..1d403002a8 100644 --- a/src/connector/odbc/tests/main.c +++ b/src/connector/odbc/tests/main.c @@ -118,8 +118,7 @@ static int do_insert(SQLHSTMT stmt, data_t data) { if (r) break; fprintf(stderr, "bind 8 [%s]\n", statement); - SQLLEN l8 = SQL_NULL_DATA; - r = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, ignored, ignored, &data.f8, ignored, &l8); + r = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, ignored, ignored, &data.f8, ignored, NULL); CHK_RESULT(r, SQL_HANDLE_STMT, stmt); if (r) break; @@ -196,6 +195,7 @@ int main(int argc, char *argv[]) { memset(data.blob, 0, sizeof(data.blob)); snprintf(data.bin, sizeof(data.bin), "hello"); snprintf(data.blob, sizeof(data.blob), "world"); + snprintf(data.blob, sizeof(data.blob), "wo人rld"); SQLHSTMT stmt = {0}; r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt); if (r!=SQL_SUCCESS) break; diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index b5d22ea80c..17aa1fbfd5 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -28,7 +28,7 @@ extern "C" { #else #define TAOS_DEFINE_ERROR(name, mod, code, msg) static const int32_t name = (0x80000000 | ((mod)<<16) | (code)); #endif - + #define TAOS_SYSTEM_ERROR(code) (0x80ff0000 | (code)) #define TAOS_SUCCEEDED(err) ((err) >= 0) #define TAOS_FAILED(err) ((err) < 0) @@ -37,7 +37,7 @@ const char* tstrerror(int32_t err); int32_t* taosGetErrno(); #define terrno (*taosGetErrno()) - + #define TSDB_CODE_SUCCESS 0 #ifdef TAOS_ERROR_C @@ -180,7 +180,7 @@ TAOS_DEFINE_ERROR(TSDB_CODE_DND_OUT_OF_MEMORY, 0, 0x0401, "Dnode out TAOS_DEFINE_ERROR(TSDB_CODE_DND_NO_WRITE_ACCESS, 0, 0x0402, "No permission for disk files in dnode") TAOS_DEFINE_ERROR(TSDB_CODE_DND_INVALID_MSG_LEN, 0, 0x0403, "Invalid message length") -// vnode +// vnode TAOS_DEFINE_ERROR(TSDB_CODE_VND_ACTION_IN_PROGRESS, 0, 0x0500, "Action in progress") TAOS_DEFINE_ERROR(TSDB_CODE_VND_MSG_NOT_PROCESSED, 0, 0x0501, "Message not processed") TAOS_DEFINE_ERROR(TSDB_CODE_VND_ACTION_NEED_REPROCESSED, 0, 0x0502, "Action need to be reprocessed") @@ -350,6 +350,12 @@ TAOS_DEFINE_ERROR(TSDB_CODE_HTTP_OP_TAG_VALUE_TOO_LONG, 0, 0x11A4, "tag value TAOS_DEFINE_ERROR(TSDB_CODE_HTTP_OP_VALUE_NULL, 0, 0x11A5, "value not find") TAOS_DEFINE_ERROR(TSDB_CODE_HTTP_OP_VALUE_TYPE, 0, 0x11A6, "value type should be boolean, number or string") + +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OOM, 0, 0x2101, "out of memory") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_UNDEF, 0, 0x2102, "convertion undefined") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_TRUNC, 0, 0x2103, "convertion truncated") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_NOT_SUPPORT, 0, 0x2104, "convertion not supported") + #ifdef TAOS_ERROR_C }; #endif