diff --git a/src/connector/odbc/src/todbc.c b/src/connector/odbc/src/todbc.c index 953999c434..594d53d132 100644 --- a/src/connector/odbc/src/todbc.c +++ b/src/connector/odbc/src/todbc.c @@ -22,6 +22,7 @@ #include "os.h" #include "taoserror.h" #include "todbc_util.h" +#include "todbc_conv.h" #include #include @@ -143,17 +144,36 @@ do { \ D("%s: elapsed: [%.6f]s", #statement, delta); \ } while (0) - -#define CHK_CONV(statement) \ -do { \ - const char *sqlstate = statement; \ - if (sqlstate) { \ - SET_ERROR(sql, sqlstate, TSDB_CODE_ODBC_OUT_OF_RANGE, \ - "no convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d]", \ - sql_c_type(valueType), valueType, valueType, \ - taos_data_type(type), type, type, idx+1); \ - return SQL_ERROR; \ - } \ +#define CHK_CONV(statement) \ +do { \ + TSDB_CONV_CODE code = (statement); \ + switch (code) { \ + case TSDB_CONV_OK: return SQL_SUCCESS; \ + case TSDB_CONV_OOM: { \ + SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, ""); \ + return SQL_ERROR; \ + } break; \ + case TSDB_CONV_OOR: { \ + SET_ERROR(sql, "22003", TSDB_CODE_ODBC_CONV_OOR, ""); \ + return SQL_ERROR; \ + } break; \ + case TSDB_CONV_CHAR_NOT_NUM: { \ + SET_ERROR(sql, "22018", TSDB_CODE_ODBC_CONV_CHAR_NOT_NUM, ""); \ + return SQL_ERROR; \ + } break; \ + case TSDB_CONV_TRUNC_FRACTION: { \ + SET_ERROR(sql, "01S07", TSDB_CODE_ODBC_CONV_TRUNC_FRAC, ""); \ + return SQL_ERROR; \ + } break; \ + case TSDB_CONV_TRUNC: { \ + SET_ERROR(sql, "22001", TSDB_CODE_ODBC_CONV_TRUNC, ""); \ + return SQL_ERROR; \ + } break; \ + default: { \ + DASSERTX(0, "internal logic error"); \ + return SQL_ERROR; /* never reached here */ \ + } break; \ + } \ } while (0) typedef struct env_s env_t; @@ -229,39 +249,6 @@ struct c_target_s { static pthread_once_t init_once = PTHREAD_ONCE_INIT; static void init_routine(void); -// conversions - -const char* tsdb_int64_to_bit(int64_t src, int8_t *dst); -const char* tsdb_int64_to_tinyint(int64_t src, int8_t *dst); -const char* tsdb_int64_to_smallint(int64_t src, int16_t *dst); -const char* tsdb_int64_to_int(int64_t src, int32_t *dst); -const char* tsdb_int64_to_bigint(int64_t src, int64_t *dst); -const char* tsdb_int64_to_ts(int64_t src, int64_t *dst); -const char* tsdb_int64_to_float(int64_t src, float *dst); -const char* tsdb_int64_to_double(int64_t src, double *dst); -const char* tsdb_int64_to_char(int64_t src, char *dst, size_t dlen); - -const char* tsdb_double_to_bit(double src, int precision, int8_t *dst); -const char* tsdb_double_to_tinyint(double src, int precision, int8_t *dst); -const char* tsdb_double_to_smallint(double src, int precision, int16_t *dst); -const char* tsdb_double_to_int(double src, int precision, int32_t *dst); -const char* tsdb_double_to_bigint(double src, int precision, int64_t *dst); -const char* tsdb_double_to_ts(double src, int precision, int64_t *dst); -const char* tsdb_double_to_float(double src, int precision, float *dst); -const char* tsdb_double_to_double(double src, int precision, double *dst); -const char* tsdb_double_to_char(double src, int precision, char *dst, size_t dlen); - -const char* tsdb_chars_to_bit(const char *src, int8_t *dst); -const char* tsdb_chars_to_tinyint(const char *src, int8_t *dst); -const char* tsdb_chars_to_smallint(const char *src, int16_t *dst); -const char* tsdb_chars_to_int(const char *src, int32_t *dst); -const char* tsdb_chars_to_bigint(const char *src, int64_t *dst); -const char* tsdb_chars_to_ts(const char *src, int64_t *dst); -const char* tsdb_chars_to_float(const char *src, float *dst); -const char* tsdb_chars_to_double(const char *src, double *dst); -const char* tsdb_chars_to_char(const char *src, char *dst, size_t dlen); - - static int do_field_display_size(TAOS_FIELD *field); static SQLRETURN doSQLAllocEnv(SQLHENV *EnvironmentHandle) @@ -1280,25 +1267,35 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.b; bind->length = &bind->buffer_length; switch (valueType) { - case SQL_C_LONG: { - CHK_CONV(tsdb_int64_to_bit(*(int32_t*)paramValue, &bind->u.b)); - } break; case SQL_C_BIT: { - CHK_CONV(tsdb_int64_to_bit(*(int8_t*)paramValue, &bind->u.b)); + CHK_CONV(tsdb_int64_to_bit(1, *(int8_t*)paramValue, &bind->u.b)); + } break; + case SQL_C_TINYINT: + case SQL_C_STINYINT: { + CHK_CONV(tsdb_int64_to_bit(1, *(int8_t*)paramValue, &bind->u.b)); } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: case SQL_C_SHORT: - case SQL_C_SSHORT: + case SQL_C_SSHORT: { + CHK_CONV(tsdb_int64_to_bit(1, *(int16_t*)paramValue, &bind->u.b)); + } break; + case SQL_C_LONG: + case SQL_C_SLONG: { + CHK_CONV(tsdb_int64_to_bit(1, *(int32_t*)paramValue, &bind->u.b)); + } break; + case SQL_C_SBIGINT: { + CHK_CONV(tsdb_int64_to_bit(1, *(int64_t*)paramValue, &bind->u.b)); + } break; + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_bit(1, (const char *)paramValue, &bind->u.b)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_bit(1, (const unsigned char*)paramValue, *soi, &bind->u.b)); + } break; case SQL_C_USHORT: - case SQL_C_SLONG: case SQL_C_ULONG: case SQL_C_FLOAT: case SQL_C_DOUBLE: - case SQL_C_TINYINT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: - case SQL_C_SBIGINT: case SQL_C_UBIGINT: case SQL_C_BINARY: case SQL_C_DATE: @@ -1324,28 +1321,34 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.v1; bind->length = &bind->buffer_length; switch (valueType) { + case SQL_C_BIT: { + CHK_CONV(tsdb_int64_to_tinyint(1, *(int8_t*)paramValue, &bind->u.v1)); + } break; + case SQL_C_STINYINT: case SQL_C_TINYINT: { - CHK_CONV(tsdb_int64_to_tinyint(*(int8_t*)paramValue, &bind->u.v1)); + CHK_CONV(tsdb_int64_to_tinyint(1, *(int8_t*)paramValue, &bind->u.v1)); } break; + case SQL_C_SSHORT: case SQL_C_SHORT: { - CHK_CONV(tsdb_int64_to_tinyint(*(int16_t*)paramValue, &bind->u.v1)); + CHK_CONV(tsdb_int64_to_tinyint(1, *(int16_t*)paramValue, &bind->u.v1)); } break; + case SQL_C_SLONG: case SQL_C_LONG: { - CHK_CONV(tsdb_int64_to_tinyint(*(int32_t*)paramValue, &bind->u.v1)); + CHK_CONV(tsdb_int64_to_tinyint(1, *(int32_t*)paramValue, &bind->u.v1)); } break; case SQL_C_SBIGINT: { - CHK_CONV(tsdb_int64_to_tinyint(*(int64_t*)paramValue, &bind->u.v1)); + CHK_CONV(tsdb_int64_to_tinyint(1, *(int64_t*)paramValue, &bind->u.v1)); + } break; + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_tinyint(1, (const char*)paramValue, &bind->u.v1)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_tinyint(1, (const unsigned char*)paramValue, *soi, &bind->u.v1)); } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: - case SQL_C_SSHORT: case SQL_C_USHORT: - case SQL_C_SLONG: case SQL_C_ULONG: case SQL_C_FLOAT: case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: case SQL_C_UBIGINT: case SQL_C_BINARY: @@ -1372,25 +1375,35 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.v2; bind->length = &bind->buffer_length; switch (valueType) { - case SQL_C_LONG: { - CHK_CONV(tsdb_int64_to_smallint(*(int32_t*)paramValue, &bind->u.v2)); + case SQL_C_BIT: { + CHK_CONV(tsdb_int64_to_smallint(1, *(int8_t*)paramValue, &bind->u.v2)); } break; - case SQL_C_SHORT: { - CHK_CONV(tsdb_int64_to_smallint(*(int16_t*)paramValue, &bind->u.v2)); + case SQL_C_STINYINT: + case SQL_C_TINYINT: { + CHK_CONV(tsdb_int64_to_smallint(1, *(int8_t*)paramValue, &bind->u.v2)); } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: case SQL_C_SSHORT: - case SQL_C_USHORT: + case SQL_C_SHORT: { + CHK_CONV(tsdb_int64_to_smallint(1, *(int16_t*)paramValue, &bind->u.v2)); + } break; case SQL_C_SLONG: + case SQL_C_LONG: { + CHK_CONV(tsdb_int64_to_smallint(1, *(int32_t*)paramValue, &bind->u.v2)); + } break; + case SQL_C_SBIGINT: { + CHK_CONV(tsdb_int64_to_smallint(1, *(int64_t*)paramValue, &bind->u.v2)); + } break; + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_smallint(1, (const char*)paramValue, &bind->u.v2)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_smallint(1, (const unsigned char*)paramValue, *soi, &bind->u.v2)); + } break; + case SQL_C_USHORT: case SQL_C_ULONG: case SQL_C_FLOAT: case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: - case SQL_C_SBIGINT: case SQL_C_UBIGINT: case SQL_C_BINARY: case SQL_C_DATE: @@ -1416,23 +1429,35 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.v4; bind->length = &bind->buffer_length; switch (valueType) { - case SQL_C_LONG: { - CHK_CONV(tsdb_int64_to_int(*(int32_t*)paramValue, &bind->u.v4)); + case SQL_C_BIT: { + CHK_CONV(tsdb_int64_to_int(1, *(int8_t*)paramValue, &bind->u.v4)); + } break; + case SQL_C_STINYINT: + case SQL_C_TINYINT: { + CHK_CONV(tsdb_int64_to_int(1, *(int8_t*)paramValue, &bind->u.v4)); } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: - case SQL_C_SHORT: case SQL_C_SSHORT: - case SQL_C_USHORT: + case SQL_C_SHORT: { + CHK_CONV(tsdb_int64_to_int(1, *(int16_t*)paramValue, &bind->u.v4)); + } break; case SQL_C_SLONG: + case SQL_C_LONG: { + CHK_CONV(tsdb_int64_to_int(1, *(int32_t*)paramValue, &bind->u.v4)); + } break; + case SQL_C_SBIGINT: { + CHK_CONV(tsdb_int64_to_int(1, *(int64_t*)paramValue, &bind->u.v4)); + } break; + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_int(1, (const char*)paramValue, &bind->u.v4)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_int(1, (const unsigned char*)paramValue, *soi, &bind->u.v4)); + } break; + case SQL_C_USHORT: case SQL_C_ULONG: case SQL_C_FLOAT: case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: - case SQL_C_SBIGINT: case SQL_C_UBIGINT: case SQL_C_BINARY: case SQL_C_DATE: @@ -1458,24 +1483,34 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.v8; bind->length = &bind->buffer_length; switch (valueType) { - case SQL_C_SBIGINT: { - bind->u.v8 = *(int64_t*)paramValue; + case SQL_C_BIT: { + CHK_CONV(tsdb_int64_to_bigint(1, *(int8_t*)paramValue, &bind->u.v8)); } break; - case SQL_C_LONG: { - bind->u.v8 = *(int32_t*)paramValue; + case SQL_C_STINYINT: + case SQL_C_TINYINT: { + CHK_CONV(tsdb_int64_to_bigint(1, *(int8_t*)paramValue, &bind->u.v8)); } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: - case SQL_C_SHORT: case SQL_C_SSHORT: - case SQL_C_USHORT: + case SQL_C_SHORT: { + CHK_CONV(tsdb_int64_to_bigint(1, *(int16_t*)paramValue, &bind->u.v8)); + } break; case SQL_C_SLONG: + case SQL_C_LONG: { + CHK_CONV(tsdb_int64_to_bigint(1, *(int32_t*)paramValue, &bind->u.v8)); + } break; + case SQL_C_SBIGINT: { + CHK_CONV(tsdb_int64_to_bigint(1, *(int64_t*)paramValue, &bind->u.v8)); + } break; + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_bigint(1, (const char*)paramValue, &bind->u.v8)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_bigint(1, (const unsigned char*)paramValue, *soi, &bind->u.v8)); + } break; + case SQL_C_USHORT: case SQL_C_ULONG: case SQL_C_FLOAT: case SQL_C_DOUBLE: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: case SQL_C_UBIGINT: case SQL_C_BINARY: @@ -1502,26 +1537,38 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.f4; bind->length = &bind->buffer_length; switch (valueType) { - case SQL_C_DOUBLE: { - bind->u.f4 = *(double*)paramValue; + case SQL_C_BIT: { + CHK_CONV(tsdb_int64_to_float(1, *(int8_t*)paramValue, &bind->u.f4)); + } break; + case SQL_C_STINYINT: + case SQL_C_TINYINT: { + CHK_CONV(tsdb_int64_to_float(1, *(int8_t*)paramValue, &bind->u.f4)); + } break; + case SQL_C_SSHORT: + case SQL_C_SHORT: { + CHK_CONV(tsdb_int64_to_float(1, *(int16_t*)paramValue, &bind->u.f4)); + } break; + case SQL_C_SLONG: + case SQL_C_LONG: { + CHK_CONV(tsdb_int64_to_float(1, *(int32_t*)paramValue, &bind->u.f4)); + } break; + case SQL_C_SBIGINT: { + CHK_CONV(tsdb_int64_to_float(1, *(int64_t*)paramValue, &bind->u.f4)); } break; case SQL_C_FLOAT: { bind->u.f4 = *(float*)paramValue; } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: - case SQL_C_SHORT: - case SQL_C_SSHORT: + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_float(1, (const char*)paramValue, &bind->u.f4)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_float(1, (const unsigned char*)paramValue, *soi, &bind->u.f4)); + } break; case SQL_C_USHORT: - case SQL_C_LONG: - case SQL_C_SLONG: case SQL_C_ULONG: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: - case SQL_C_SBIGINT: case SQL_C_UBIGINT: + case SQL_C_DOUBLE: case SQL_C_BINARY: case SQL_C_DATE: case SQL_C_TIME: @@ -1546,23 +1593,39 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin bind->buffer = &bind->u.f8; bind->length = &bind->buffer_length; switch (valueType) { + case SQL_C_BIT: { + CHK_CONV(tsdb_int64_to_double(1, *(int8_t*)paramValue, &bind->u.f8)); + } break; + case SQL_C_STINYINT: + case SQL_C_TINYINT: { + CHK_CONV(tsdb_int64_to_double(1, *(int8_t*)paramValue, &bind->u.f8)); + } break; + case SQL_C_SSHORT: + case SQL_C_SHORT: { + CHK_CONV(tsdb_int64_to_double(1, *(int16_t*)paramValue, &bind->u.f8)); + } break; + case SQL_C_SLONG: + case SQL_C_LONG: { + CHK_CONV(tsdb_int64_to_double(1, *(int32_t*)paramValue, &bind->u.f8)); + } break; + case SQL_C_SBIGINT: { + CHK_CONV(tsdb_int64_to_double(1, *(int64_t*)paramValue, &bind->u.f8)); + } break; + case SQL_C_FLOAT: { + bind->u.f8 = *(float*)paramValue; + } break; case SQL_C_DOUBLE: { bind->u.f8 = *(double*)paramValue; } break; - case SQL_C_CHAR: - case SQL_C_WCHAR: - case SQL_C_SHORT: - case SQL_C_SSHORT: + case SQL_C_CHAR: { + CHK_CONV(tsdb_chars_to_double(1, (const char*)paramValue, &bind->u.f8)); + } break; + case SQL_C_WCHAR: { + CHK_CONV(tsdb_wchars_to_double(1, (const unsigned char*)paramValue, *soi, &bind->u.f8)); + } break; case SQL_C_USHORT: - case SQL_C_LONG: - case SQL_C_SLONG: case SQL_C_ULONG: - case SQL_C_FLOAT: - case SQL_C_BIT: - case SQL_C_TINYINT: - case SQL_C_STINYINT: case SQL_C_UTINYINT: - case SQL_C_SBIGINT: case SQL_C_UBIGINT: case SQL_C_BINARY: case SQL_C_DATE: @@ -1614,12 +1677,12 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin case SQL_C_ULONG: case SQL_C_FLOAT: case SQL_C_DOUBLE: - case SQL_C_BIT: case SQL_C_TINYINT: case SQL_C_STINYINT: case SQL_C_UTINYINT: case SQL_C_SBIGINT: case SQL_C_UBIGINT: + case SQL_C_BIT: case SQL_C_DATE: case SQL_C_TIME: case SQL_C_TIMESTAMP: @@ -3117,364 +3180,3 @@ static SQLRETURN conv_tsdb_str_to_c_bin(sql_t *sql, c_target_t *target, TAOS_FIE -const char* tsdb_int64_to_bit(int64_t src, int8_t *dst) -{ - *dst = src; - if (src==0 || src==1) return NULL; - return "22003"; -} - -const char* tsdb_int64_to_tinyint(int64_t src, int8_t *dst) -{ - *dst = src; - if (src>=SCHAR_MIN && src<=SCHAR_MAX) return NULL; - return "22003"; -} - -const char* tsdb_int64_to_smallint(int64_t src, int16_t *dst) -{ - *dst = src; - if (src>=SHRT_MIN && src<=SHRT_MAX) return NULL; - return "22003"; -} - -const char* tsdb_int64_to_int(int64_t src, int32_t *dst) -{ - *dst = src; - if (src>=LONG_MIN && src<=LONG_MAX) return NULL; - return "22003"; -} - -const char* tsdb_int64_to_bigint(int64_t src, int64_t *dst) -{ - *dst = src; - return NULL; -} - -const char* tsdb_int64_to_ts(int64_t src, int64_t *dst) -{ - *dst = src; - - char buf[4096]; - int n = snprintf(buf, sizeof(buf), "%" PRId64 "", src); - DASSERT(n>=0); - DASSERT(n=2) return "22003"; - - char buf[4096]; - int n = snprintf(buf, sizeof(buf), "%.*g", precision, src); - DASSERT(n>=0); - DASSERT(nSCHAR_MAX) return "22003"; - - char buf[4096]; - int n = snprintf(buf, sizeof(buf), "%.*g", precision, src); - DASSERT(n>=0); - DASSERT(nSHRT_MAX) return "22003"; - - char buf[4096]; - int n = snprintf(buf, sizeof(buf), "%.*g", precision, src); - DASSERT(n>=0); - DASSERT(nLONG_MAX) return "22003"; - - char buf[4096]; - int n = snprintf(buf, sizeof(buf), "%.*g", precision, src); - DASSERT(n>=0); - DASSERT(nLLONG_MAX) return "22003"; - - char buf[4096]; - int n = snprintf(buf, sizeof(buf), "%.*g", precision, src); - DASSERT(n>=0); - DASSERT(n=0); - DASSERT(n=0); - DASSERT(n2>=0); - DASSERT(n1=0); - if (n>=dlen) return "22001"; - - return NULL; -} - -const char* tsdb_chars_to_bit(const char *src, int8_t *dst) -{ - int bytes = 0; - int64_t v = 0; - int n = sscanf(src, "%" PRId64 "%n", &v, &bytes); - if (n!=1) return "22018"; - - if (bytes!=strlen(src)) { - if (src[bytes-1]=='.') { - if (v==0 || v==1) return "22001"; - - return "22003"; - } - return "22018"; - } - - if (v==0 || v==1) return NULL; - - return "22003"; -} - -const char* tsdb_chars_to_tinyint(const char *src, int8_t *dst) -{ - int bytes = 0; - int64_t v = 0; - int n = sscanf(src, "%" PRId64 "%n", &v, &bytes); - if (n!=1) return "22018"; - - - if (bytes!=strlen(src)) { - if (src[bytes-1]=='.') { - if (vSCHAR_MAX) return "22001"; - - return "22003"; - } - return "22018"; - } - - if (vSCHAR_MAX) return "22001"; - - return NULL; -} - -const char* tsdb_chars_to_smallint(const char *src, int16_t *dst) -{ - int bytes = 0; - int64_t v = 0; - int n = sscanf(src, "%" PRId64 "%n", &v, &bytes); - if (n!=1) return "22018"; - - - if (bytes!=strlen(src)) { - if (src[bytes-1]=='.') { - if (vSHRT_MAX) return "22001"; - - return "22003"; - } - return "22018"; - } - - if (vSHRT_MAX) return "22001"; - - return NULL; -} - -const char* tsdb_chars_to_int(const char *src, int32_t *dst) -{ - int bytes = 0; - int64_t v = 0; - int n = sscanf(src, "%" PRId64 "%n", &v, &bytes); - if (n!=1) return "22018"; - - - if (bytes!=strlen(src)) { - if (src[bytes-1]=='.') { - if (vLONG_MAX) return "22001"; - - return "22003"; - } - return "22018"; - } - - if (vLONG_MAX) return "22001"; - - return NULL; -} - -const char* tsdb_chars_to_bigint(const char *src, int64_t *dst) -{ - int bytes = 0; - int64_t v = 0; - int n = sscanf(src, "%" PRId64 "%n", &v, &bytes); - if (n!=1) return "22018"; - - - if (bytes!=strlen(src)) { - if (src[bytes-1]=='.') { - if (vLLONG_MAX) return "22001"; - - return "22003"; - } - return "22018"; - } - - if (vLLONG_MAX) return "22001"; - - return NULL; -} - -const char* tsdb_chars_to_ts(const char *src, int64_t *dst) -{ - int bytes = 0; - int64_t v = 0; - int n = sscanf(src, "%" PRId64 "%n", &v, &bytes); - if (n!=1) return "22018"; - - - if (bytes!=strlen(src)) { - if (src[bytes-1]=='.') { - if (vLLONG_MAX) return "22001"; - - return "22003"; - } - return "22018"; - } - - if (vLLONG_MAX) return "22001"; - - return NULL; -} - -const char* tsdb_chars_to_float(const char *src, float *dst) -{ - int bytes = 0; - int n = sscanf(src, "%f%n", dst, &bytes); - if (n!=1) return "22018"; - - if (bytes!=strlen(src)) return "22018"; - - return NULL; -} - -const char* tsdb_chars_to_double(const char *src, double *dst) -{ - int bytes = 0; - int n = sscanf(src, "%lf%n", dst, &bytes); - if (n!=1) return "22018"; - - if (bytes!=strlen(src)) return "22018"; - - return NULL; -} - -const char* tsdb_chars_to_char(const char *src, char *dst, size_t dlen) -{ - int n = snprintf(dst, dlen, "%s", src); - if (n>=dlen) return "22001"; - - return NULL; -} - diff --git a/src/connector/odbc/src/todbc_conv.c b/src/connector/odbc/src/todbc_conv.c new file mode 100644 index 0000000000..ccfead3eb3 --- /dev/null +++ b/src/connector/odbc/src/todbc_conv.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "todbc_conv.h" + +#include "todbc_util.h" + +#include +#include +#include +#include + + +// src: int +TSDB_CONV_CODE tsdb_int64_to_bit(int todb, int64_t src, int8_t *dst) { + *dst = (int8_t)src; + if (src==0 || src==1) return TSDB_CONV_OK; + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_tinyint(int todb, int64_t src, int8_t *dst) { + *dst = (int8_t)src; + if (src == *dst) return TSDB_CONV_OK; + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_smallint(int todb, int64_t src, int16_t *dst) { + *dst = (int16_t)src; + if (src == *dst) return TSDB_CONV_OK; + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_int(int todb, int64_t src, int32_t *dst) { + *dst = (int32_t)src; + if (src == *dst) return TSDB_CONV_OK; + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_bigint(int todb, int64_t src, int64_t *dst) { + *dst = src; + return TSDB_CONV_OK; +} + +TSDB_CONV_CODE tsdb_int64_to_ts(int todb, int64_t src, int64_t *dst) { + *dst = src; + + time_t t = (time_t)(src / 1000); + struct tm tm = {0}; + if (localtime_r(&t, &tm)) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_float(int todb, int64_t src, float *dst) { + *dst = (float)src; + + int64_t v = (int64_t)*dst; + if (v==src) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_double(int todb, int64_t src, double *dst) { + *dst = (double)src; + + int64_t v = (int64_t)*dst; + if (v==src) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_int64_to_char(int todb, int64_t src, char *dst, size_t dlen) { + int n = snprintf(dst, dlen, "%" PRId64 "", src); + + if (n=2) return TSDB_CONV_OOR; + if (src == *dst) return TSDB_CONV_OK; + + int64_t v = (int64_t)src; + if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; + + return TSDB_CONV_TRUNC; +} + +TSDB_CONV_CODE tsdb_double_to_tinyint(int todb, double src, int8_t *dst) { + *dst = (int8_t)src; + + if (srcSCHAR_MAX) return TSDB_CONV_OOR; + if (src == *dst) return TSDB_CONV_OK; + + int64_t v = (int64_t)src; + if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; + + return TSDB_CONV_TRUNC; +} + +TSDB_CONV_CODE tsdb_double_to_smallint(int todb, double src, int16_t *dst) { + *dst = (int16_t)src; + + if (srcSHRT_MAX) return TSDB_CONV_OOR; + if (src == *dst) return TSDB_CONV_OK; + + int64_t v = (int64_t)src; + if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; + + return TSDB_CONV_TRUNC; +} + +TSDB_CONV_CODE tsdb_double_to_int(int todb, double src, int32_t *dst) { + *dst = (int32_t)src; + + if (srcLONG_MAX) return TSDB_CONV_OOR; + if (src == *dst) return TSDB_CONV_OK; + + int64_t v = (int64_t)src; + if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; + + return TSDB_CONV_TRUNC; +} + +TSDB_CONV_CODE tsdb_double_to_bigint(int todb, double src, int64_t *dst) { + *dst = (int64_t)src; + + if (srcLLONG_MAX) return TSDB_CONV_OOR; + if (src == *dst) return TSDB_CONV_OK; + + int64_t v = (int64_t)src; + if (v == *dst) return TSDB_CONV_TRUNC_FRACTION; + + return TSDB_CONV_TRUNC; +} + +TSDB_CONV_CODE tsdb_double_to_ts(int todb, double src, int64_t *dst) { + TSDB_CONV_CODE code = tsdb_double_to_bigint(todb, src, dst); + + if (code==TSDB_CONV_OK || code==TSDB_CONV_TRUNC_FRACTION) { + int64_t v = (int64_t)src; + time_t t = (time_t)(v / 1000); + struct tm tm = {0}; + if (localtime_r(&t, &tm)) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; + } + + return code; +} + +// src: chars +TSDB_CONV_CODE tsdb_chars_to_bit(int todb, const char *src, int8_t *dst) { + if (strcmp(src, "0")==0) { + *dst = 0; + return TSDB_CONV_OK; + } + + if (strcmp(src, "1")==0) { + *dst = 1; + return TSDB_CONV_OK; + } + + double v; + int bytes; + int n = sscanf(src, "%lg%n", &v, &bytes); + + if (n!=1) return TSDB_CONV_CHAR_NOT_NUM; + if (bytes!=strlen(src)) return TSDB_CONV_CHAR_NOT_NUM; + + if (v<0 || v>=2) return TSDB_CONV_OOR; + + return TSDB_CONV_TRUNC_FRACTION; +} + +TSDB_CONV_CODE tsdb_chars_to_tinyint(int todb, const char *src, int8_t *dst) { + int64_t v; + TSDB_CONV_CODE code = tsdb_chars_to_bigint(todb, src, &v); + if (code!=TSDB_CONV_OK) return code; + + *dst = (int8_t)v; + + if (v==*dst) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_chars_to_smallint(int todb, const char *src, int16_t *dst) { + int64_t v; + TSDB_CONV_CODE code = tsdb_chars_to_bigint(todb, src, &v); + if (code!=TSDB_CONV_OK) return code; + + *dst = (int16_t)v; + + if (v==*dst) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_chars_to_int(int todb, const char *src, int32_t *dst) { + int64_t v; + TSDB_CONV_CODE code = tsdb_chars_to_bigint(todb, src, &v); + if (code!=TSDB_CONV_OK) return code; + + *dst = (int32_t)v; + + if (v==*dst) return TSDB_CONV_OK; + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_chars_to_bigint(int todb, const char *src, int64_t *dst) { + int bytes; + int n = sscanf(src, "%" PRId64 "%n", dst, &bytes); + + if (n!=1) return TSDB_CONV_CHAR_NOT_NUM; + if (bytes==strlen(src)) { + return TSDB_CONV_OK; + } + + double v; + n = sscanf(src, "%lg%n", &v, &bytes); + if (n!=1) return TSDB_CONV_CHAR_NOT_NUM; + if (bytes==strlen(src)) { + return TSDB_CONV_TRUNC_FRACTION; + } + + return TSDB_CONV_OK; +} + +TSDB_CONV_CODE tsdb_chars_to_ts(int todb, const char *src, int64_t *dst) { + int64_t v; + TSDB_CONV_CODE code = tsdb_chars_to_bigint(todb, src, &v); + if (code!=TSDB_CONV_OK) return code; + + *dst = v; + + if (v==*dst) { + time_t t = (time_t)(v / 1000); + struct tm tm = {0}; + if (localtime_r(&t, &tm)) return TSDB_CONV_OK; + } + + return TSDB_CONV_OOR; +} + +TSDB_CONV_CODE tsdb_chars_to_float(int todb, const char *src, float *dst) { + int bytes; + int n = sscanf(src, "%g%n", dst, &bytes); + + if (n==1 && bytes==strlen(src)) { + return TSDB_CONV_OK; + } + + return TSDB_CONV_CHAR_NOT_NUM; +} + +TSDB_CONV_CODE tsdb_chars_to_double(int todb, const char *src, double *dst) { + int bytes; + int n = sscanf(src, "%lg%n", dst, &bytes); + + if (n==1 && bytes==strlen(src)) { + return TSDB_CONV_OK; + } + + return TSDB_CONV_CHAR_NOT_NUM; +} + +TSDB_CONV_CODE tsdb_chars_to_char(int todb, const char *src, char *dst, size_t dlen) { + int n = snprintf(dst, dlen, "%s", src); + if (n= sizeof(buf)) { + plen = slen * 2 + 1; + p = (char*)malloc(plen); + if (!p) return TSDB_CONV_OOM; + } + + size_t n = wchars_to_chars2((const SQLWCHAR*)src, slen, (SQLCHAR*)p, plen); + + TSDB_CONV_CODE code = TSDB_CONV_OK; + do { + if (n<0) { + code = TSDB_CONV_CHAR_NOT_NUM; + break; + } + if (n>=plen) { + code = TSDB_CONV_CHAR_NOT_NUM; + break; + } + + p[n] = '\0'; + code = tsdb_chars_to_bit(todb, p, dst); + } while (0); + + if (p!=buf) { + free(p); + } + + return code; +} + +TSDB_CONV_CODE tsdb_wchars_to_tinyint(int todb, const unsigned char *src, size_t slen, int8_t *dst) { + char buf[4096]; + char *p = buf; + size_t plen = sizeof(buf); + if (slen * 2 + 1 >= sizeof(buf)) { + plen = slen * 2 + 1; + p = (char*)malloc(plen); + if (!p) return TSDB_CONV_OOM; + } + + size_t n = wchars_to_chars2((const SQLWCHAR*)src, slen, (SQLCHAR*)p, plen); + TSDB_CONV_CODE code = TSDB_CONV_OK; + do { + if (n<0) { + code = TSDB_CONV_CHAR_NOT_NUM; + break; + } + if (n>=sizeof(buf)) { + code = TSDB_CONV_CHAR_NOT_NUM; + break; + } + + buf[n] = '\0'; + code = tsdb_chars_to_tinyint(todb, buf, dst); + } while (0); + + if (p!=buf) { + free(p); + } + + return code; +} + + + + diff --git a/src/connector/odbc/src/todbc_conv.h b/src/connector/odbc/src/todbc_conv.h new file mode 100644 index 0000000000..3ff7e24de2 --- /dev/null +++ b/src/connector/odbc/src/todbc_conv.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef _todbc_conv_h_ +#define _todbc_conv_h_ + +#include +#include + +typedef enum { + TSDB_CONV_OK = 0, + TSDB_CONV_OOM, + TSDB_CONV_OOR, + TSDB_CONV_TRUNC_FRACTION, + TSDB_CONV_TRUNC, + TSDB_CONV_CHAR_NOT_NUM, +} TSDB_CONV_CODE; + +TSDB_CONV_CODE tsdb_int64_to_bit(int todb, int64_t src, int8_t *dst); +TSDB_CONV_CODE tsdb_int64_to_tinyint(int todb, int64_t src, int8_t *dst); +TSDB_CONV_CODE tsdb_int64_to_smallint(int todb, int64_t src, int16_t *dst); +TSDB_CONV_CODE tsdb_int64_to_int(int todb, int64_t src, int32_t *dst); +TSDB_CONV_CODE tsdb_int64_to_bigint(int todb, int64_t src, int64_t *dst); +TSDB_CONV_CODE tsdb_int64_to_ts(int todb, int64_t src, int64_t *dst); +TSDB_CONV_CODE tsdb_int64_to_float(int todb, int64_t src, float *dst); +TSDB_CONV_CODE tsdb_int64_to_double(int todb, int64_t src, double *dst); +TSDB_CONV_CODE tsdb_int64_to_char(int todb, int64_t src, char *dst, size_t dlen); + +TSDB_CONV_CODE tsdb_double_to_bit(int todb, double src, int8_t *dst); +TSDB_CONV_CODE tsdb_double_to_tinyint(int todb, double src, int8_t *dst); +TSDB_CONV_CODE tsdb_double_to_smallint(int todb, double src, int16_t *dst); +TSDB_CONV_CODE tsdb_double_to_int(int todb, double src, int32_t *dst); +TSDB_CONV_CODE tsdb_double_to_bigint(int todb, double src, int64_t *dst); +TSDB_CONV_CODE tsdb_double_to_ts(int todb, double src, int64_t *dst); + +TSDB_CONV_CODE tsdb_chars_to_bit(int todb, const char *src, int8_t *dst); +TSDB_CONV_CODE tsdb_chars_to_tinyint(int todb, const char *src, int8_t *dst); +TSDB_CONV_CODE tsdb_chars_to_smallint(int todb, const char *src, int16_t *dst); +TSDB_CONV_CODE tsdb_chars_to_int(int todb, const char *src, int32_t *dst); +TSDB_CONV_CODE tsdb_chars_to_bigint(int todb, const char *src, int64_t *dst); +TSDB_CONV_CODE tsdb_chars_to_ts(int todb, const char *src, int64_t *dst); +TSDB_CONV_CODE tsdb_chars_to_float(int todb, const char *src, float *dst); +TSDB_CONV_CODE tsdb_chars_to_double(int todb, const char *src, double *dst); +TSDB_CONV_CODE tsdb_chars_to_char(int todb, const char *src, char *dst, size_t dlen); + +TSDB_CONV_CODE tsdb_wchars_to_bit(int todb, const unsigned char *src, size_t slen, int8_t *dst); +TSDB_CONV_CODE tsdb_wchars_to_tinyint(int todb, const unsigned char *src, size_t slen, int8_t *dst); +TSDB_CONV_CODE tsdb_wchars_to_smallint(int todb, const unsigned char *src, size_t slen, int16_t *dst); +TSDB_CONV_CODE tsdb_wchars_to_int(int todb, const unsigned char *src, size_t slen, int32_t *dst); +TSDB_CONV_CODE tsdb_wchars_to_bigint(int todb, const unsigned char *src, size_t slen, int64_t *dst); +TSDB_CONV_CODE tsdb_wchars_to_ts(int todb, const unsigned char *src, size_t slen, int64_t *dst); +TSDB_CONV_CODE tsdb_wchars_to_float(int todb, const unsigned char *src, size_t slen, float *dst); +TSDB_CONV_CODE tsdb_wchars_to_double(int todb, const unsigned char *src, size_t slen, double *dst); +TSDB_CONV_CODE tsdb_wchars_to_char(int todb, const unsigned char *src, size_t slen, char *dst, size_t dlen); + +#endif // _todbc_conv_h_ + diff --git a/src/connector/odbc/src/todbc_util.c b/src/connector/odbc/src/todbc_util.c index b6b45d8120..378a2e1b75 100644 --- a/src/connector/odbc/src/todbc_util.c +++ b/src/connector/odbc/src/todbc_util.c @@ -236,3 +236,19 @@ SQLCHAR* wchars_to_chars(const SQLWCHAR *wchars, size_t chs, size_t *bytes) return dst; } +size_t wchars_to_chars2(const SQLWCHAR *src, size_t slen, SQLCHAR *dst, size_t dlen) +{ + size_t consumed=0, generated=0; + int n = string_conv("UCS-2LE", "UTF-8", (const unsigned char*)src, slen, dst, dlen, &consumed, &generated); + if (n) return -1; + return generated; +} + +size_t chars_to_wchars2(const SQLCHAR *src, size_t slen, SQLWCHAR *dst, size_t dlen) +{ + size_t consumed=0, generated=0; + int n = string_conv("UTF-8", "UCS-2LE", (const unsigned char*)src, slen, (unsigned char*)dst, dlen, &consumed, &generated); + if (n) return -1; + return generated; +} + diff --git a/src/connector/odbc/src/todbc_util.h b/src/connector/odbc/src/todbc_util.h index 43264975b4..b3c307b85f 100644 --- a/src/connector/odbc/src/todbc_util.h +++ b/src/connector/odbc/src/todbc_util.h @@ -60,4 +60,8 @@ unsigned char* utf8_to_ucs4le(const char *utf8, size_t *chars); char* ucs4le_to_utf8(const unsigned char *ucs4le, size_t slen, size_t *chars); SQLCHAR* wchars_to_chars(const SQLWCHAR *wchars, size_t chs, size_t *bytes); +size_t wchars_to_chars2(const SQLWCHAR *src, size_t slen, SQLCHAR *dst, size_t dlen); +size_t chars_to_wchars2(const SQLCHAR *src, size_t slen, SQLWCHAR *dst, size_t dlen); + #endif // _TODBC_UTIL_H_ + diff --git a/src/connector/odbc/tests/odbc.py b/src/connector/odbc/tests/odbc.py index d2de8f39c6..5218957fb9 100644 --- a/src/connector/odbc/tests/odbc.py +++ b/src/connector/odbc/tests/odbc.py @@ -118,3 +118,13 @@ while row: row = cursor.fetchone() cursor.close() +cursor = cnxn.cursor() +cursor.execute("create table db.f (ts timestamp, v1 bool)") +cursor.close() + +params = [ ('2020-10-20 00:00:00', 'acb') ] +cursor = cnxn.cursor() +cursor.fast_executemany = True +cursor.executemany("insert into db.f values (?, ?)", params) +cursor.close() + diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index bb111d2da0..ad8bce7ca7 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -355,20 +355,23 @@ TAOS_DEFINE_ERROR(TSDB_CODE_HTTP_OP_VALUE_NULL, 0, 0x11A5, "value not 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_OOM, 0, 0x2100, "out of memory") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_CHAR_NOT_NUM, 0, 0x2101, "convertion not a valid literal input") 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") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OUT_OF_RANGE, 0, 0x2105, "out of range") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NOT_SUPPORT, 0, 0x2106, "not supported yet") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_HANDLE, 0, 0x2107, "invalid handle") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_RESULT, 0, 0x2108, "no result set") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_FIELDS, 0, 0x2109, "no fields returned") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_CURSOR, 0, 0x2110, "invalid cursor") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_STATEMENT_NOT_READY, 0, 0x2111, "statement not ready") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONNECTION_BUSY, 0, 0x2112, "connection still busy") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_CONNSTR, 0, 0x2113, "bad connection string") -TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_ARG, 0, 0x2114, "bad argument") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_TRUNC_FRAC, 0, 0x2103, "convertion fractional truncated") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_TRUNC, 0, 0x2104, "convertion truncated") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_NOT_SUPPORT, 0, 0x2105, "convertion not supported") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_OOR, 0, 0x2106, "convertion numeric value out of range") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OUT_OF_RANGE, 0, 0x2107, "out of range") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NOT_SUPPORT, 0, 0x2108, "not supported yet") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_HANDLE, 0, 0x2109, "invalid handle") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_RESULT, 0, 0x210a, "no result set") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_FIELDS, 0, 0x210b, "no fields returned") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_CURSOR, 0, 0x210c, "invalid cursor") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_STATEMENT_NOT_READY, 0, 0x210d, "statement not ready") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONNECTION_BUSY, 0, 0x210e, "connection still busy") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_CONNSTR, 0, 0x210f, "bad connection string") +TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_ARG, 0, 0x2110, "bad argument") #ifdef TAOS_ERROR_C