提交 dc2df3a0 编写于 作者: F freemine

add Error support

上级 36e5dac0
...@@ -21,5 +21,5 @@ ADD_SUBDIRECTORY(wal) ...@@ -21,5 +21,5 @@ ADD_SUBDIRECTORY(wal)
ADD_SUBDIRECTORY(cq) ADD_SUBDIRECTORY(cq)
ADD_SUBDIRECTORY(dnode) ADD_SUBDIRECTORY(dnode)
ADD_SUBDIRECTORY(connector/odbc) ADD_SUBDIRECTORY(connector/odbc)
ADD_SUBDIRECTORY(connector/jdbc) # ADD_SUBDIRECTORY(connector/jdbc)
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "taos.h" #include "taos.h"
#include "os.h" #include "os.h"
#include "taoserror.h"
#include <sql.h> #include <sql.h>
#include <sqlext.h> #include <sqlext.h>
...@@ -45,16 +46,73 @@ do { \ ...@@ -45,16 +46,73 @@ do { \
#define LOCK(obj) pthread_mutex_lock(&obj->lock); #define LOCK(obj) pthread_mutex_lock(&obj->lock);
#define UNLOCK(obj) pthread_mutex_unlock(&obj->lock); #define UNLOCK(obj) pthread_mutex_unlock(&obj->lock);
#define SET_ERROR(obj, sqlstate, eno, err_fmt, ...) \
do { \
obj->err.err_no = eno; \
const char* estr = tstrerror(eno); \
if (!estr) estr = "Unknown error"; \
int n = snprintf(NULL, 0, "[%x]%s: " err_fmt "", eno, estr, ##__VA_ARGS__); \
if (n<0) break; \
char *err_str = (char*)realloc(obj->err.err_str, n+1); \
if (!err_str) break; \
obj->err.err_str = err_str; \
snprintf(obj->err.err_str, n+1, "[%x]%s: " err_fmt "", eno, estr, ##__VA_ARGS__); \
snprintf((char*)obj->err.sql_state, sizeof(obj->err.sql_state), "%s", sqlstate); \
} while (0)
#define CLR_ERROR(obj) \
do { \
obj->err.err_no = TSDB_CODE_SUCCESS; \
if (obj->err.err_str) obj->err.err_str[0] = '\0'; \
obj->err.sql_state[0] = '\0'; \
} while (0)
#define FILL_ERROR(obj) \
do { \
size_t n = sizeof(obj->err.sql_state); \
if (Sqlstate) strncpy((char*)Sqlstate, (char*)obj->err.sql_state, n); \
if (NativeError) *NativeError = obj->err.err_no; \
snprintf((char*)MessageText, BufferLength, "%s", obj->err.err_str); \
if (TextLength && obj->err.err_str) *TextLength = strlen(obj->err.err_str); \
} while (0)
#define FREE_ERROR(obj) \
do { \
obj->err.err_no = TSDB_CODE_SUCCESS; \
if (obj->err.err_str) { \
free(obj->err.err_str); \
obj->err.err_str = NULL; \
} \
obj->err.sql_state[0] = '\0'; \
} while (0)
#define SDUP(s,n) (s ? (s[n] ? (const char*)strndup((const char*)s,n) : (const char*)s) : strdup(""))
#define SFRE(x,s,n) \
do { \
if (x==(const char*)s) break; \
if (x) { \
free((char*)x); \
x = NULL; \
} \
} while (0)
typedef struct env_s env_t; typedef struct env_s env_t;
typedef struct conn_s conn_t; typedef struct conn_s conn_t;
typedef struct sql_s sql_t; typedef struct sql_s sql_t;
typedef struct taos_error_s taos_error_t;
struct taos_error_s {
char *err_str;
int err_no;
SQLCHAR sql_state[6];
};
struct env_s { struct env_s {
uint64_t refcount; uint64_t refcount;
unsigned int destroying:1; unsigned int destroying:1;
taos_error_t err;
}; };
struct conn_s { struct conn_s {
...@@ -62,14 +120,19 @@ struct conn_s { ...@@ -62,14 +120,19 @@ struct conn_s {
env_t *env; env_t *env;
TAOS *taos; TAOS *taos;
taos_error_t err;
}; };
struct sql_s { struct sql_s {
uint64_t refcount; uint64_t refcount;
conn_t *conn; conn_t *conn;
TAOS_STMT *stmt;
TAOS_RES *rs; TAOS_RES *rs;
TAOS_ROW row; TAOS_ROW row;
taos_error_t err;
}; };
static pthread_once_t init_once = PTHREAD_ONCE_INIT; static pthread_once_t init_once = PTHREAD_ONCE_INIT;
...@@ -88,6 +151,7 @@ SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) { ...@@ -88,6 +151,7 @@ SQLRETURN SQL_API SQLAllocEnv(SQLHENV *EnvironmentHandle) {
*EnvironmentHandle = env; *EnvironmentHandle = env;
CLR_ERROR(env);
return SQL_SUCCESS; return SQL_SUCCESS;
} }
...@@ -104,6 +168,7 @@ SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) { ...@@ -104,6 +168,7 @@ SQLRETURN SQL_API SQLFreeEnv(SQLHENV EnvironmentHandle) {
DASSERT(DEC_REF(env)==0); DASSERT(DEC_REF(env)==0);
FREE_ERROR(env);
free(env); free(env);
return SQL_SUCCESS; return SQL_SUCCESS;
...@@ -119,7 +184,10 @@ SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle, ...@@ -119,7 +184,10 @@ SQLRETURN SQL_API SQLAllocConnect(SQLHENV EnvironmentHandle,
conn_t *conn = NULL; conn_t *conn = NULL;
do { do {
conn = (conn_t*)calloc(1, sizeof(*conn)); conn = (conn_t*)calloc(1, sizeof(*conn));
if (!conn) break; if (!conn) {
SET_ERROR(env, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to alloc connection handle");
break;
}
conn->env = env; conn->env = env;
*ConnectionHandle = conn; *ConnectionHandle = conn;
...@@ -152,6 +220,7 @@ SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) { ...@@ -152,6 +220,7 @@ SQLRETURN SQL_API SQLFreeConnect(SQLHDBC ConnectionHandle) {
DASSERT(DEC_REF(conn)==0); DASSERT(DEC_REF(conn)==0);
conn->env = NULL; conn->env = NULL;
FREE_ERROR(conn);
free(conn); free(conn);
} while (0); } while (0);
...@@ -165,10 +234,32 @@ SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle, ...@@ -165,10 +234,32 @@ SQLRETURN SQL_API SQLConnect(SQLHDBC ConnectionHandle,
conn_t *conn = (conn_t*)ConnectionHandle; conn_t *conn = (conn_t*)ConnectionHandle;
if (!conn) return SQL_ERROR; if (!conn) return SQL_ERROR;
if (conn->taos) return SQL_ERROR; if (conn->taos) {
SET_ERROR(conn, "HY000", TSDB_CODE_TSC_APP_ERROR, "connection still in use");
return SQL_ERROR;
}
const char *serverName = SDUP(ServerName, NameLength1);
const char *userName = SDUP(UserName, NameLength2);
const char *auth = SDUP(Authentication, NameLength3);
do {
if (!serverName || !userName || !auth) {
SET_ERROR(conn, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to connect to database");
break;
}
// TODO: data-race // TODO: data-race
conn->taos = taos_connect("localhost", (const char*)UserName, (const char*)Authentication, NULL, 0); // TODO: shall receive ip/port from odbc.ini
conn->taos = taos_connect("localhost", userName, auth, NULL, 0);
if (!conn->taos) {
SET_ERROR(conn, "HY000", terrno, "failed to connect to database");
break;
}
} while (0);
SFRE(serverName, ServerName, NameLength1);
SFRE(userName, UserName, NameLength2);
SFRE(auth, Authentication, NameLength3);
return conn->taos ? SQL_SUCCESS : SQL_ERROR; return conn->taos ? SQL_SUCCESS : SQL_ERROR;
} }
...@@ -194,7 +285,10 @@ SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle, ...@@ -194,7 +285,10 @@ SQLRETURN SQL_API SQLAllocStmt(SQLHDBC ConnectionHandle,
do { do {
sql_t *sql = (sql_t*)calloc(1, sizeof(*sql)); sql_t *sql = (sql_t*)calloc(1, sizeof(*sql));
if (!sql) break; if (!sql) {
SET_ERROR(conn, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to alloc statement handle");
break;
}
sql->conn = conn; sql->conn = conn;
DASSERT(INC_REF(sql)>0); DASSERT(INC_REF(sql)>0);
...@@ -214,6 +308,12 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, ...@@ -214,6 +308,12 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle,
sql_t *sql = (sql_t*)StatementHandle; sql_t *sql = (sql_t*)StatementHandle;
if (!sql) return SQL_ERROR; if (!sql) return SQL_ERROR;
if (Option != SQL_DROP) {
D("Option: [%d][%x]", Option, Option);
SET_ERROR(sql, "HY000", TSDB_CODE_COM_OPS_NOT_SUPPORT, "failed to free statement");
return SQL_ERROR;
}
DASSERT(GET_REF(sql)==1); DASSERT(GET_REF(sql)==1);
if (sql->rs) { if (sql->rs) {
...@@ -221,11 +321,17 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, ...@@ -221,11 +321,17 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle,
sql->rs = NULL; sql->rs = NULL;
} }
if (sql->stmt) {
taos_stmt_close(sql->stmt);
sql->stmt = NULL;
}
DASSERT(DEC_REF(sql->conn)>0); DASSERT(DEC_REF(sql->conn)>0);
DASSERT(DEC_REF(sql)==0); DASSERT(DEC_REF(sql)==0);
sql->conn = NULL; sql->conn = NULL;
FREE_ERROR(sql);
free(sql); free(sql);
return SQL_SUCCESS; return SQL_SUCCESS;
...@@ -243,7 +349,27 @@ SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle, ...@@ -243,7 +349,27 @@ SQLRETURN SQL_API SQLExecDirect(SQLHSTMT StatementHandle,
sql->rs = NULL; sql->rs = NULL;
sql->row = NULL; sql->row = NULL;
} }
sql->rs = taos_query(sql->conn->taos, (const char*)StatementText);
if (sql->stmt) {
taos_stmt_close(sql->stmt);
sql->stmt = NULL;
}
const char *stxt = SDUP(StatementText, TextLength);
do {
if (!stxt) {
SET_ERROR(sql, "HY000", TSDB_CODE_COM_OUT_OF_MEMORY, "failed to query");
break;
}
sql->rs = taos_query(sql->conn->taos, stxt);
if (!sql->rs) {
SET_ERROR(sql, "HY000", terrno, "failed to query");
break;
}
} while (0);
SFRE(stxt, StatementText, TextLength);
return sql->rs ? SQL_SUCCESS : SQL_NO_DATA; return sql->rs ? SQL_SUCCESS : SQL_NO_DATA;
} }
...@@ -351,13 +477,113 @@ SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) { ...@@ -351,13 +477,113 @@ SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) {
SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle, SQLRETURN SQL_API SQLPrepare(SQLHSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength) { SQLCHAR *StatementText, SQLINTEGER TextLength) {
return SQL_ERROR; 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;
}
if (sql->stmt) {
taos_stmt_close(sql->stmt);
sql->stmt = NULL;
}
do {
sql->stmt = taos_stmt_init(sql->conn->taos);
if (!sql->stmt) {
SET_ERROR(sql, "HY000", terrno, "failed to initialize statement internally");
break;
}
int r = taos_stmt_prepare(sql->stmt, (const char *)StatementText, TextLength);
if (r) {
SET_ERROR(sql, "HY000", r, "failed to prepare a statement");
taos_stmt_close(sql->stmt);
sql->stmt = NULL;
break;
}
} while (0);
return sql->stmt ? SQL_SUCCESS : SQL_ERROR;
} }
SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) { SQLRETURN SQL_API SQLExecute(SQLHSTMT StatementHandle) {
sql_t *sql = (sql_t*)StatementHandle;
if (!sql) return SQL_ERROR;
if (!sql->conn) return SQL_ERROR;
if (!sql->conn->taos) return SQL_ERROR;
if (!sql->stmt) return SQL_ERROR;
if (sql->rs) {
taos_free_result(sql->rs);
sql->rs = NULL;
sql->row = NULL;
}
int r = 0;
r = taos_stmt_execute(sql->stmt);
if (r) {
SET_ERROR(sql, "HY000", r, "failed to execute statement");
return SQL_ERROR;
}
sql->rs = taos_stmt_use_result(sql->stmt);
if (!sql->rs) {
SET_ERROR(sql, "HY000", r, "failed to fetch result");
return SQL_ERROR;
}
return sql->rs ? SQL_SUCCESS : SQL_ERROR;
}
SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier,
SQLPOINTER DiagInfo, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLength) {
// if this function is not exported, isql will never call SQLGetDiagRec
return SQL_ERROR; return SQL_ERROR;
} }
SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
SQLINTEGER *NativeError, SQLCHAR *MessageText,
SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) {
if (RecNumber>1) return SQL_NO_DATA;
switch (HandleType) {
case SQL_HANDLE_ENV: {
env_t *env = (env_t*)Handle;
if (!env) break;
FILL_ERROR(env);
return SQL_SUCCESS;
} break;
case SQL_HANDLE_DBC: {
conn_t *conn = (conn_t*)Handle;
if (!conn) break;
FILL_ERROR(conn);
return SQL_SUCCESS;
} break;
case SQL_HANDLE_STMT: {
sql_t *sql = (sql_t*)Handle;
if (!sql) break;
FILL_ERROR(sql);
return SQL_SUCCESS;
} break;
default: {
} break;
}
return SQL_ERROR;
}
static void init_routine(void) { static void init_routine(void) {
taos_init(); taos_init();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册