提交 f43bbfea 编写于 作者: F freemine

adding charset-endec support

上级 7d332df5
......@@ -28,6 +28,11 @@
#include <sqlext.h>
#define UTF8_ENC "UTF-8"
#define UTF16_ENC "UCS-2LE"
#define UNICODE_ENC "UCS-4LE"
#define GB18030_ENC "GB18030"
#define GET_REF(obj) atomic_load_64(&obj->refcount)
#define INC_REF(obj) atomic_add_fetch_64(&obj->refcount, 1)
#define DEC_REF(obj) atomic_sub_fetch_64(&obj->refcount, 1)
......@@ -159,8 +164,8 @@ do { \
#define CHK_CONV(todb, statement) \
do { \
TSDB_CONV_CODE code = (statement); \
switch (code) { \
TSDB_CONV_CODE code_0c80 = (statement); \
switch (code_0c80) { \
case TSDB_CONV_OK: return SQL_SUCCESS; \
case TSDB_CONV_OOM: { \
SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, ""); \
......@@ -225,6 +230,16 @@ struct conn_s {
uint64_t refcount;
env_t *env;
char client_enc[64];
char server_enc[64];
tsdb_conv_t *client_to_server;
tsdb_conv_t *server_to_client;
tsdb_conv_t *utf8_to_client;
tsdb_conv_t *utf16_to_utf8;
tsdb_conv_t *utf16_to_server;
tsdb_conv_t *client_to_utf8;
TAOS *taos;
taos_error_t err;
......@@ -275,20 +290,88 @@ static iconv_t sql_get_w2c(sql_t *sql) {
return sql->w2c;
}
// typedef struct stack_buffer_s stack_buffer_t;
// struct stack_buffer_s {
// char buf[1024*16];
// size_t next;
// };
//
// static char* stack_buffer_alloc(stack_buffer_t *buffer, size_t bytes);
// static int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr);
//
// static const char* tsdb_conn_conv_client_to_server(conn_t *conn, stack_buffer_t *buffer, const char *src, size_t len);
// static const char* tsdb_conn_conv_server_to_client(conn_t *conn, stack_buffer_t *buffer, const char *src, size_t len);
// static const char* tsdb_conn_conv_wchars_to_server(conn_t *conn, stack_buffer_t *buffer, const char *src, size_t len);
// static const char* tsdb_conn_conv_server_to_wchars(conn_t *conn, stack_buffer_t *buffer, const char *src, size_t len);
//
static tsdb_conv_t* tsdb_conn_client_to_server(conn_t *conn) {
if (!conn->client_to_server) {
conn->client_to_server = tsdb_conv_open(conn->client_enc, conn->server_enc);
}
return conn->client_to_server;
}
static tsdb_conv_t* tsdb_conn_server_to_client(conn_t *conn) {
if (!conn->server_to_client) {
conn->server_to_client = tsdb_conv_open(conn->server_enc, conn->client_enc);
}
return conn->server_to_client;
}
static tsdb_conv_t* tsdb_conn_utf8_to_client(conn_t *conn) {
if (!conn->utf8_to_client) {
conn->utf8_to_client = tsdb_conv_open(UTF8_ENC, conn->client_enc);
}
return conn->utf8_to_client;
}
tsdb_conv_t* tsdb_conn_utf16_to_utf8(conn_t *conn) {
if (!conn->utf16_to_utf8) {
conn->utf16_to_utf8 = tsdb_conv_open(UTF16_ENC, UTF8_ENC);
}
return conn->utf16_to_utf8;
}
tsdb_conv_t* tsdb_conn_utf16_to_server(conn_t *conn) {
if (!conn->utf16_to_server) {
conn->utf16_to_server = tsdb_conv_open(UTF16_ENC, conn->server_enc);
}
return conn->utf16_to_server;
}
static tsdb_conv_t* tsdb_conn_client_to_utf8(conn_t *conn) {
if (!conn->client_to_utf8) {
conn->client_to_utf8 = tsdb_conv_open(conn->client_enc, UTF8_ENC);
}
return conn->client_to_utf8;
}
static void tsdb_conn_close_convs(conn_t *conn) {
if (0) {
tsdb_conn_server_to_client(NULL);
}
if (conn->client_to_server) {
tsdb_conv_close(conn->client_to_server);
conn->client_to_server = NULL;
}
if (conn->server_to_client) {
tsdb_conv_close(conn->server_to_client);
conn->server_to_client = NULL;
}
if (conn->utf8_to_client) {
tsdb_conv_close(conn->utf8_to_client);
conn->utf8_to_client = NULL;
}
if (conn->utf16_to_utf8) {
tsdb_conv_close(conn->utf16_to_utf8);
conn->utf16_to_utf8 = NULL;
}
if (conn->utf16_to_server) {
tsdb_conv_close(conn->utf16_to_server);
conn->utf16_to_server = NULL;
}
if (conn->client_to_utf8) {
tsdb_conv_close(conn->client_to_utf8);
conn->client_to_utf8 = NULL;
}
}
#define SFREE(buffer, v, src) \
do { \
const char *v_096a = (const char*)(v); \
const char *src_6a = (const char*)(src); \
if (v_096a && v_096a!=src_6a && !is_owned_by_stack_buffer((buffer), v_096a)) { \
free((char*)v_096a); \
} \
} while (0)
// static iconv_t sql_get_u2c(sql_t *sql) {
// if (sql->u2c == (iconv_t)-1) {
// sql->u2c = iconv_open("UTF-8", "UCS-4LE");
......@@ -375,6 +458,9 @@ static SQLRETURN doSQLAllocConnect(SQLHENV EnvironmentHandle,
break;
}
snprintf(conn->client_enc, sizeof(conn->client_enc), UTF8_ENC);
snprintf(conn->server_enc, sizeof(conn->server_enc), UTF8_ENC);
conn->env = env;
*ConnectionHandle = conn;
......@@ -416,6 +502,7 @@ static SQLRETURN doSQLFreeConnect(SQLHDBC ConnectionHandle)
conn->env = NULL;
FREE_ERROR(conn);
tsdb_conn_close_convs(conn);
free(conn);
} while (0);
......@@ -434,6 +521,8 @@ static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle,
SQLCHAR *UserName, SQLSMALLINT NameLength2,
SQLCHAR *Authentication, SQLSMALLINT NameLength3)
{
stack_buffer_t buffer; buffer.next = 0;
conn_t *conn = (conn_t*)ConnectionHandle;
if (!conn) return SQL_ERROR;
......@@ -451,12 +540,16 @@ static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle,
return SQL_ERROR;
}
const char *serverName = SDUP(ServerName, NameLength1);
const char *userName = SDUP(UserName, NameLength2);
const char *auth = SDUP(Authentication, NameLength3);
tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn);
const char *serverName = NULL;
const char *userName = NULL;
const char *auth = NULL;
do {
if ((ServerName && !serverName) || (UserName && !userName) || (Authentication && !auth)) {
tsdb_conv(client_to_server, &buffer, (const char*)ServerName, (size_t)NameLength1, &serverName, NULL);
tsdb_conv(client_to_server, &buffer, (const char*)UserName, (size_t)NameLength2, &userName, NULL);
tsdb_conv(client_to_server, &buffer, (const char*)Authentication, (size_t)NameLength3, &auth, NULL);
if ((!serverName) || (!userName) || (!auth)) {
SET_ERROR(conn, "HY001", TSDB_CODE_ODBC_OOM, "");
break;
}
......@@ -470,9 +563,9 @@ static SQLRETURN doSQLConnect(SQLHDBC ConnectionHandle,
}
} while (0);
SFRE(serverName, ServerName, NameLength1);
SFRE(userName, UserName, NameLength2);
SFRE(auth, Authentication, NameLength3);
tsdb_conv_free(client_to_server, serverName, &buffer, (const char*)ServerName);
tsdb_conv_free(client_to_server, userName, &buffer, (const char*)UserName);
tsdb_conv_free(client_to_server, auth, &buffer, (const char*)Authentication);
return conn->taos ? SQL_SUCCESS : SQL_ERROR;
}
......@@ -659,12 +752,16 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle,
static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength)
{
stack_buffer_t buffer; buffer.next = 0;
sql_t *sql = (sql_t*)StatementHandle;
if (!sql) return SQL_INVALID_HANDLE;
CHK_CONN(sql);
CHK_CONN_TAOS(sql);
conn_t *conn = sql->conn;
NORM_STR_LENGTH(sql, StatementText, TextLength);
if (sql->rs) {
......@@ -684,10 +781,12 @@ static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle,
}
sql->n_params = 0;
const char *stxt = SDUP(StatementText, TextLength);
tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn);
const char *stxt = NULL;
SQLRETURN r = SQL_ERROR;
do {
tsdb_conv(client_to_server, &buffer, (const char*)StatementText, (size_t)TextLength, &stxt, NULL);
if (!stxt) {
SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, "");
break;
......@@ -696,7 +795,7 @@ static SQLRETURN doSQLExecDirect(SQLHSTMT StatementHandle,
CHK_RS(r, sql, "failed to execute");
} while (0);
SFRE(stxt, StatementText, TextLength);
tsdb_conv_free(client_to_server, stxt, &buffer, (const char*)StatementText);
return r;
}
......@@ -901,6 +1000,8 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
CHK_CONN(sql);
CHK_CONN_TAOS(sql);
conn_t *conn = sql->conn;
if (!sql->rs) {
SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NO_RESULT, "");
return SQL_ERROR;
......@@ -911,8 +1012,6 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
return SQL_ERROR;
}
DASSERT(TargetValue);
int nfields = taos_field_count(sql->rs);
TAOS_FIELD *fields = taos_fetch_fields(sql->rs);
......@@ -925,14 +1024,20 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "NULL TargetValue not allowed for col [%d]", ColumnNumber);
return SQL_ERROR;
}
if (BufferLength<0) {
SET_ERROR(sql, "HY090", TSDB_CODE_ODBC_BAD_ARG, "");
return SQL_ERROR;
}
TAOS_FIELD *field = fields + ColumnNumber-1;
void *row = sql->row[ColumnNumber-1];
if (!row) {
if (StrLen_or_Ind) {
*StrLen_or_Ind = SQL_NULL_DATA;
if (!StrLen_or_Ind) {
SET_ERROR(sql, "22002", TSDB_CODE_ODBC_BAD_ARG, "NULL StrLen_or_Ind not allowed for col [%d]", ColumnNumber);
return SQL_ERROR;
}
*StrLen_or_Ind = SQL_NULL_DATA;
return SQL_SUCCESS;
}
......@@ -981,7 +1086,11 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
CHK_CONV(0, tsdb_int64_to_double(v, TargetValue));
} break;
case SQL_C_CHAR: {
CHK_CONV(0, tsdb_int64_to_char(v, TargetValue, (size_t)BufferLength));
tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn);
size_t len = (size_t)BufferLength;
TSDB_CONV_CODE code = tsdb_conv_write_int64(utf8_to_client, v, (char*)TargetValue, &len);
if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len;
CHK_CONV(0, code);
} break;
default: {
SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT,
......@@ -1003,7 +1112,11 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
return SQL_SUCCESS;
} break;
case SQL_C_CHAR: {
CHK_CONV(0, tsdb_double_to_char(v, TargetValue, (size_t)BufferLength));
tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn);
size_t len = (size_t)BufferLength;
TSDB_CONV_CODE code = tsdb_conv_write_double(utf8_to_client, v, (char*)TargetValue, &len);
if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len;
CHK_CONV(0, code);
} break;
default: {
SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT,
......@@ -1021,7 +1134,11 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
return SQL_SUCCESS;
} break;
case SQL_C_CHAR: {
CHK_CONV(0, tsdb_double_to_char(v, TargetValue, (size_t)BufferLength));
tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn);
size_t len = (size_t)BufferLength;
TSDB_CONV_CODE code = tsdb_conv_write_double(utf8_to_client, v, (char*)TargetValue, &len);
if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len;
CHK_CONV(0, code);
} break;
default: {
SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT,
......@@ -1050,7 +1167,11 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
return SQL_SUCCESS;
} break;
case SQL_C_CHAR: {
CHK_CONV(0, tsdb_timestamp_to_char(ts, TargetValue, (size_t)BufferLength));
tsdb_conv_t *utf8_to_client = tsdb_conn_utf8_to_client(conn);
size_t len = (size_t)BufferLength;
TSDB_CONV_CODE code = tsdb_conv_write_timestamp(utf8_to_client, ts, (char*)TargetValue, &len);
if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)len;
CHK_CONV(0, code);
} break;
case SQL_C_TYPE_TIMESTAMP:
case SQL_C_TIMESTAMP: {
......@@ -1070,7 +1191,14 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
field_bytes -= VARSTR_HEADER_SIZE;
switch (target.ct) {
case SQL_C_CHAR: {
CHK_CONV(0, tsdb_chars_to_char((const char*)row, field_bytes, TargetValue, (size_t)BufferLength));
tsdb_conv_t *server_to_client = tsdb_conn_server_to_client(conn);
size_t slen = strnlen((const char*)row, field_bytes);
size_t len = (size_t)BufferLength;
TSDB_CONV_CODE code = tsdb_conv_write(server_to_client,
(const char*)row, &slen,
(char*)TargetValue, &len);
if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)((size_t)BufferLength - len);
CHK_CONV(0, code);
} break;
default: {
SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT,
......@@ -1085,7 +1213,14 @@ static SQLRETURN doSQLGetData(SQLHSTMT StatementHandle,
field_bytes -= VARSTR_HEADER_SIZE;
switch (target.ct) {
case SQL_C_CHAR: {
CHK_CONV(0, tsdb_chars_to_char((const char*)row, field_bytes, TargetValue, (size_t)BufferLength));
tsdb_conv_t *server_to_client = tsdb_conn_server_to_client(conn);
size_t slen = strnlen((const char*)row, field_bytes);
size_t len = (size_t)BufferLength;
TSDB_CONV_CODE code = tsdb_conv_write(server_to_client,
(const char*)row, &slen,
(char*)TargetValue, &len);
if (StrLen_or_Ind) *StrLen_or_Ind = (SQLLEN)((size_t)BufferLength - len);
CHK_CONV(0, code);
} break;
default: {
SET_ERROR(sql, "HYC00", TSDB_CODE_ODBC_NOT_SUPPORT,
......@@ -1144,12 +1279,16 @@ SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle)
static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength)
{
stack_buffer_t buffer; buffer.next = 0;
sql_t *sql = (sql_t*)StatementHandle;
if (!sql) return SQL_INVALID_HANDLE;
CHK_CONN(sql);
CHK_CONN_TAOS(sql);
conn_t *conn = sql->conn;
NORM_STR_LENGTH(sql, StatementText, TextLength);
if (sql->rs) {
......@@ -1177,9 +1316,17 @@ static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle,
break;
}
tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn);
const char *stxt = NULL;
int ok = 0;
do {
int r = taos_stmt_prepare(sql->stmt, (const char *)StatementText, (unsigned long)TextLength);
tsdb_conv(client_to_server, &buffer, (const char*)StatementText, (size_t)TextLength, &stxt, NULL);
if ((!stxt)) {
SET_ERROR(sql, "HY001", TSDB_CODE_ODBC_OOM, "");
break;
}
int r = taos_stmt_prepare(sql->stmt, stxt, (unsigned long)strlen(stxt));
if (r) {
SET_ERROR(sql, "HY000", r, "failed to prepare a TAOS statement");
break;
......@@ -1216,6 +1363,8 @@ static SQLRETURN doSQLPrepare(SQLHSTMT StatementHandle,
ok = 1;
} while (0);
tsdb_conv_free(client_to_server, stxt, &buffer, (const char*)StatementText);
if (!ok) {
taos_stmt_close(sql->stmt);
sql->stmt = NULL;
......@@ -1245,6 +1394,16 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
SET_ERROR(sql, "HY000", TSDB_CODE_ODBC_NOT_SUPPORT, "parameter [@%d] not bound yet", idx+1);
return SQL_ERROR;
}
if (param->ParameterValue==NULL) {
SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "ParameterValue [@%p] not allowed", param->ParameterValue);
return SQL_ERROR;
}
if (param->StrLen_or_Ind==NULL) {
SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "StrLen_or_Ind [@%p] not allowed", param->StrLen_or_Ind);
return SQL_ERROR;
}
conn_t *conn = sql->conn;
unsigned char *paramValue = param->ParameterValue;
SQLSMALLINT valueType = param->ValueType;
......@@ -1252,11 +1411,11 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
size_t offset = ((size_t)idx_row) * sql->rowlen + sql->ptr_offset;
if (paramValue) paramValue += offset;
if (soi) soi = (SQLLEN*)((char*)soi + offset);
paramValue += offset;
soi = (SQLLEN*)((char*)soi + offset);
if (soi && *soi == SQL_NULL_DATA) {
if (*soi == SQL_NULL_DATA) {
bind->is_null = (int*)&yes;
return SQL_SUCCESS;
}
......@@ -1271,6 +1430,7 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
}
} else {
switch (valueType) {
case SQL_C_SLONG:
case SQL_C_LONG: {
type = TSDB_DATA_TYPE_INT;
} break;
......@@ -1282,7 +1442,6 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_FLOAT:
case SQL_C_DOUBLE:
......@@ -1344,7 +1503,12 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
CHK_CONV(1, tsdb_double_to_bit(*(double*)paramValue, &bind->u.b));
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_bit((const char *)paramValue, (size_t)*soi, &bind->u.b));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_bit(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.b));
// CHK_CONV(1, tsdb_chars_to_bit((const char *)paramValue, (size_t)*soi, &bind->u.b));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_bit(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.b));
......@@ -1396,7 +1560,12 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
CHK_CONV(1, tsdb_int64_to_tinyint(*(int64_t*)paramValue, &bind->u.v1));
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_tinyint((const char*)paramValue, (size_t)*soi, &bind->u.v1));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_tinyint(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v1));
// CHK_CONV(1, tsdb_chars_to_tinyint((const char *)paramValue, (size_t)*soi, &bind->u.v1));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_tinyint(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.v1));
......@@ -1450,7 +1619,12 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
CHK_CONV(1, tsdb_int64_to_smallint(*(int64_t*)paramValue, &bind->u.v2));
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_smallint((const char*)paramValue, (size_t)*soi, &bind->u.v2));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_smallint(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v2));
// CHK_CONV(1, tsdb_chars_to_smallint((const char*)paramValue, (size_t)*soi, &bind->u.v2));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_smallint(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.v2));
......@@ -1504,7 +1678,12 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
CHK_CONV(1, tsdb_int64_to_int(*(int64_t*)paramValue, &bind->u.v4));
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_int((const char*)paramValue, (size_t)*soi, &bind->u.v4));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_int(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v4));
// CHK_CONV(1, tsdb_chars_to_int((const char*)paramValue, (size_t)*soi, &bind->u.v4));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_int(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.v4));
......@@ -1558,7 +1737,12 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
CHK_CONV(1, tsdb_int64_to_bigint(*(int64_t*)paramValue, &bind->u.v8));
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_bigint((const char*)paramValue, (size_t)*soi, &bind->u.v8));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_bigint(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8));
// CHK_CONV(1, tsdb_chars_to_bigint((const char*)paramValue, (size_t)*soi, &bind->u.v8));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_bigint(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.v8));
......@@ -1618,10 +1802,20 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
bind->u.f4 = (float)*(double*)paramValue;
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_float((const char*)paramValue, (size_t)*soi, &bind->u.f4));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_float(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f4));
// CHK_CONV(1, tsdb_chars_to_float((const char*)paramValue, (size_t)*soi, &bind->u.f4));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_float(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.f4));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn);
size_t slen = (size_t)*soi;
DASSERT(slen != SQL_NTS);
CHK_CONV(1, tsdb_conv_chars_to_float(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f4));
// CHK_CONV(1, tsdb_wchars_to_float(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.f4));
} break;
case SQL_C_USHORT:
case SQL_C_ULONG:
......@@ -1676,10 +1870,20 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
bind->u.f8 = *(double*)paramValue;
} break;
case SQL_C_CHAR: {
CHK_CONV(1, tsdb_chars_to_double((const char*)paramValue, (size_t)*soi, &bind->u.f8));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
CHK_CONV(1, tsdb_conv_chars_to_double(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f8));
// CHK_CONV(1, tsdb_chars_to_double((const char*)paramValue, (size_t)*soi, &bind->u.f8));
} break;
case SQL_C_WCHAR: {
CHK_CONV(1, tsdb_wchars_to_double(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.f8));
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn);
size_t slen = (size_t)*soi;
DASSERT(slen != SQL_NTS);
CHK_CONV(1, tsdb_conv_chars_to_double(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.f8));
// CHK_CONV(1, tsdb_wchars_to_double(sql_get_w2c(sql), (const unsigned char*)paramValue, (size_t)*soi, &bind->u.f8));
} break;
case SQL_C_USHORT:
case SQL_C_ULONG:
......@@ -1703,30 +1907,30 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
} break;
}
} break;
case TSDB_DATA_TYPE_BINARY: {
case TSDB_DATA_TYPE_TIMESTAMP: {
bind->buffer_type = type;
bind->buffer_length = sizeof(bind->u.v8);
bind->buffer = &bind->u.v8;
bind->length = &bind->buffer_length;
switch (valueType) {
case SQL_C_CHAR: {
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *client_to_utf8 = tsdb_conn_client_to_utf8(conn);
size_t slen = (size_t)*soi;
DASSERT(slen != SQL_NTS);
CHK_CONV(1, tsdb_conv_chars_to_timestamp_ts(client_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8));
} break;
case SQL_C_WCHAR: {
DASSERT(soi);
DASSERT(*soi != SQL_NTS);
size_t bytes = 0;
SQLCHAR *utf8 = wchars_to_chars((const SQLWCHAR*)paramValue, (size_t)*soi/2, &bytes);
bind->allocated = 1;
bind->u.bin = utf8;
bind->buffer_length = bytes;
bind->buffer = bind->u.bin;
} break;
case SQL_C_BINARY: {
bind->u.bin = (unsigned char*)paramValue;
if (*soi == SQL_NTS) {
bind->buffer_length = strlen((const char*)paramValue);
} else {
bind->buffer_length = (uintptr_t)*soi;
}
bind->buffer = bind->u.bin;
stack_buffer_t buffer; buffer.next = 0;
tsdb_conv_t *utf16_to_utf8 = tsdb_conn_utf16_to_utf8(conn);
size_t slen = (size_t)*soi;
DASSERT(slen != SQL_NTS);
CHK_CONV(1, tsdb_conv_chars_to_timestamp_ts(utf16_to_utf8, &buffer, (const char *)paramValue, slen, &bind->u.v8));
} break;
case SQL_C_SBIGINT: {
int64_t t = *(int64_t*)paramValue;
bind->u.v8 = t;
} break;
case SQL_C_CHAR:
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
......@@ -1735,12 +1939,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_BINARY:
case SQL_C_DATE:
case SQL_C_TIME:
case SQL_C_TIMESTAMP:
......@@ -1758,34 +1962,50 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
} break;
}
} break;
case TSDB_DATA_TYPE_TIMESTAMP: {
case TSDB_DATA_TYPE_BINARY: {
bind->buffer_type = type;
bind->buffer_length = sizeof(bind->u.v8);
bind->buffer = &bind->u.v8;
bind->length = &bind->buffer_length;
switch (valueType) {
case SQL_C_WCHAR: {
DASSERT(soi);
DASSERT(*soi != SQL_NTS);
size_t bytes = 0;
int r = 0;
int64_t t = 0;
SQLCHAR *utf8 = wchars_to_chars((const SQLWCHAR*)paramValue, (size_t)*soi/2, &bytes);
// why cast utf8 to 'char*' ?
r = taosParseTime((char*)utf8, &t, (int)strlen((const char*)utf8), TSDB_TIME_PRECISION_MILLI, 0);
bind->u.v8 = t;
free(utf8);
if (r) {
SET_ERROR(sql, "22007", TSDB_CODE_ODBC_OUT_OF_RANGE,
"convertion from [%s[%d/0x%x]] to [%s[%d/0x%x]] for parameter [%d] failed",
sql_c_type(valueType), valueType, valueType,
taos_data_type(type), type, type, idx+1);
return SQL_ERROR;
tsdb_conv_t *utf16_to_server = tsdb_conn_utf16_to_server(conn);
size_t slen = (size_t)*soi;
DASSERT(slen != SQL_NTS);
const char *buf = NULL;
size_t blen = 0;
TSDB_CONV_CODE code = tsdb_conv(utf16_to_server, NULL, (const char *)paramValue, slen, &buf, &blen);
if (code==TSDB_CONV_OK) {
if (buf!=(const char*)paramValue) {
bind->allocated = 1;
}
bind->u.bin = (unsigned char*)buf;
bind->buffer_length = blen;
bind->buffer = bind->u.bin;
}
CHK_CONV(1, code);
} break;
case SQL_C_SBIGINT: {
int64_t t = *(int64_t*)paramValue;
bind->u.v8 = t;
case SQL_C_CHAR: {
tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
const char *buf = NULL;
size_t blen = 0;
TSDB_CONV_CODE code = tsdb_conv(client_to_server, NULL, (const char *)paramValue, slen, &buf, &blen);
if (code==TSDB_CONV_OK) {
if (buf!=(const char*)paramValue) {
bind->allocated = 1;
}
bind->u.bin = (unsigned char*)buf;
bind->buffer_length = blen;
bind->buffer = bind->u.bin;
}
CHK_CONV(1, code);
// bind->u.bin = (unsigned char*)paramValue;
// if (*soi == SQL_NTS) {
// bind->buffer_length = strlen((const char*)paramValue);
// } else {
// bind->buffer_length = (uintptr_t)*soi;
// }
// bind->buffer = bind->u.bin;
} break;
case SQL_C_SHORT:
case SQL_C_SSHORT:
......@@ -1795,11 +2015,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_BINARY:
case SQL_C_DATE:
case SQL_C_TIME:
......@@ -1823,23 +2044,45 @@ static SQLRETURN do_bind_param_value(sql_t *sql, int idx_row, int idx, param_bin
bind->length = &bind->buffer_length;
switch (valueType) {
case SQL_C_WCHAR: {
DASSERT(soi);
DASSERT(*soi != SQL_NTS);
size_t bytes = 0;
SQLCHAR *utf8 = wchars_to_chars((const SQLWCHAR*)paramValue, (size_t)(*soi/2), &bytes);
bind->allocated = 1;
bind->u.nchar = (char*)utf8;
bind->buffer_length = bytes;
bind->buffer = bind->u.nchar;
tsdb_conv_t *utf16_to_server = tsdb_conn_utf16_to_server(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
const char *buf = NULL;
size_t blen = 0;
TSDB_CONV_CODE code = tsdb_conv(utf16_to_server, NULL, (const char *)paramValue, slen, &buf, &blen);
if (code==TSDB_CONV_OK) {
if (buf!=(const char*)paramValue) {
bind->allocated = 1;
}
bind->u.nchar = (char*)buf;
bind->buffer_length = blen;
bind->buffer = bind->u.nchar;
}
CHK_CONV(1, code);
} break;
case SQL_C_CHAR: {
bind->u.nchar = (char*)paramValue;
if (*soi == SQL_NTS) {
bind->buffer_length = strlen((const char*)paramValue);
} else {
bind->buffer_length = (uintptr_t)*soi;
tsdb_conv_t *client_to_server = tsdb_conn_client_to_server(conn);
size_t slen = (size_t)*soi;
if (slen==SQL_NTS) slen = strlen((const char*)paramValue);
const char *buf = NULL;
size_t blen = 0;
TSDB_CONV_CODE code = tsdb_conv(client_to_server, NULL, (const char *)paramValue, slen, &buf, &blen);
if (code==TSDB_CONV_OK) {
if (buf!=(const char*)paramValue) {
bind->allocated = 1;
}
bind->u.bin = (unsigned char*)buf;
bind->buffer_length = blen;
bind->buffer = bind->u.bin;
}
bind->buffer = bind->u.nchar;
CHK_CONV(1, code);
// bind->u.nchar = (char*)paramValue;
// if (*soi == SQL_NTS) {
// bind->buffer_length = strlen((const char*)paramValue);
// } else {
// bind->buffer_length = (uintptr_t)*soi;
// }
// bind->buffer = bind->u.nchar;
} break;
case SQL_C_SHORT:
case SQL_C_SSHORT:
......@@ -2110,6 +2353,16 @@ static SQLRETURN doSQLBindParameter(
return SQL_ERROR;
}
if (ParameterValue==NULL) {
SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "ParameterValue [@%p] not allowed", ParameterValue);
return SQL_ERROR;
}
if (StrLen_or_Ind==NULL) {
SET_ERROR(sql, "HY009", TSDB_CODE_ODBC_BAD_ARG, "StrLen_or_Ind [@%p] not allowed", StrLen_or_Ind);
return SQL_ERROR;
}
param_bind_t *pb = sql->params + ParameterNumber - 1;
pb->ParameterNumber = ParameterNumber;
......@@ -2171,12 +2424,7 @@ static SQLRETURN doSQLDriverConnect(
const char *connStr = SDUP(szConnStrIn, cbConnStrIn);
char *serverName = NULL;
char *userName = NULL;
char *auth = NULL;
char *host = NULL;
char *ip = NULL;
int port = 0;
conn_val_t val = {0};
do {
if (szConnStrIn && !connStr) {
......@@ -2184,22 +2432,37 @@ static SQLRETURN doSQLDriverConnect(
break;
}
int n = todbc_parse_conn_string((const char *)connStr, &serverName, &userName, &auth, &host);
int n = todbc_parse_conn_string((const char *)connStr, &val);
if (n) {
SET_ERROR(conn, "HY000", TSDB_CODE_ODBC_BAD_CONNSTR, "unrecognized connection string: [%s]", (const char*)szConnStrIn);
break;
}
if (host) {
char *p = strchr(host, ':');
char *ip = NULL;
int port = 0;
if (val.host) {
char *p = strchr(val.host, ':');
if (p) {
ip = strndup(host, (size_t)(p-host));
ip = strndup(val.host, (size_t)(p-val.host));
port = atoi(p+1);
}
}
if ((val.cli_enc && strcmp(val.cli_enc, conn->client_enc)) ||
(val.svr_enc && strcmp(val.svr_enc, conn->server_enc)) )
{
tsdb_conn_close_convs(conn);
if (val.cli_enc) {
snprintf(conn->client_enc, sizeof(conn->client_enc), "%s", val.cli_enc);
}
if (val.svr_enc) {
snprintf(conn->server_enc, sizeof(conn->server_enc), "%s", val.svr_enc);
}
}
// TODO: data-race
// TODO: shall receive ip/port from odbc.ini
conn->taos = taos_connect(ip ? ip : "localhost", userName, auth, NULL, (uint16_t)port);
// shall we support non-ansi uid/pwd/db etc?
conn->taos = taos_connect(ip ? ip : "localhost", val.uid, val.pwd, val.db, (uint16_t)port);
free(ip); ip = NULL;
if (!conn->taos) {
SET_ERROR(conn, "HY000", terrno, "failed to connect to data source");
......@@ -2212,12 +2475,9 @@ static SQLRETURN doSQLDriverConnect(
if (pcbConnStrOut) {
*pcbConnStrOut = cbConnStrIn;
}
} while (0);
if (serverName) free(serverName);
if (userName) free(userName);
if (auth) free(auth);
conn_val_reset(&val);
SFRE(connStr, szConnStrIn, cbConnStrIn);
......
......@@ -15,6 +15,8 @@
#include "todbc_conv.h"
#include "todbc_log.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
......@@ -53,11 +55,13 @@ static void buf_clean(buf_t *buf) {
const char* tsdb_conv_code_str(TSDB_CONV_CODE code) {
switch (code) {
case TSDB_CONV_OK: return "TSDB_CONV_OK";
case TSDB_CONV_NOT_AVAIL: return "TSDB_CONV_NOT_AVAIL";
case TSDB_CONV_OOM: return "TSDB_CONV_OOM";
case TSDB_CONV_OOR: return "TSDB_CONV_OOR";
case TSDB_CONV_TRUNC_FRACTION: return "TSDB_CONV_TRUNC_FRACTION";
case TSDB_CONV_TRUNC: return "TSDB_CONV_TRUNC";
case TSDB_CONV_CHAR_NOT_NUM: return "TSDB_CONV_CHAR_NOT_NUM";
case TSDB_CONV_CHAR_NOT_TS: return "TSDB_CONV_CHAR_NOT_TS";
case TSDB_CONV_GENERAL: return "TSDB_CONV_GENERAL";
case TSDB_CONV_BAD_CHAR: return "TSDB_CONV_BAD_CHAR";
default: return "UNKNOWN";
......@@ -154,6 +158,7 @@ TSDB_CONV_CODE tsdb_int64_to_double(int64_t src, double *dst) {
TSDB_CONV_CODE tsdb_int64_to_char(int64_t src, char *dst, size_t dlen) {
int n = snprintf(dst, dlen, "%" PRId64 "", src);
DASSERT(n>=0);
if (n<dlen) return TSDB_CONV_OK;
......@@ -238,6 +243,7 @@ TSDB_CONV_CODE tsdb_double_to_ts(double src, int64_t *dst) {
TSDB_CONV_CODE tsdb_double_to_char(double src, char *dst, size_t dlen) {
int n = snprintf(dst, dlen, "%lg", src);
DASSERT(n>=0);
if (n<dlen) return TSDB_CONV_OK;
......@@ -250,6 +256,7 @@ TSDB_CONV_CODE tsdb_timestamp_to_char(SQL_TIMESTAMP_STRUCT src, char *dst, size_
src.year, src.month, src.day,
src.hour, src.minute, src.second,
src.fraction / 1000000);
DASSERT(n>=0);
if (n<dlen) return TSDB_CONV_OK;
if (strlen(dst)>=19) return TSDB_CONV_TRUNC_FRACTION;
......@@ -374,8 +381,43 @@ TSDB_CONV_CODE tsdb_chars_to_double(const char *src, size_t smax, double *dst) {
return TSDB_CONV_CHAR_NOT_NUM;
}
TSDB_CONV_CODE tsdb_chars_to_timestamp(const char *src, size_t smax, SQL_TIMESTAMP_STRUCT *dst) {
int64_t v = 0;
// why cast to 'char*' ?
int r = taosParseTime((char*)src, &v, (int32_t)smax, TSDB_TIME_PRECISION_MILLI, 0);
if (r) {
return TSDB_CONV_CHAR_NOT_TS;
}
time_t t = v/1000;
struct tm vtm = {0};
localtime_r(&t, &vtm);
dst->year = (SQLSMALLINT)(vtm.tm_year + 1900);
dst->month = (SQLUSMALLINT)(vtm.tm_mon + 1);
dst->day = (SQLUSMALLINT)(vtm.tm_mday);
dst->hour = (SQLUSMALLINT)(vtm.tm_hour);
dst->minute = (SQLUSMALLINT)(vtm.tm_min);
dst->second = (SQLUSMALLINT)(vtm.tm_sec);
dst->fraction = (SQLUINTEGER)(v%1000 * 1000000);
return TSDB_CONV_OK;
}
TSDB_CONV_CODE tsdb_chars_to_timestamp_ts(const char *src, size_t smax, int64_t *dst) {
// why cast to 'char*' ?
int r = taosParseTime((char*)src, dst, (int32_t)smax, TSDB_TIME_PRECISION_MILLI, 0);
if (r) {
return TSDB_CONV_CHAR_NOT_TS;
}
return TSDB_CONV_OK;
}
TSDB_CONV_CODE tsdb_chars_to_char(const char *src, size_t smax, char *dst, size_t dmax) {
int n = snprintf(dst, dmax, "%s", src);
DASSERT(n>=0);
if (n<dmax) return TSDB_CONV_OK;
return TSDB_CONV_TRUNC;
......@@ -524,5 +566,264 @@ TSDB_CONV_CODE tsdb_wchars_to_char(iconv_t cnv, const unsigned char *src, size_t
return tsdb_iconv_conv(cnv, src, &smax, (unsigned char*)dst, &dmax);
}
char* stack_buffer_alloc(stack_buffer_t *buffer, size_t bytes) {
if (!buffer) return NULL;
// align-by-size_of-size_t-bytes
if (bytes==0) bytes = sizeof(size_t);
bytes = (bytes + sizeof(size_t) - 1) / sizeof(size_t) * sizeof(size_t);
size_t next = buffer->next + bytes;
if (next>sizeof(buffer->buf)) return NULL;
char *p = buffer->buf + buffer->next;
buffer->next = next;
return p;
}
int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr) {
if (!buffer) return 0;
if (ptr>=buffer->buf && ptr<buffer->buf+buffer->next) return 1;
return 0;
}
struct tsdb_conv_s {
iconv_t cnv;
unsigned int direct:1;
};
tsdb_conv_t* tsdb_conv_open(const char *from_enc, const char *to_enc) {
tsdb_conv_t *cnv = (tsdb_conv_t*)calloc(1, sizeof(*cnv));
if (!cnv) return NULL;
if (strcmp(from_enc, to_enc)==0) {
cnv->cnv = (iconv_t)-1;
cnv->direct = 1;
return cnv;
}
cnv->cnv = iconv_open(to_enc, from_enc);
if (cnv->cnv == (iconv_t)-1) {
free(cnv);
return NULL;
}
cnv->direct = 0;
return cnv;
}
void tsdb_conv_close(tsdb_conv_t *cnv) {
if (!cnv) return;
if (!cnv->direct) {
if (cnv->cnv != (iconv_t)-1) {
iconv_close(cnv->cnv);
}
}
cnv->cnv = (iconv_t)-1;
cnv->direct = 0;
free(cnv);
}
TSDB_CONV_CODE tsdb_conv_write(tsdb_conv_t *cnv, const char *src, size_t *slen, char *dst, size_t *dlen) {
if (!cnv) return TSDB_CONV_NOT_AVAIL;
if (cnv->direct) {
size_t n = (*slen > *dlen) ? *dlen : *slen;
memcpy(dst, src, n);
*slen -= n;
*dlen -= n;
if (*dlen) dst[n] = '\0';
return TSDB_CONV_OK;
}
if (!cnv->cnv) return TSDB_CONV_NOT_AVAIL;
size_t r = iconv(cnv->cnv, (char**)&src, slen, &dst, dlen);
if (r==(size_t)-1) return TSDB_CONV_BAD_CHAR;
if (*slen) return TSDB_CONV_TRUNC;
if (*dlen) *dst = '\0';
return TSDB_CONV_OK;
}
TSDB_CONV_CODE tsdb_conv_write_int64(tsdb_conv_t *cnv, int64_t val, char *dst, size_t *dlen) {
char utf8[64];
int n = snprintf(utf8, sizeof(utf8), "%" PRId64 "", val);
DASSERT(n>=0);
DASSERT(n<sizeof(utf8));
size_t len = (size_t)n;
TSDB_CONV_CODE code = tsdb_conv_write(cnv, utf8, &len, dst, dlen);
*dlen = (size_t)n+1;
return code;
}
TSDB_CONV_CODE tsdb_conv_write_double(tsdb_conv_t *cnv, double val, char *dst, size_t *dlen) {
char utf8[256];
int n = snprintf(utf8, sizeof(utf8), "%g", val);
DASSERT(n>=0);
DASSERT(n<sizeof(utf8));
size_t len = (size_t)n;
TSDB_CONV_CODE code = tsdb_conv_write(cnv, utf8, &len, dst, dlen);
*dlen = (size_t)n+1;
return code;
}
TSDB_CONV_CODE tsdb_conv_write_timestamp(tsdb_conv_t *cnv, SQL_TIMESTAMP_STRUCT val, char *dst, size_t *dlen) {
char utf8[256];
int n = snprintf(utf8, sizeof(utf8), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
val.year, val.month, val.day,
val.hour, val.minute, val.second,
val.fraction / 1000000);
DASSERT(n>=0);
DASSERT(n<sizeof(utf8));
size_t len = (size_t)n;
TSDB_CONV_CODE code = tsdb_conv_write(cnv, utf8, &len, dst, dlen);
*dlen = (size_t)n+1;
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_bit(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_bit(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_tinyint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_tinyint(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_smallint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int16_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_smallint(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_int(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int32_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_int(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_bigint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_bigint(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_ts(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_float(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, float *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_float(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_double(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, double *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_double(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, SQL_TIMESTAMP_STRUCT *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_timestamp(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst) {
const char *utf8 = NULL;
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
if (code) return code;
code = tsdb_chars_to_timestamp_ts(utf8, sizeof(utf8), dst);
tsdb_conv_free(cnv, utf8, buffer, src);
return code;
}
TSDB_CONV_CODE tsdb_conv(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, const char **dst, size_t *dlen) {
if (!cnv) return TSDB_CONV_NOT_AVAIL;
char *buf;
size_t blen;
if (cnv->direct) {
if (src[slen]=='\0') { // access violation?
*dst = src;
if (dlen) *dlen = slen;
return TSDB_CONV_OK;
}
blen = slen + 1;
} else {
blen = (slen + 1) * 4;
}
buf = stack_buffer_alloc(buffer, blen);
if (!buf) {
buf = (char*)malloc(blen);
if (!buf) return TSDB_CONV_OOM;
}
if (cnv->direct) {
size_t n = slen;
DASSERT(blen > n);
memcpy(buf, src, n);
buf[n] = '\0';
*dst = buf;
if (dlen) *dlen = n;
return TSDB_CONV_OK;
}
const char *orig_s = src;
char *orig_d = buf;
size_t orig_blen = blen;
TSDB_CONV_CODE code;
size_t r = iconv(cnv->cnv, (char**)&src, &slen, &buf, &blen);
do {
if (r==(size_t)-1) {
code = TSDB_CONV_BAD_CHAR;
break;
}
if (slen) {
code = TSDB_CONV_TRUNC;
break;
}
DASSERT(blen);
*buf = '\0';
*dst = orig_d;
if (dlen) *dlen = orig_blen - blen;
return TSDB_CONV_OK;
} while (0);
if (orig_d!=(char*)orig_s && !is_owned_by_stack_buffer(buffer, orig_d)) free(orig_d);
return code;
}
void tsdb_conv_free(tsdb_conv_t *cnv, const char *ptr, stack_buffer_t *buffer, const char *src) {
if (ptr!=src && !is_owned_by_stack_buffer(buffer, ptr)) free((char*)ptr);
}
......@@ -23,17 +23,50 @@
typedef enum {
TSDB_CONV_OK = 0,
TSDB_CONV_NOT_AVAIL,
TSDB_CONV_OOM,
TSDB_CONV_OOR,
TSDB_CONV_TRUNC_FRACTION,
TSDB_CONV_TRUNC,
TSDB_CONV_CHAR_NOT_NUM,
TSDB_CONV_CHAR_NOT_TS,
TSDB_CONV_GENERAL,
TSDB_CONV_BAD_CHAR,
} TSDB_CONV_CODE;
const char* tsdb_conv_code_str(TSDB_CONV_CODE code);
typedef struct stack_buffer_s stack_buffer_t;
struct stack_buffer_s {
char buf[1024*16];
size_t next;
};
char* stack_buffer_alloc(stack_buffer_t *buffer, size_t bytes);
int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr);
typedef struct tsdb_conv_s tsdb_conv_t;
tsdb_conv_t* tsdb_conv_open(const char *from_enc, const char *to_enc);
void tsdb_conv_close(tsdb_conv_t *cnv);
TSDB_CONV_CODE tsdb_conv_write(tsdb_conv_t *cnv, const char *src, size_t *slen, char *dst, size_t *dlen);
TSDB_CONV_CODE tsdb_conv_write_int64(tsdb_conv_t *cnv, int64_t val, char *dst, size_t *dlen);
TSDB_CONV_CODE tsdb_conv_write_double(tsdb_conv_t *cnv, double val, char *dst, size_t *dlen);
TSDB_CONV_CODE tsdb_conv_write_timestamp(tsdb_conv_t *cnv, SQL_TIMESTAMP_STRUCT val, char *dst, size_t *dlen);
TSDB_CONV_CODE tsdb_conv_chars_to_bit(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_tinyint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_smallint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int16_t *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_int(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int32_t *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_bigint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_float(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, float *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_double(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, double *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, SQL_TIMESTAMP_STRUCT *dst);
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst);
TSDB_CONV_CODE tsdb_conv(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, const char **dst, size_t *dlen);
void tsdb_conv_free(tsdb_conv_t *cnv, const char *ptr, stack_buffer_t *buffer, const char *src);
TSDB_CONV_CODE tsdb_iconv_conv(iconv_t cnv, const unsigned char *src, size_t *slen, unsigned char *dst, size_t *dlen);
......@@ -66,6 +99,7 @@ TSDB_CONV_CODE tsdb_chars_to_bigint(const char *src, size_t smax, int64_t *dst);
TSDB_CONV_CODE tsdb_chars_to_ts(const char *src, size_t smax, int64_t *dst);
TSDB_CONV_CODE tsdb_chars_to_float(const char *src, size_t smax, float *dst);
TSDB_CONV_CODE tsdb_chars_to_double(const char *src, size_t smax, double *dst);
TSDB_CONV_CODE tsdb_chars_to_timestamp(const char *src, size_t smax, SQL_TIMESTAMP_STRUCT *dst);
TSDB_CONV_CODE tsdb_chars_to_char(const char *src, size_t smax, char *dst, size_t dmax);
TSDB_CONV_CODE tsdb_wchars_to_bit(iconv_t cnv, const unsigned char *src, size_t smax, int8_t *dst);
......
......@@ -16,7 +16,21 @@
#ifndef _TODBC_FLEX_H_
#define _TODBC_FLEX_H_
int todbc_parse_conn_string(const char *conn, char **dsn, char **uid, char **pwd, char **host);
typedef struct conn_val_s conn_val_t;
struct conn_val_s {
char *key;
char *dsn;
char *uid;
char *pwd;
char *db;
char *host;
char *svr_enc;
char *cli_enc;
};
void conn_val_reset(conn_val_t *val);
int todbc_parse_conn_string(const char *conn, conn_val_t *val);
#endif // _TODBC_FLEX_H_
......@@ -7,15 +7,6 @@
#define strcasecmp _stricmp
#endif
typedef struct params_s params_t;
struct params_s {
char *key;
char *dsn;
char *uid;
char *pwd;
char *host;
};
#define PUSH_STATE(state) yy_push_state(state, yyscanner)
#define POP_STATE() yy_pop_state(yyscanner)
......@@ -61,17 +52,32 @@ do { \
yyextra->pwd = strdup(yytext); \
break; \
} \
if (strcasecmp(yyextra->key, "DB")==0) { \
free(yyextra->db); \
yyextra->pwd = strdup(yytext); \
break; \
} \
if (strcasecmp(yyextra->key, "HOST")==0) { \
free(yyextra->host); \
yyextra->host = strdup(yytext); \
break; \
} \
if (strcasecmp(yyextra->key, "SERVER_ENC")==0) { \
free(yyextra->svr_enc); \
yyextra->host = strdup(yytext); \
break; \
} \
if (strcasecmp(yyextra->key, "CLIENT_ENC")==0) { \
free(yyextra->cli_enc); \
yyextra->host = strdup(yytext); \
break; \
} \
} while (0)
%}
%option prefix="todbc_yy"
%option extra-type="struct params_s *"
%option extra-type="conn_val_t *"
%option nounistd
%option never-interactive
%option reentrant
......@@ -115,20 +121,45 @@ do { \
<VAL>.|\n { return -1; }
%%
int todbc_parse_conn_string(const char *conn, char **dsn, char **uid, char **pwd, char **host) {
int todbc_parse_conn_string(const char *conn, conn_val_t *val) {
yyscan_t arg = {0};
params_t params = {0};
yylex_init(&arg);
yyset_debug(0, arg);
yyset_extra(&params, arg);
yyset_extra(val, arg);
yy_scan_string(conn, arg);
int ret =yylex(arg);
yylex_destroy(arg);
*dsn = params.dsn;
*uid = params.uid;
*pwd = params.pwd;
*host = params.host;
if (val->key) free(val->key); val->key = NULL;
if (ret) {
conn_val_reset(val);
}
return ret ? -1 : 0;
}
void conn_val_reset(conn_val_t *val) {
if (val->key) {
free(val->key); val->key = NULL;
}
if (val->dsn) {
free(val->dsn); val->dsn = NULL;
}
if (val->uid) {
free(val->uid); val->uid = NULL;
}
if (val->pwd) {
free(val->pwd); val->pwd = NULL;
}
if (val->db) {
free(val->db); val->db = NULL;
}
if (val->host) {
free(val->host); val->host = NULL;
}
if (val->svr_enc) {
free(val->svr_enc); val->svr_enc = NULL;
}
if (val->cli_enc) {
free(val->cli_enc); val->cli_enc = NULL;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册