init odbc
This commit is contained in:
parent
c522e902fa
commit
52f023c028
|
@ -20,4 +20,6 @@ ADD_SUBDIRECTORY(tsdb)
|
|||
ADD_SUBDIRECTORY(wal)
|
||||
ADD_SUBDIRECTORY(cq)
|
||||
ADD_SUBDIRECTORY(dnode)
|
||||
ADD_SUBDIRECTORY(connector/odbc)
|
||||
ADD_SUBDIRECTORY(connector/jdbc)
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
PROJECT(TDengine)
|
||||
|
||||
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 sudo odbcinst -i -d -f ${CMAKE_CURRENT_SOURCE_DIR}/src/template.ini
|
||||
COMMAND odbcinst -i -s -f ${CMAKE_CURRENT_SOURCE_DIR}/src/template.dsn
|
||||
COMMAND echo odbc install done)")
|
||||
|
||||
ADD_SUBDIRECTORY(tests)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
odbcinst -u -d -n TAOS &&
|
||||
odbcinst -i -d -f "$(dirname "$0")/template.ini" &&
|
||||
odbcinst -i -s -f "$(dirname "$0")/template.dsn" &&
|
||||
echo yes
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[TAOS_DSN]
|
||||
Description=Connection to TAOS
|
||||
Driver=TAOS
|
||||
Server=localhost:1234
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[TAOS]
|
||||
Description = taos odbc driver
|
||||
Driver = /home/xxh/Documents/TDengine/debug/build/lib/libtodbc.so
|
||||
|
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* 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 "taos.h"
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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 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)
|
||||
|
||||
#define LOCK(obj) pthread_mutex_lock(&obj->lock);
|
||||
#define UNLOCK(obj) pthread_mutex_unlock(&obj->lock);
|
||||
|
||||
|
||||
typedef struct env_s env_t;
|
||||
typedef struct conn_s conn_t;
|
||||
typedef struct sql_s sql_t;
|
||||
|
||||
|
||||
|
||||
struct env_s {
|
||||
unsigned int destroying:1;
|
||||
};
|
||||
|
||||
struct conn_s {
|
||||
env_t *env;
|
||||
|
||||
TAOS *taos;
|
||||
};
|
||||
|
||||
struct sql_s {
|
||||
conn_t *conn;
|
||||
|
||||
TAOS_RES *rs;
|
||||
TAOS_ROW row;
|
||||
};
|
||||
|
||||
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||
static void init_routine(void);
|
||||
|
||||
static int do_field_display_size(TAOS_FIELD *field);
|
||||
static void do_convert(SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrLen_or_Ind, TAOS_FIELD *field, void *row);
|
||||
|
||||
SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) {
|
||||
pthread_once(&init_once, init_routine);
|
||||
|
||||
env_t *env = (env_t*)calloc(1, sizeof(*env));
|
||||
if (!env) return SQL_ERROR;
|
||||
|
||||
*EnvironmentHandle = env;
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) {
|
||||
env_t *env = (env_t*)EnvironmentHandle;
|
||||
if (!env) return SQL_ERROR;
|
||||
|
||||
DASSERT(!env->destroying);
|
||||
|
||||
env->destroying = 1;
|
||||
DASSERT(env->destroying == 1);
|
||||
|
||||
free(env);
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle,
|
||||
SQLHDBC *ConnectionHandle) {
|
||||
env_t *env = (env_t*)EnvironmentHandle;
|
||||
if (!env) return SQL_ERROR;
|
||||
|
||||
conn_t *conn = NULL;
|
||||
do {
|
||||
conn = (conn_t*)calloc(1, sizeof(*conn));
|
||||
if (!conn) break;
|
||||
|
||||
conn->env = env;
|
||||
*ConnectionHandle = conn;
|
||||
} while (0);
|
||||
|
||||
return conn ? SQL_SUCCESS : SQL_ERROR;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) {
|
||||
conn_t *conn = (conn_t*)ConnectionHandle;
|
||||
if (!conn) return SQL_ERROR;
|
||||
|
||||
do {
|
||||
if (conn->taos) {
|
||||
taos_close(conn->taos);
|
||||
conn->taos = NULL;
|
||||
}
|
||||
conn->env = NULL;
|
||||
free(conn);
|
||||
} while (0);
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle,
|
||||
SQLCHAR *ServerName, SQLSMALLINT NameLength1,
|
||||
SQLCHAR *UserName, SQLSMALLINT NameLength2,
|
||||
SQLCHAR *Authentication, SQLSMALLINT NameLength3) {
|
||||
conn_t *conn = (conn_t*)ConnectionHandle;
|
||||
if (!conn) return SQL_ERROR;
|
||||
|
||||
if (conn->taos) return SQL_ERROR;
|
||||
|
||||
conn->taos = taos_connect("localhost", (const char*)UserName, (const char*)Authentication, NULL, 0);
|
||||
|
||||
return conn->taos ? SQL_SUCCESS : SQL_ERROR;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) {
|
||||
conn_t *conn = (conn_t*)ConnectionHandle;
|
||||
if (!conn) return SQL_ERROR;
|
||||
|
||||
if (conn->taos) {
|
||||
taos_close(conn->taos);
|
||||
conn->taos = NULL;
|
||||
}
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle,
|
||||
SQLHSTMT *StatementHandle) {
|
||||
conn_t *conn = (conn_t*)ConnectionHandle;
|
||||
if (!conn) return SQL_ERROR;
|
||||
|
||||
sql_t *sql = (sql_t*)calloc(1, sizeof(*sql));
|
||||
if (!sql) return SQL_ERROR;
|
||||
|
||||
sql->conn = conn;
|
||||
*StatementHandle = sql;
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle,
|
||||
SQLUSMALLINT Option) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
|
||||
if (sql->rs) {
|
||||
taos_free_result(sql->rs);
|
||||
sql->rs = NULL;
|
||||
}
|
||||
sql->conn = NULL;
|
||||
free(sql);
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle,
|
||||
SQLCHAR *StatementText, SQLINTEGER TextLength) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
if (!sql->conn) return SQL_ERROR;
|
||||
if (!sql->conn->taos) return SQL_ERROR;
|
||||
|
||||
if (sql->rs) {
|
||||
taos_free_result(sql->rs);
|
||||
sql->rs = NULL;
|
||||
sql->row = NULL;
|
||||
}
|
||||
sql->rs = taos_query(sql->conn->taos, (const char*)StatementText);
|
||||
if (sql->rs) {
|
||||
sql->row = taos_fetch_row(sql->rs);
|
||||
}
|
||||
|
||||
return sql->row ? SQL_SUCCESS : SQL_NO_DATA;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle,
|
||||
SQLSMALLINT *ColumnCount) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
if (!sql->conn) return SQL_ERROR;
|
||||
if (!sql->conn->taos) return SQL_ERROR;
|
||||
if (!sql->rs) return SQL_ERROR;
|
||||
|
||||
int fields = taos_field_count(sql->rs);
|
||||
if (ColumnCount) {
|
||||
*ColumnCount = fields;
|
||||
}
|
||||
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLRowCount(SQLHSTMT StatementHandle,
|
||||
SQLLEN *RowCount) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
if (!sql->conn) return SQL_ERROR;
|
||||
if (!sql->conn->taos) return SQL_ERROR;
|
||||
if (!sql->rs) return SQL_ERROR;
|
||||
int rows = taos_affected_rows(sql->rs);
|
||||
if (RowCount) {
|
||||
*RowCount = rows;
|
||||
}
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLColAttribute(SQLHSTMT StatementHandle,
|
||||
SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier,
|
||||
SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength,
|
||||
SQLSMALLINT *StringLength, SQLLEN *NumericAttribute ) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
if (!sql->conn) return SQL_ERROR;
|
||||
if (!sql->conn->taos) return SQL_ERROR;
|
||||
if (!sql->rs) return SQL_ERROR;
|
||||
int nfields = taos_field_count(sql->rs);
|
||||
TAOS_FIELD *fields = taos_fetch_fields(sql->rs);
|
||||
|
||||
if (nfields==0 || fields==NULL) return SQL_ERROR;
|
||||
if (ColumnNumber>nfields) return SQL_ERROR;
|
||||
|
||||
TAOS_FIELD *field = fields + ColumnNumber-1;
|
||||
|
||||
switch (FieldIdentifier) {
|
||||
case SQL_COLUMN_DISPLAY_SIZE: {
|
||||
*NumericAttribute = do_field_display_size(field);
|
||||
} break;
|
||||
case SQL_COLUMN_LABEL: {
|
||||
strncpy(CharacterAttribute, field->name, field->bytes);
|
||||
} break;
|
||||
default: {
|
||||
return SQL_ERROR;
|
||||
} break;
|
||||
}
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle,
|
||||
SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
|
||||
SQLPOINTER TargetValue, SQLLEN BufferLength,
|
||||
SQLLEN *StrLen_or_Ind) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
if (!sql->conn) return SQL_ERROR;
|
||||
if (!sql->conn->taos) return SQL_ERROR;
|
||||
if (!sql->rs) return SQL_ERROR;
|
||||
if (!sql->row) return SQL_ERROR;
|
||||
int nfields = taos_field_count(sql->rs);
|
||||
TAOS_FIELD *fields = taos_fetch_fields(sql->rs);
|
||||
|
||||
if (nfields==0 || fields==NULL) return SQL_ERROR;
|
||||
if (ColumnNumber>nfields) return SQL_ERROR;
|
||||
|
||||
TAOS_FIELD *field = fields + ColumnNumber-1;
|
||||
|
||||
switch (TargetType) {
|
||||
case SQL_CHAR: {
|
||||
do_convert(TargetValue, BufferLength, StrLen_or_Ind, field, sql->row[ColumnNumber-1]);
|
||||
*StrLen_or_Ind = SQL_NTS;
|
||||
} break;
|
||||
default: {
|
||||
return SQL_ERROR;
|
||||
} break;
|
||||
}
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) {
|
||||
sql_t *sql = (sql_t*)StatementHandle;
|
||||
if (!sql) return SQL_ERROR;
|
||||
if (!sql->conn) return SQL_ERROR;
|
||||
if (!sql->conn->taos) return SQL_ERROR;
|
||||
if (!sql->rs) return SQL_ERROR;
|
||||
sql->row = taos_fetch_row(sql->rs);
|
||||
return sql->row ? SQL_SUCCESS : SQL_NO_DATA;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle,
|
||||
SQLCHAR *StatementText, SQLINTEGER TextLength) {
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) {
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
static void init_routine(void) {
|
||||
taos_init();
|
||||
}
|
||||
|
||||
static int do_field_display_size(TAOS_FIELD *field) {
|
||||
switch (field->type) {
|
||||
case TSDB_DATA_TYPE_TINYINT:
|
||||
return 5;
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_SMALLINT:
|
||||
return 7;
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_INT:
|
||||
return 12;
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
return 22;
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_FLOAT: {
|
||||
return 12;
|
||||
} break;
|
||||
|
||||
case TSDB_DATA_TYPE_DOUBLE: {
|
||||
return 12;
|
||||
} break;
|
||||
|
||||
case TSDB_DATA_TYPE_BINARY:
|
||||
case TSDB_DATA_TYPE_NCHAR: {
|
||||
return 3*(field->bytes - VARSTR_HEADER_SIZE) + 2;
|
||||
} break;
|
||||
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
return 22;
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
return 7;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
static void do_convert(SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrLen_or_Ind, TAOS_FIELD *field, void *row) {
|
||||
switch (field->type) {
|
||||
case TSDB_DATA_TYPE_TINYINT:
|
||||
snprintf((char*)TargetValue, BufferLength, "%d", *((int8_t *)row));
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_SMALLINT:
|
||||
snprintf((char*)TargetValue, BufferLength, "%d", *((int16_t *)row));
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_INT:
|
||||
snprintf((char*)TargetValue, BufferLength, "%d", *((int32_t *)row));
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
snprintf((char*)TargetValue, BufferLength, "%" PRId64, *((int64_t *)row));
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_FLOAT: {
|
||||
float fv = 0;
|
||||
fv = GET_FLOAT_VAL(row);
|
||||
snprintf((char*)TargetValue, BufferLength, "%f", fv);
|
||||
} break;
|
||||
|
||||
case TSDB_DATA_TYPE_DOUBLE: {
|
||||
double dv = 0;
|
||||
dv = GET_DOUBLE_VAL(row);
|
||||
snprintf((char*)TargetValue, BufferLength, "%lf", dv);
|
||||
} break;
|
||||
|
||||
case TSDB_DATA_TYPE_BINARY:
|
||||
case TSDB_DATA_TYPE_NCHAR: {
|
||||
size_t xlen = 0;
|
||||
char *p = (char*)TargetValue;
|
||||
size_t n = BufferLength;
|
||||
for (xlen = 0; xlen < field->bytes - VARSTR_HEADER_SIZE; xlen++) {
|
||||
char c = ((char *)row)[xlen];
|
||||
if (c == 0) break;
|
||||
int v = snprintf(p, n, "%c", c);
|
||||
p += v;
|
||||
n -= v;
|
||||
if (n<=0) break;
|
||||
}
|
||||
if (n>0) *p = '\0';
|
||||
((char*)TargetValue)[BufferLength-1] = '\0';
|
||||
} break;
|
||||
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
snprintf((char*)TargetValue, BufferLength, "%" PRId64, *((int64_t *)row));
|
||||
break;
|
||||
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
snprintf((char*)TargetValue, BufferLength, "%d", *((int8_t *)row));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
PROJECT(TDengine)
|
||||
|
||||
IF (TD_LINUX)
|
||||
AUX_SOURCE_DIRECTORY(. SRC)
|
||||
ADD_EXECUTABLE(tcodbc main.c)
|
||||
TARGET_LINK_LIBRARIES(tcodbc odbc)
|
||||
ENDIF ()
|
|
@ -0,0 +1,20 @@
|
|||
#include <sql.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int main(void) {
|
||||
SQLRETURN r;
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
r = SQLAllocEnv(&env);
|
||||
if (r!=SQL_SUCCESS) return 1;
|
||||
do {
|
||||
r = SQLAllocConnect(env, &conn);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
SQLFreeConnect(conn);
|
||||
} while (0);
|
||||
SQLFreeEnv(env);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue