未验证 提交 7a77d047 编写于 作者: S Shengliang Guan 提交者: GitHub

Merge pull request #3765 from freemine/odbc

add odbc connector
......@@ -32,6 +32,8 @@ matrix:
- python3-setuptools
- valgrind
- psmisc
- unixodbc
- unixodbc-dev
before_script:
- export TZ=Asia/Harbin
......
......@@ -20,4 +20,6 @@ ADD_SUBDIRECTORY(tsdb)
ADD_SUBDIRECTORY(wal)
ADD_SUBDIRECTORY(cq)
ADD_SUBDIRECTORY(dnode)
ADD_SUBDIRECTORY(connector/odbc)
ADD_SUBDIRECTORY(connector/jdbc)
......@@ -139,7 +139,7 @@ static int normalStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
}
return TSDB_CODE_SUCCESS;
}
......@@ -213,7 +213,7 @@ static char* normalStmtBuildSql(STscStmt* stmt) {
case TSDB_DATA_TYPE_NULL:
taosStringBuilderAppendNull(&sb);
break;
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT:
......@@ -266,6 +266,388 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
return TSDB_CODE_SUCCESS;
}
if (1) {
// allow user bind param data with different type
short size = 0;
union {
int8_t v1;
int16_t v2;
int32_t v4;
int64_t v8;
float f4;
double f8;
unsigned char buf[32*1024];
} u;
switch (param->type) {
case TSDB_DATA_TYPE_BOOL: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL: {
u.v1 = *(int8_t*)bind->buffer;
if (u.v1==0 || u.v1==1) break;
} break;
case TSDB_DATA_TYPE_TINYINT: {
u.v1 = *(int8_t*)bind->buffer;
if (u.v1==0 || u.v1==1) break;
} break;
case TSDB_DATA_TYPE_SMALLINT: {
u.v1 = (int8_t)*(int16_t*)bind->buffer;
if (u.v1==0 || u.v1==1) break;
} break;
case TSDB_DATA_TYPE_INT: {
u.v1 = (int8_t)*(int32_t*)bind->buffer;
if (u.v1==0 || u.v1==1) break;
} break;
case TSDB_DATA_TYPE_BIGINT: {
u.v1 = (int8_t)*(int64_t*)bind->buffer;
if (u.v1==0 || u.v1==1) break;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
// "0", "1" convertible
if (strncmp((const char*)bind->buffer, "0", *bind->length)==0) {
u.v1 = 0;
break;
}
if (strncmp((const char*)bind->buffer, "1", *bind->length)==0) {
u.v1 = 1;
break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
memcpy(data + param->offset, &u.v1, sizeof(u.v1));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_TINYINT: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT: {
int8_t v = *(int8_t*)bind->buffer;
u.v1 = v;
if (v >= SCHAR_MIN && v <= SCHAR_MAX) break;
} break;
case TSDB_DATA_TYPE_SMALLINT: {
int16_t v = *(int16_t*)bind->buffer;
u.v1 = (int8_t)v;
if (v >= SCHAR_MIN && v <= SCHAR_MAX) break;
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_INT: {
int32_t v = *(int32_t*)bind->buffer;
u.v1 = (int8_t)v;
if (v >= SCHAR_MIN && v <= SCHAR_MAX) break;
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_BIGINT: {
int64_t v = *(int64_t*)bind->buffer;
u.v1 = (int8_t)v;
if (v >= SCHAR_MIN && v <= SCHAR_MAX) break;
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
int64_t v;
int n,r;
r = sscanf((const char*)bind->buffer, "%" PRId64 "%n", &v, &n);
if (r==1 && n==strlen((const char*)bind->buffer)) {
u.v1 = (int8_t)v;
if (v >= SCHAR_MIN && v <= SCHAR_MAX) break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
memcpy(data + param->offset, &u.v1, sizeof(u.v1));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_SMALLINT: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT: {
int v = *(int16_t*)bind->buffer;
u.v2 = (int16_t)v;
} break;
case TSDB_DATA_TYPE_INT: {
int32_t v = *(int32_t*)bind->buffer;
u.v2 = (int16_t)v;
if (v >= SHRT_MIN && v <= SHRT_MAX) break;
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_BIGINT: {
int64_t v = *(int64_t*)bind->buffer;
u.v2 = (int16_t)v;
if (v >= SHRT_MIN && v <= SHRT_MAX) break;
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
int64_t v;
int n,r;
r = sscanf((const char*)bind->buffer, "%" PRId64 "%n", &v, &n);
if (r==1 && n==strlen((const char*)bind->buffer)) {
u.v2 = (int16_t)v;
if (v >= SHRT_MIN && v <= SHRT_MAX) break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
memcpy(data + param->offset, &u.v2, sizeof(u.v2));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_INT: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT:
case TSDB_DATA_TYPE_INT: {
u.v4 = *(int32_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_BIGINT: {
int64_t v = *(int64_t*)bind->buffer;
u.v4 = (int32_t)v;
if (v >= INT_MIN && v <= INT_MAX) break;
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
int64_t v;
int n,r;
r = sscanf((const char*)bind->buffer, "%" PRId64 "%n", &v, &n);
if (r==1 && n==strlen((const char*)bind->buffer)) {
u.v4 = (int32_t)v;
if (v >= INT_MIN && v <= INT_MAX) break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
memcpy(data + param->offset, &u.v2, sizeof(u.v2));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_FLOAT: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT: {
u.f4 = *(int8_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_SMALLINT: {
u.f4 = *(int16_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_INT: {
u.f4 = (float)*(int32_t*)bind->buffer;
// shall we check equality?
} break;
case TSDB_DATA_TYPE_BIGINT: {
u.f4 = (float)*(int64_t*)bind->buffer;
// shall we check equality?
} break;
case TSDB_DATA_TYPE_FLOAT: {
u.f4 = *(float*)bind->buffer;
} break;
case TSDB_DATA_TYPE_DOUBLE: {
u.f4 = *(float*)bind->buffer;
// shall we check equality?
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
float v;
int n,r;
r = sscanf((const char*)bind->buffer, "%f%n", &v, &n);
if (r==1 && n==strlen((const char*)bind->buffer)) {
u.f4 = v;
break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
memcpy(data + param->offset, &u.f4, sizeof(u.f4));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_BIGINT: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT: {
u.v8 = *(int8_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_SMALLINT: {
u.v8 = *(int16_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_INT: {
u.v8 = *(int32_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_BIGINT: {
u.v8 = *(int64_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
int64_t v;
int n,r;
r = sscanf((const char*)bind->buffer, "%" PRId64 "%n", &v, &n);
if (r==1 && n==strlen((const char*)bind->buffer)) {
u.v8 = v;
break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
memcpy(data + param->offset, &u.v8, sizeof(u.v8));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_DOUBLE: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT: {
u.f8 = *(int8_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_SMALLINT: {
u.f8 = *(int16_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_INT: {
u.f8 = *(int32_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_BIGINT: {
u.f8 = (double)*(int64_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_FLOAT: {
u.f8 = *(float*)bind->buffer;
} break;
case TSDB_DATA_TYPE_DOUBLE: {
u.f8 = *(double*)bind->buffer;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
double v;
int n,r;
r = sscanf((const char*)bind->buffer, "%lf%n", &v, &n);
if (r==1 && n==strlen((const char*)bind->buffer)) {
u.f8 = v;
break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_TIMESTAMP:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
} break;
memcpy(data + param->offset, &u.f8, sizeof(u.f8));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_TIMESTAMP: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_TIMESTAMP: {
u.v8 = *(int64_t*)bind->buffer;
} break;
case TSDB_DATA_TYPE_BINARY:
case TSDB_DATA_TYPE_NCHAR: {
// is this the correct way to call taosParseTime?
int32_t len = (int32_t)*bind->length;
if (taosParseTime(bind->buffer, &u.v8, len, 3, tsDaylight) == TSDB_CODE_SUCCESS) {
break;
}
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT:
case TSDB_DATA_TYPE_INT:
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_BIGINT:
case TSDB_DATA_TYPE_DOUBLE:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
} break;
memcpy(data + param->offset, &u.v8, sizeof(u.v8));
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_BINARY: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_BINARY: {
if ((*bind->length) > (uintptr_t)param->bytes) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
size = (short)*bind->length;
STR_WITH_SIZE_TO_VARSTR(data + param->offset, bind->buffer, size);
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT:
case TSDB_DATA_TYPE_INT:
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_BIGINT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
case TSDB_DATA_TYPE_NCHAR:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
} break;
case TSDB_DATA_TYPE_NCHAR: {
switch (bind->buffer_type) {
case TSDB_DATA_TYPE_NCHAR: {
size_t output = 0;
if (!taosMbsToUcs4(bind->buffer, *bind->length, varDataVal(data + param->offset), param->bytes - VARSTR_HEADER_SIZE, &output)) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
varDataSetLen(data + param->offset, output);
return TSDB_CODE_SUCCESS;
} break;
case TSDB_DATA_TYPE_BOOL:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT:
case TSDB_DATA_TYPE_INT:
case TSDB_DATA_TYPE_FLOAT:
case TSDB_DATA_TYPE_BIGINT:
case TSDB_DATA_TYPE_DOUBLE:
case TSDB_DATA_TYPE_TIMESTAMP:
case TSDB_DATA_TYPE_BINARY:
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
} break;
default: {
return TSDB_CODE_TSC_INVALID_VALUE;
} break;
}
}
if (bind->buffer_type != param->type) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
......@@ -299,12 +681,12 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
size = (short)*bind->length;
STR_WITH_SIZE_TO_VARSTR(data + param->offset, bind->buffer, size);
return TSDB_CODE_SUCCESS;
case TSDB_DATA_TYPE_NCHAR: {
size_t output = 0;
if (!taosMbsToUcs4(bind->buffer, *bind->length, varDataVal(data + param->offset), param->bytes - VARSTR_HEADER_SIZE, &output)) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
}
varDataSetLen(data + param->offset, output);
return TSDB_CODE_SUCCESS;
}
......@@ -358,7 +740,7 @@ static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
}
// actual work of all data blocks is done, update block size and numOfRows.
// note we don't do this block by block during the binding process, because
// note we don't do this block by block during the binding process, because
// we cannot recover if something goes wrong.
pCmd->batchSize = binded * 2 + 1;
......@@ -405,7 +787,7 @@ static int insertStmtReset(STscStmt* pStmt) {
}
}
pCmd->batchSize = 0;
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
pTableMetaInfo->vgroupIndex = 0;
return TSDB_CODE_SUCCESS;
......@@ -447,7 +829,7 @@ static int insertStmtExecute(STscStmt* stmt) {
pRes->numOfRows = 0;
pRes->numOfTotal = 0;
pRes->numOfClauseTotal = 0;
pRes->qhandle = 0;
pSql->cmd.insertType = 0;
......@@ -508,35 +890,35 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
SSqlObj* pSql = pStmt->pSql;
size_t sqlLen = strlen(sql);
SSqlCmd *pCmd = &pSql->cmd;
SSqlRes *pRes = &pSql->res;
pSql->param = (void*) pSql;
pSql->fp = waitForQueryRsp;
pSql->cmd.insertType = TSDB_QUERY_TYPE_STMT_INSERT;
if (TSDB_CODE_SUCCESS != tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE)) {
tscError("%p failed to malloc payload buffer", pSql);
return TSDB_CODE_TSC_OUT_OF_MEMORY;
}
pSql->sqlstr = realloc(pSql->sqlstr, sqlLen + 1);
if (pSql->sqlstr == NULL) {
tscError("%p failed to malloc sql string buffer", pSql);
free(pCmd->payload);
return TSDB_CODE_TSC_OUT_OF_MEMORY;
}
pRes->qhandle = 0;
pRes->numOfRows = 1;
strtolower(pSql->sqlstr, sql);
tscDebugL("%p SQL: %s", pSql, pSql->sqlstr);
if (tscIsInsertData(pSql->sqlstr)) {
if (tscIsInsertData(pSql->sqlstr)) {
pStmt->isInsert = true;
pSql->cmd.numOfParams = 0;
pSql->cmd.batchSize = 0;
......@@ -548,7 +930,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
tsem_wait(&pSql->rspSem);
return pSql->res.code;
}
return code;
}
......@@ -637,3 +1019,80 @@ TAOS_RES *taos_stmt_use_result(TAOS_STMT* stmt) {
pStmt->pSql = NULL;
return result;
}
int taos_stmt_is_insert(TAOS_STMT *stmt, int *insert) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->taos == NULL || pStmt->pSql == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (insert) *insert = pStmt->isInsert;
return TSDB_CODE_SUCCESS;
}
int taos_stmt_num_params(TAOS_STMT *stmt, int *nums) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->taos == NULL || pStmt->pSql == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (pStmt->isInsert) {
SSqlObj* pSql = pStmt->pSql;
SSqlCmd *pCmd = &pSql->cmd;
*nums = pCmd->numOfParams;
return TSDB_CODE_SUCCESS;
} else {
SNormalStmt* normal = &pStmt->normal;
*nums = normal->numParams;
return TSDB_CODE_SUCCESS;
}
}
int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->taos == NULL || pStmt->pSql == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (pStmt->isInsert) {
SSqlObj* pSql = pStmt->pSql;
SSqlCmd *pCmd = &pSql->cmd;
STableDataBlocks* pBlock = taosArrayGetP(pCmd->pDataBlocks, 0);
assert(pCmd->numOfParams == pBlock->numOfParams);
if (idx < 0 || idx >= pBlock->numOfParams) return -1;
SParamInfo* param = pBlock->params + idx;
if (type) *type = param->type;
if (bytes) *bytes = param->bytes;
return TSDB_CODE_SUCCESS;
} else {
return TSDB_CODE_TSC_APP_ERROR;
}
}
const char *taos_data_type(int type) {
switch (type) {
case TSDB_DATA_TYPE_NULL: return "TSDB_DATA_TYPE_NULL";
case TSDB_DATA_TYPE_BOOL: return "TSDB_DATA_TYPE_BOOL";
case TSDB_DATA_TYPE_TINYINT: return "TSDB_DATA_TYPE_TINYINT";
case TSDB_DATA_TYPE_SMALLINT: return "TSDB_DATA_TYPE_SMALLINT";
case TSDB_DATA_TYPE_INT: return "TSDB_DATA_TYPE_INT";
case TSDB_DATA_TYPE_BIGINT: return "TSDB_DATA_TYPE_BIGINT";
case TSDB_DATA_TYPE_FLOAT: return "TSDB_DATA_TYPE_FLOAT";
case TSDB_DATA_TYPE_DOUBLE: return "TSDB_DATA_TYPE_DOUBLE";
case TSDB_DATA_TYPE_BINARY: return "TSDB_DATA_TYPE_BINARY";
case TSDB_DATA_TYPE_TIMESTAMP: return "TSDB_DATA_TYPE_TIMESTAMP";
case TSDB_DATA_TYPE_NCHAR: return "TSDB_DATA_TYPE_NCHAR";
default: return "UNKNOWN";
}
}
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(TDengine)
IF (TD_LINUX_64)
find_program(HAVE_ODBCINST NAMES odbcinst)
IF (HAVE_ODBCINST)
include(CheckSymbolExists)
# shall we revert CMAKE_REQUIRED_LIBRARIES and how?
set(CMAKE_REQUIRED_LIBRARIES odbc)
check_symbol_exists(SQLExecute "sql.h" HAVE_ODBC_DEV)
if(NOT (HAVE_ODBC_DEV))
unset(HAVE_ODBC_DEV CACHE)
message(WARNING "unixodbc-dev is not installed yet, you may install it under ubuntu by typing: sudo apt install unixodbc-dev")
else ()
message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built")
AUX_SOURCE_DIRECTORY(src SRC)
# generate dynamic library (*.so)
ADD_LIBRARY(todbc SHARED ${SRC})
SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1)
TARGET_LINK_LIBRARIES(todbc taos)
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/install.sh ${CMAKE_BINARY_DIR})")
ADD_SUBDIRECTORY(tests)
endif()
ELSE ()
message(WARNING "unixodbc is not installed yet, you may install it under ubuntu by typing: sudo apt install unixodbc")
ENDIF ()
ENDIF ()
#!/bin/bash
set -u
BLD_DIR="$1"
rm -f "${BLD_DIR}/template.ini"
rm -f "${BLD_DIR}/template.dsn"
cat > "${BLD_DIR}/template.ini" <<EOF
[TAOS]
Description = taos odbc driver
Driver = ${BLD_DIR}/build/lib/libtodbc.so
EOF
cat > "${BLD_DIR}/template.dsn" <<EOF
[TAOS_DSN]
Description=Connection to TAOS
Driver=TAOS
EOF
sudo odbcinst -i -d -f "${BLD_DIR}/template.ini" &&
odbcinst -i -s -f "${BLD_DIR}/template.dsn" &&
echo "odbc install done"
此差异已折叠。
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "todbc_util.h"
#include "iconv.h"
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
#include <stdlib.h>
#include <string.h>
const char* sql_sql_type(int type) {
switch (type) {
case SQL_BIT: return "SQL_BIT";
case SQL_TINYINT: return "SQL_TINYINT";
case SQL_SMALLINT: return "SQL_SMALLINT";
case SQL_INTEGER: return "SQL_INTEGER";
case SQL_BIGINT: return "SQL_BIGINT";
case SQL_FLOAT: return "SQL_FLOAT";
case SQL_DOUBLE: return "SQL_DOUBLE";
case SQL_DECIMAL: return "SQL_DECIMAL";
case SQL_NUMERIC: return "SQL_NUMERIC";
case SQL_REAL: return "SQL_REAL";
case SQL_CHAR: return "SQL_CHAR";
case SQL_VARCHAR: return "SQL_VARCHAR";
case SQL_LONGVARCHAR: return "SQL_LONGVARCHAR";
case SQL_WCHAR: return "SQL_WCHAR";
case SQL_WVARCHAR: return "SQL_WVARCHAR";
case SQL_WLONGVARCHAR: return "SQL_WLONGVARCHAR";
case SQL_BINARY: return "SQL_BINARY";
case SQL_VARBINARY: return "SQL_VARBINARY";
case SQL_LONGVARBINARY: return "SQL_LONGVARBINARY";
case SQL_DATE: return "SQL_DATE";
case SQL_TIME: return "SQL_TIME";
case SQL_TIMESTAMP: return "SQL_TIMESTAMP";
case SQL_TYPE_DATE: return "SQL_TYPE_DATE";
case SQL_TYPE_TIME: return "SQL_TYPE_TIME";
case SQL_TYPE_TIMESTAMP: return "SQL_TYPE_TIMESTAMP";
case SQL_INTERVAL_MONTH: return "SQL_INTERVAL_MONTH";
case SQL_INTERVAL_YEAR: return "SQL_INTERVAL_YEAR";
case SQL_INTERVAL_YEAR_TO_MONTH: return "SQL_INTERVAL_YEAR_TO_MONTH";
case SQL_INTERVAL_DAY: return "SQL_INTERVAL_DAY";
case SQL_INTERVAL_HOUR: return "SQL_INTERVAL_HOUR";
case SQL_INTERVAL_MINUTE: return "SQL_INTERVAL_MINUTE";
case SQL_INTERVAL_SECOND: return "SQL_INTERVAL_SECOND";
case SQL_INTERVAL_DAY_TO_HOUR: return "SQL_INTERVAL_DAY_TO_HOUR";
case SQL_INTERVAL_DAY_TO_MINUTE: return "SQL_INTERVAL_DAY_TO_MINUTE";
case SQL_INTERVAL_DAY_TO_SECOND: return "SQL_INTERVAL_DAY_TO_SECOND";
case SQL_INTERVAL_HOUR_TO_MINUTE: return "SQL_INTERVAL_HOUR_TO_MINUTE";
case SQL_INTERVAL_HOUR_TO_SECOND: return "SQL_INTERVAL_HOUR_TO_SECOND";
case SQL_INTERVAL_MINUTE_TO_SECOND: return "SQL_INTERVAL_MINUTE_TO_SECOND";
case SQL_GUID: return "SQL_GUID";
default: return "UNKNOWN";
}
}
const char* sql_c_type(int type) {
switch (type) {
case SQL_C_CHAR: return "SQL_C_CHAR";
case SQL_C_WCHAR: return "SQL_C_WCHAR";
case SQL_C_SHORT: return "SQL_C_SHORT";
case SQL_C_SSHORT: return "SQL_C_SSHORT";
case SQL_C_USHORT: return "SQL_C_USHORT";
case SQL_C_LONG: return "SQL_C_LONG";
case SQL_C_SLONG: return "SQL_C_SLONG";
case SQL_C_ULONG: return "SQL_C_ULONG";
case SQL_C_FLOAT: return "SQL_C_FLOAT";
case SQL_C_DOUBLE: return "SQL_C_DOUBLE";
case SQL_C_BIT: return "SQL_C_BIT";
case SQL_C_TINYINT: return "SQL_C_TINYINT";
case SQL_C_STINYINT: return "SQL_C_STINYINT";
case SQL_C_UTINYINT: return "SQL_C_UTINYINT";
case SQL_C_SBIGINT: return "SQL_C_SBIGINT";
case SQL_C_UBIGINT: return "SQL_C_UBIGINT";
case SQL_C_BINARY: return "SQL_C_BINARY";
case SQL_C_DATE: return "SQL_C_DATE";
case SQL_C_TIME: return "SQL_C_TIME";
case SQL_C_TIMESTAMP: return "SQL_C_TIMESTAMP";
case SQL_C_TYPE_DATE: return "SQL_C_TYPE_DATE";
case SQL_C_TYPE_TIME: return "SQL_C_TYPE_TIME";
case SQL_C_TYPE_TIMESTAMP: return "SQL_C_TYPE_TIMESTAMP";
case SQL_C_NUMERIC: return "SQL_C_NUMERIC";
case SQL_C_GUID: return "SQL_C_GUID";
default: return "UNKNOWN";
}
}
int is_valid_sql_c_type(int type) {
const char *ctype = sql_c_type(type);
if (strcmp(ctype, "UNKNOWN")==0) return 0;
return 1;
}
int is_valid_sql_sql_type(int type) {
const char *sqltype = sql_sql_type(type);
if (strcmp(sqltype, "UNKNOWN")==0) return 0;
return 1;
}
int string_conv(const char *fromcode, const char *tocode,
const unsigned char *src, size_t sbytes,
unsigned char *dst, size_t dbytes,
size_t *consumed, size_t *generated)
{
if (consumed) *consumed = 0;
if (generated) *generated = 0;
if (dbytes <= 0) return -1;
dst[0] = '\0';
iconv_t conv = iconv_open(tocode, fromcode);
if (!conv) return -1;
int r = 0;
do {
char *s = (char*)src;
char *d = (char*)dst;
size_t sl = sbytes;
size_t dl = dbytes;
r = iconv(conv, &s, &sl, &d, &dl);
*d = '\0';
if (consumed) *consumed = sbytes - sl;
if (generated) *generated = dbytes - dl;
} while (0);
iconv_close(conv);
return r;
}
int utf8_chars(const char *src)
{
const char *fromcode = "UTF-8";
const char *tocode = "UCS-2LE";
iconv_t conv = iconv_open(tocode, fromcode);
if (!conv) return -1;
size_t slen = strlen(src);
char buf[4096];
size_t dlen = sizeof(buf);
char *ps = (char*)src;
char *pd = buf;
iconv(conv, &ps, &slen, &pd, &dlen);
DASSERT(slen==0);
size_t chars = (sizeof(buf) - dlen) / 2;
iconv_close(conv);
return chars;
}
unsigned char* utf8_to_ucs4le(const char *utf8, size_t *chars)
{
const char *tocode = "UCS-4LE";
const char *fromcode = "UTF-8";
iconv_t conv = iconv_open(tocode, fromcode);
if (!conv) return NULL;
unsigned char *ucs4le = NULL;
do {
size_t slen = strlen(utf8);
size_t dlen = slen * 4;
ucs4le = (unsigned char*)malloc(dlen+1);
if (!ucs4le) break;
char *src = (char*)utf8;
char *dst = (char*)ucs4le;
size_t s = slen;
size_t d = dlen;
iconv(conv, &src, &s, &dst, &d);
dst[0] = '\0';
if (chars) *chars = (dlen - d) / 4;
} while (0);
iconv_close(conv);
return ucs4le;
}
char* ucs4le_to_utf8(const unsigned char *ucs4le, size_t slen, size_t *chars)
{
const char *fromcode = "UCS-4LE";
const char *tocode = "UTF-8";
iconv_t conv = iconv_open(tocode, fromcode);
if (!conv) return NULL;
char *utf8 = NULL;
do {
size_t dlen = slen;
utf8 = (char*)malloc(dlen+1);
if (!utf8) break;
char *dst = utf8;
char *src = (char*)ucs4le;
size_t s = slen;
size_t d = dlen;
iconv(conv, &src, &s, &dst, &d);
dst[0] = '\0';
if (chars) *chars = (slen - s) / 4;
} while (0);
iconv_close(conv);
return utf8;
}
SQLCHAR* wchars_to_chars(const SQLWCHAR *wchars, size_t chs, size_t *bytes)
{
size_t dlen = chs * 4;
SQLCHAR *dst = (SQLCHAR*)malloc(dlen + 1);
if (!dst) return NULL;
string_conv("UCS-2LE", "UTF-8", (const unsigned char*)wchars, chs * sizeof(*wchars), dst, dlen + 1, NULL, bytes);
return dst;
}
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _TODBC_UTIL_H_
#define _TODBC_UTIL_H_
#include <libgen.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#define D(fmt, ...) \
fprintf(stderr, \
"%s[%d]:%s() " fmt "\n", \
basename((char*)__FILE__), __LINE__, __func__, \
##__VA_ARGS__)
#define DASSERT(statement) \
do { \
if (statement) break; \
D("Assertion failure: %s", #statement); \
abort(); \
} while (0)
#define DASSERTX(statement, fmt, ...) \
do { \
if (statement) break; \
D("Assertion failure: %s, " fmt "", #statement, ##__VA_ARGS__); \
abort(); \
} while (0)
const char* sql_sql_type(int type);
const char* sql_c_type(int type);
int is_valid_sql_c_type(int type);
int is_valid_sql_sql_type(int type);
int string_conv(const char *fromcode, const char *tocode,
const unsigned char *src, size_t sbytes,
unsigned char *dst, size_t dbytes,
size_t *consumed, size_t *generated);
int utf8_chars(const char *src);
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);
#endif // _TODBC_UTIL_H_
PROJECT(TDengine)
IF (TD_LINUX)
AUX_SOURCE_DIRECTORY(. SRC)
ADD_EXECUTABLE(tcodbc main.c)
TARGET_LINK_LIBRARIES(tcodbc odbc)
ENDIF ()
#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <string.h>
#include "os.h"
// static const char *dsn = "TAOS_DSN";
// static const char *uid = "root";
// static const char *pwd = "taosdata";
typedef struct data_s data_t;
struct data_s {
int64_t ts;
int8_t b;
int8_t v1;
int16_t v2;
int32_t v4;
int64_t v8;
float f4;
double f8;
char bin[40+1];
char blob[40+1]; // why 80? ref: tests/examples/c/apitest.c
};
static const char *pre_stmts[] = {
"create database db",
"use db",
"create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(40), blob nchar(10))"
};
static const char *pro_stmts[] = {
// "insert into t values ('2019-07-15 00:00:00', 1)",
// "insert into t values ('2019-07-15 01:00:00', 2)",
"select * from t"
// "drop database db"
};
#define CHK_RESULT(r, ht, h) \
do { \
if (r==0) break; \
SQLCHAR ss[10]; \
SQLINTEGER ne = 0; \
SQLCHAR es[4096]; \
SQLSMALLINT n = 0; \
ss[0] = '\0'; \
es[0] = '\0'; \
SQLRETURN ret = SQLGetDiagRec(ht, h, 1, ss, &ne, es, sizeof(es), &n); \
if (ret) break; \
fprintf(stderr, "%s%s\n", ss, es); \
} while (0)
static int do_statement(SQLHSTMT stmt, const char *statement) {
SQLRETURN r = 0;
do {
fprintf(stderr, "prepare [%s]\n", statement);
r = SQLPrepare(stmt, (SQLCHAR*)statement, strlen(statement));
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "execute [%s]\n", statement);
r = SQLExecute(stmt);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "done\n");
} while (0);
fprintf(stderr, "r: [%x][%d]\n", r, r);
return r;
}
static int do_insert(SQLHSTMT stmt, data_t data) {
SQLRETURN r = 0;
SQLLEN lbin;
SQLLEN lblob;
const char *statement = "insert into t values (?, ?, ?, ?, ?, ?, ?, ?, ?,?)";
int ignored = 0;
do {
fprintf(stderr, "prepare [%s]\n", statement);
r = SQLPrepare(stmt, (SQLCHAR*)statement, strlen(statement));
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 1 [%s]\n", statement);
r = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_TIMESTAMP, ignored, ignored, &data.ts, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 2 [%s]\n", statement);
r = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, ignored, ignored, &data.b, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 3 [%s]\n", statement);
r = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_TINYINT, SQL_TINYINT, ignored, ignored, &data.v1, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 4 [%s]\n", statement);
r = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, ignored, ignored, &data.v2, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 5 [%s]\n", statement);
r = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, ignored, ignored, &data.v4, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 6 [%s]\n", statement);
r = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, ignored, ignored, &data.v8, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 7 [%s]\n", statement);
r = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, ignored, ignored, &data.f4, ignored, NULL);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 8 [%s]\n", statement);
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;
fprintf(stderr, "bind 9 [%s]\n", statement);
lbin = SQL_NTS;
r = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sizeof(data.bin)-1, ignored, &data.bin, ignored, &lbin);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "bind 10 [%s]\n", statement);
lblob = SQL_NTS;
r = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(data.blob)-1, ignored, &data.blob, ignored, &lblob);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
fprintf(stderr, "execute [%s]\n", statement);
r = SQLExecute(stmt);
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
if (r) break;
// ts += 1;
// v = 2;
// fprintf(stderr, "execute [%s]\n", statement);
// r = SQLExecute(stmt);
// if (r) break;
fprintf(stderr, "done\n");
} while (0);
fprintf(stderr, "r: [%x][%d]\n", r, r);
return r;
}
int main(int argc, char *argv[]) {
if (argc < 4) return 1;
const char *dsn = argv[1];
const char *uid = argv[2];
const char *pwd = argv[3];
SQLRETURN r;
SQLHENV env = {0};
SQLHDBC conn = {0};
r = SQLAllocEnv(&env);
if (r!=SQL_SUCCESS) return 1;
do {
r = SQLAllocConnect(env, &conn);
CHK_RESULT(r, SQL_HANDLE_ENV, env);
if (r!=SQL_SUCCESS) break;
do {
r = SQLConnect(conn, (SQLCHAR*)dsn, strlen(dsn),
(SQLCHAR*)uid, strlen(uid),
(SQLCHAR*)pwd, strlen(pwd));
CHK_RESULT(r, SQL_HANDLE_DBC, conn);
if (r!=SQL_SUCCESS) break;
do {
SQLHSTMT stmt = {0};
r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
if (r!=SQL_SUCCESS) break;
do {
do_statement(stmt, "drop database db");
for (size_t i=0; i<sizeof(pre_stmts)/sizeof(pre_stmts[0]); ++i) {
r = do_statement(stmt, pre_stmts[i]);
if (r!=SQL_SUCCESS) break;
}
do {
data_t data = {0};
data.ts = 1591060628001;
data.b = 1;
data.v1 = 127;
data.v2 = 32767;
data.v4 = 2147483647;
data.v8 = 9223372036854775807;
data.f4 = 123.456;
data.f8 = 9999999.999999;
memset(data.bin, 0, sizeof(data.bin));
memset(data.blob, 0, sizeof(data.blob));
snprintf(data.bin, sizeof(data.bin), "hel我lo");
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;
do {
r = do_insert(stmt, data);
if (r!=SQL_SUCCESS) break;
} while (0);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
// r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
// if (r!=SQL_SUCCESS) break;
// do {
// r = do_insert(stmt, ts++, v++);
// if (r!=SQL_SUCCESS) break;
// } while (0);
// SQLFreeHandle(SQL_HANDLE_STMT, stmt);
} while (0);
if (r!=SQL_SUCCESS) break;
for (size_t i=0; i<sizeof(pro_stmts)/sizeof(pro_stmts[0]); ++i) {
r = do_statement(stmt, pro_stmts[i]);
if (r!=SQL_SUCCESS) break;
}
} while (0);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
} while (0);
SQLDisconnect(conn);
} while (0);
SQLFreeConnect(conn);
} while (0);
SQLFreeEnv(env);
return r ? 1 : 0;
}
import pyodbc
cnxn = pyodbc.connect('DSN=TAOS_DSN;UID=root;PWD=taosdata', autocommit=True)
cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8')
#cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8')
#cnxn.setencoding(encoding='utf-8')
cursor = cnxn.cursor()
cursor.execute("SELECT * from db.t")
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cursor.close()
#cursor = cnxn.cursor()
#cursor.execute("""
#INSERT INTO db.t values (?,?,?,?,?,?,?,?,?,?)
#""",
#"2020-12-12 00:00:00",
#1,
#27,
#32767,
#147483647,
#223372036854775807,
#23.456,
#899.999999,
#"foo",
#"bar")
cursor = cnxn.cursor()
cursor.execute("drop database if exists db");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("create database db");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(40), blob nchar(10))");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("insert into db.t values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hello', 'world')")
cursor.close()
cursor = cnxn.cursor()
cursor.execute("insert into db.t values(?,?,?,?,?,?,?,?,?,?)", "2020-10-13 07:06:00", 0, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo", "wo哈rld");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("SELECT * from db.t")
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cursor.close()
cursor = cnxn.cursor()
cursor.execute("drop database if exists db");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("create database db");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(4), blob nchar(4))");
cursor.close()
cursor = cnxn.cursor()
cursor.execute("insert into db.t values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hell', 'worl')")
cursor.close()
cursor = cnxn.cursor()
cursor.execute("SELECT * from db.t")
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cursor.close()
cursor = cnxn.cursor()
cursor.execute("create table db.v (ts timestamp, v1 tinyint)")
cursor.close()
params = [ ('A', 1), ('B', 2), ('C', 3) ]
params = [ ('A', 1), ('B', 2), ('C', 3) ]
params = [ ('2020-10-16 00:00:00', 1),
('2020-10-16 00:00:01', 4),
('2020-10-16 00:00:02', 5),
('2020-10-16 00:00:03.009', 6) ]
cursor = cnxn.cursor()
cursor.fast_executemany = True
cursor.executemany("insert into db.v values (?, ?)", params)
cursor.close()
cursor = cnxn.cursor()
cursor.execute("SELECT * from db.v")
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cursor.close()
cursor = cnxn.cursor()
cursor.execute("SELECT * from db.v where v1 > ?", 4)
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cursor.close()
cursor = cnxn.cursor()
cursor.execute("SELECT * from db.v where v1 > ?", '5')
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cursor.close()
......@@ -69,6 +69,8 @@ DLL_EXPORT int taos_options(TSDB_OPTION option, const void *arg, ...);
DLL_EXPORT TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port);
DLL_EXPORT void taos_close(TAOS *taos);
const char *taos_data_type(int type);
typedef struct TAOS_BIND {
int buffer_type;
void * buffer;
......@@ -77,10 +79,26 @@ typedef struct TAOS_BIND {
int * is_null;
int is_unsigned; // unused
int * error; // unused
union {
int64_t ts;
int8_t b;
int8_t v1;
int16_t v2;
int32_t v4;
int64_t v8;
float f4;
double f8;
unsigned char *bin;
char *nchar;
} u;
unsigned int allocated;
} TAOS_BIND;
TAOS_STMT *taos_stmt_init(TAOS *taos);
int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length);
int taos_stmt_is_insert(TAOS_STMT *stmt, int *insert);
int taos_stmt_num_params(TAOS_STMT *stmt, int *nums);
int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes);
int taos_stmt_bind_param(TAOS_STMT *stmt, TAOS_BIND *bind);
int taos_stmt_add_batch(TAOS_STMT *stmt);
int taos_stmt_execute(TAOS_STMT *stmt);
......
......@@ -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
......@@ -182,7 +182,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")
......@@ -354,6 +354,23 @@ 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")
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")
#ifdef TAOS_ERROR_C
};
#endif
......
......@@ -27,7 +27,7 @@ extern "C" {
#define FD_VALID(x) ((x) > STDERR_FILENO)
#define FD_INITIALIZER ((int32_t)-1)
#define WCHAR wchar_t
// #define WCHAR wchar_t
#define POINTER_SHIFT(p, b) ((void *)((char *)(p) + (b)))
#define POINTER_DISTANCE(p1, p2) ((char *)(p1) - (char *)(p2))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册