From 865ed91cefa9e69c449776050b00759748ad343f Mon Sep 17 00:00:00 2001 From: Bogdan Pintea Date: Tue, 21 Aug 2018 16:05:35 +0200 Subject: [PATCH 1/4] b/f: fix older if(); error --- driver/connect.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/driver/connect.c b/driver/connect.c index 43b95126..05fd8496 100644 --- a/driver/connect.c +++ b/driver/connect.c @@ -1631,8 +1631,9 @@ SQLRETURN EsSQLGetConnectAttrW( ERRH(dbc, "failed to get current catalog."); RET_STATE(dbc->hdr.diag.state); } - if (StringLengthPtr); - *StringLengthPtr = (SQLINTEGER)used; + if (StringLengthPtr) { + *StringLengthPtr = (SQLINTEGER)used; + } break; case SQL_ATTR_METADATA_ID: From 9c7f7147eba292686b4032078e85967c4c5adff2 Mon Sep 17 00:00:00 2001 From: Bogdan Pintea Date: Tue, 21 Aug 2018 16:13:24 +0200 Subject: [PATCH 2/4] all async attributes indicate now lack of support The async API is not supported -- implement all attributes that signal the lack of support. The driver supports the multi-threading model with connection/statement per thread and will further implement connection pooling --- driver/connect.c | 24 ++++++++++++++++++++---- driver/error.h | 6 ++++++ driver/handles.c | 19 +++++++++++++------ driver/handles.h | 2 -- driver/info.c | 22 +++++++++++++++------- 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/driver/connect.c b/driver/connect.c index 05fd8496..772b30a9 100644 --- a/driver/connect.c +++ b/driver/connect.c @@ -1575,10 +1575,26 @@ SQLRETURN EsSQLSetConnectAttrW( DBGH(dbc, "setting metadata_id to %u.", (SQLULEN)Value); dbc->metadata_id = (SQLULEN)Value; break; + case SQL_ATTR_ASYNC_ENABLE: - DBGH(dbc, "setting async enable to %u.", (SQLULEN)Value); - dbc->async_enable = (SQLULEN)Value; + ERRH(dbc, "no support for async API (setting param: %llu)", + (SQLULEN)(uintptr_t)Value); + if ((SQLULEN)(uintptr_t)Value == SQL_ASYNC_ENABLE_ON) { + RET_HDIAGS(dbc, SQL_STATE_HYC00); + } break; + case SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE: + ERRH(dbc, "no support for async API (setting param: %llu)", + (SQLULEN)(uintptr_t)Value); + if ((SQLULEN)(uintptr_t)Value == SQL_ASYNC_DBC_ENABLE_ON) { + RET_HDIAGS(dbc, SQL_STATE_HY114); + } + break; + case SQL_ATTR_ASYNC_DBC_EVENT: + // case SQL_ATTR_ASYNC_DBC_PCALLBACK: + // case SQL_ATTR_ASYNC_DBC_PCONTEXT: + ERRH(dbc, "no support for async API (attr: %ld)", Attribute); + RET_HDIAGS(dbc, SQL_STATE_S1118); case SQL_ATTR_QUIET_MODE: DBGH(dbc, "setting window handler to 0x%p.", Value); @@ -1641,8 +1657,8 @@ SQLRETURN EsSQLGetConnectAttrW( *(SQLULEN *)ValuePtr = dbc->metadata_id; break; case SQL_ATTR_ASYNC_ENABLE: - DBGH(dbc, "requested: async enable: %u.", dbc->async_enable); - *(SQLULEN *)ValuePtr = dbc->async_enable; + DBGH(dbc, "getting async mode: %llu", SQL_ASYNC_ENABLE_OFF); + *(SQLULEN *)ValuePtr = SQL_ASYNC_ENABLE_OFF; break; case SQL_ATTR_QUIET_MODE: diff --git a/driver/error.h b/driver/error.h index 83434350..1ecf02f1 100644 --- a/driver/error.h +++ b/driver/error.h @@ -120,6 +120,7 @@ typedef enum { SQL_STATE_HY109, SQL_STATE_HY110, SQL_STATE_HY111, + SQL_STATE_HY114, SQL_STATE_HYC00, SQL_STATE_HYT00, SQL_STATE_HYT01, @@ -138,6 +139,7 @@ typedef enum { SQL_STATE_IM013, SQL_STATE_IM014, SQL_STATE_IM015, + SQL_STATE_S1118, SQL_STATE_MAX } esodbc_state_et; @@ -379,6 +381,8 @@ static esodbc_errors_st esodbc_errors[] = { SQL_ERROR}, {MK_WPTR("HY111"), MK_WPTR("Invalid bookmark value"), SQL_ERROR}, + {MK_WPTR("HY114"), MK_WPTR("Driver does not support connection-level " + "asynchronous function execution"), SQL_ERROR}, {MK_WPTR("HYC00"), MK_WPTR("Optional feature not implemented"), SQL_ERROR}, {MK_WPTR("HYT00"), MK_WPTR("Timeout expired"), @@ -417,6 +421,8 @@ static esodbc_errors_st esodbc_errors[] = { SQL_ERROR}, {MK_WPTR("IM015"), MK_WPTR("Corrupt file data source"), SQL_ERROR}, + {MK_WPTR("S1118"), MK_WPTR("Driver does not support asynchronous " + "notification"), SQL_ERROR}, }; /*INDENT-ON*/ diff --git a/driver/handles.c b/driver/handles.c index 069af88f..c7819d57 100644 --- a/driver/handles.c +++ b/driver/handles.c @@ -225,7 +225,6 @@ SQLRETURN EsSQLAllocHandle(SQLSMALLINT HandleType, } dbc->dsn.str = MK_WPTR(""); /* see explanation in cleanup_dbc() */ dbc->metadata_id = SQL_FALSE; - dbc->async_enable = SQL_ASYNC_ENABLE_OFF; dbc->txn_isolation = ESODBC_DEF_TXN_ISOLATION; /* rest of initialization done at connect time */ @@ -261,7 +260,6 @@ SQLRETURN EsSQLAllocHandle(SQLSMALLINT HandleType, * Note: these attributes won't propagate at statement level when * set at connection level. */ stmt->metadata_id = dbc->metadata_id; - stmt->async_enable = dbc->async_enable; stmt->sql2c_conversion = CONVERSION_UNCHECKED; DBGH(dbc, "new Statement handle allocated @0x%p.", *OutputHandle); @@ -767,10 +765,19 @@ SQLRETURN EsSQLSetStmtAttrW( DBGH(stmt, "setting metadata_id to: %u", (SQLULEN)ValuePtr); stmt->metadata_id = (SQLULEN)ValuePtr; break; + case SQL_ATTR_ASYNC_ENABLE: - DBGH(stmt, "setting async_enable to: %u", (SQLULEN)ValuePtr); - stmt->async_enable = (SQLULEN)ValuePtr; + ERRH(stmt, "no support for async API (setting param: %llu)", + (SQLULEN)(uintptr_t)ValuePtr); + if ((SQLULEN)(uintptr_t)ValuePtr == SQL_ASYNC_ENABLE_ON) { + RET_HDIAGS(stmt, SQL_STATE_HYC00); + } break; + case SQL_ATTR_ASYNC_STMT_EVENT: + // case SQL_ATTR_ASYNC_STMT_PCALLBACK: + // case SQL_ATTR_ASYNC_STMT_PCONTEXT: + ERRH(stmt, "no support for async API (attr: %ld)", Attribute); + RET_HDIAGS(stmt, SQL_STATE_S1118); case SQL_ATTR_MAX_LENGTH: ulen = (SQLULEN)ValuePtr; @@ -834,8 +841,8 @@ SQLRETURN EsSQLGetStmtAttrW( *(SQLULEN *)ValuePtr = stmt->metadata_id; break; case SQL_ATTR_ASYNC_ENABLE: - DBGH(stmt, "getting async_enable: %llu", stmt->async_enable); - *(SQLULEN *)ValuePtr = stmt->async_enable; + DBGH(stmt, "getting async mode: %llu", SQL_ASYNC_ENABLE_OFF); + *(SQLULEN *)ValuePtr = SQL_ASYNC_ENABLE_OFF; break; case SQL_ATTR_MAX_LENGTH: DBGH(stmt, "getting max_length: %llu", stmt->max_length); diff --git a/driver/handles.h b/driver/handles.h index 0355d31a..e4ff5f4e 100644 --- a/driver/handles.h +++ b/driver/handles.h @@ -155,7 +155,6 @@ typedef struct struct_dbc { /* options */ SQLULEN metadata_id; // default: SQL_FALSE - SQLULEN async_enable; // default: SQL_ASYNC_ENABLE_OFF SQLUINTEGER txn_isolation; // default: SQL_TXN_* } esodbc_dbc_st; @@ -307,7 +306,6 @@ typedef struct struct_stmt { /* options */ SQLULEN bookmarks; //default: SQL_UB_OFF SQLULEN metadata_id; // default: copied from connection - SQLULEN async_enable; // default: copied from connection /* "the maximum amount of data that the driver returns from a character or * binary column" */ SQLULEN max_length; diff --git a/driver/info.c b/driver/info.c index c4e12292..a8b5e367 100644 --- a/driver/info.c +++ b/driver/info.c @@ -123,19 +123,29 @@ SQLRETURN EsSQLGetInfoW(SQLHDBC ConnectionHandle, return write_wstr(dbc, InfoValue, &MK_WSTR(ESODBC_SQL_SPEC_STRING), BufferLength, StringLengthPtr); + case SQL_ASYNC_MODE: + DBGH(dbc, "requested: async mode (%lu).", SQL_AM_NONE); + *(SQLUINTEGER *)InfoValue = SQL_AM_NONE; + break; + /* "if the driver can execute functions asynchronously on the * connection handle" */ case SQL_ASYNC_DBC_FUNCTIONS: - /* TODO: review@alpha */ - *(SQLUSMALLINT *)InfoValue = SQL_FALSE; - DBGH(dbc, "requested: support for async fuctions: no."); + DBGH(dbc, "requested: async DBC functions (no - %lu).", + SQL_ASYNC_DBC_NOT_CAPABLE); + *(SQLUINTEGER *)InfoValue = SQL_ASYNC_DBC_NOT_CAPABLE; break; /* "if the driver supports asynchronous notification" */ case SQL_ASYNC_NOTIFICATION: - // FIXME: review@alpha */ + DBGH(dbc, "requested: async notification (no - %lu).", + SQL_ASYNC_NOTIFICATION_NOT_CAPABLE); *(SQLUINTEGER *)InfoValue = SQL_ASYNC_NOTIFICATION_NOT_CAPABLE; - DBGH(dbc, "requested: support for async notifications: no."); + break; + + case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS: + DBGH(dbc, "requested: async concurrent statements (0)."); + *(SQLUINTEGER *)InfoValue = 0; break; /* "the maximum number of active statements that the driver can @@ -159,8 +169,6 @@ SQLRETURN EsSQLGetInfoW(SQLHDBC ConnectionHandle, case SQL_GETDATA_EXTENSIONS: DBGH(dbc, "requested: GetData extentions."); - // FIXME: review@alpha - // TODO: GetData review *(SQLUINTEGER *)InfoValue = ESODBC_GETDATA_EXTENSIONS; break; From 5b1a4a298c4909d5a8cd791a5e678a4ed8923bda Mon Sep 17 00:00:00 2001 From: Bogdan Pintea Date: Tue, 21 Aug 2018 16:17:07 +0200 Subject: [PATCH 3/4] add locking of handles for multi-threaded operation All handles have now their own lock, which is acquired at API entry. (The descriptor handles have it too, but the statement locks are used instead.) The connection handles have an extra lock for serializing access to the libcurl-related members, since multiple statements can be active for one connection. --- driver/connect.c | 8 +- driver/defs.h | 3 +- driver/handles.c | 15 ++- driver/handles.h | 17 ++- driver/info.c | 6 +- driver/log.c | 14 +-- driver/odbc.c | 294 ++++++++++++++++++++--------------------------- driver/queries.c | 26 +++++ driver/queries.h | 2 + driver/util.h | 15 +++ 10 files changed, 207 insertions(+), 193 deletions(-) diff --git a/driver/connect.c b/driver/connect.c index 772b30a9..75a6d942 100644 --- a/driver/connect.c +++ b/driver/connect.c @@ -313,6 +313,8 @@ SQLRETURN post_json(esodbc_stmt_st *stmt, const cstr_st *u8body) DBGH(stmt, "POSTing JSON [%zd] `" LCPDL "`.", u8body->cnt, LCSTR(u8body)); + ESODBC_MUX_LOCK(&dbc->curl_mux); + if (! dbc->curl) { init_curl(dbc); } @@ -370,6 +372,8 @@ SQLRETURN post_json(esodbc_stmt_st *stmt, const cstr_st *u8body) DBGH(stmt, "libcurl: request succesfull, received code %ld and %zd bytes" " back.", code, apos); + ESODBC_MUX_UNLOCK(&dbc->curl_mux); + if (code != 200) { ERRH(stmt, "libcurl: non-200 HTTP response code %ld received.", code); /* expect a 200 with body; everything else is failure (todo?) */ @@ -387,6 +391,8 @@ SQLRETURN post_json(esodbc_stmt_st *stmt, const cstr_st *u8body) res != CURLE_OK ? curl_easy_strerror(res) : "", res); err_net: /* the error occured after the request hit hit the network */ cleanup_curl(dbc); + ESODBC_MUX_UNLOCK(&dbc->curl_mux); + if (abuff) { free(abuff); abuff = NULL; @@ -594,7 +600,7 @@ void cleanup_dbc(esodbc_dbc_st *dbc) } else { assert(dbc->no_types == 0); } - assert(dbc->abuff == NULL); /* reminder for when going multithreaded */ + assert(dbc->abuff == NULL); cleanup_curl(dbc); } diff --git a/driver/defs.h b/driver/defs.h index 78294572..46b4fdd4 100644 --- a/driver/defs.h +++ b/driver/defs.h @@ -53,8 +53,7 @@ #define ESODBC_PARAM_MARKER "?" /* max # of active statements for a connection */ -/* TODO: review@alpha */ -#define ESODBC_MAX_CONCURRENT_ACTIVITIES 16 +#define ESODBC_MAX_CONCURRENT_ACTIVITIES 0 /* maximum identifer length */ /* TODO: review@alpha */ /* match 'keyword' ES type length */ diff --git a/driver/handles.c b/driver/handles.c index c7819d57..561398d5 100644 --- a/driver/handles.c +++ b/driver/handles.c @@ -51,6 +51,7 @@ static void init_hheader(esodbc_hhdr_st *hdr, SQLSMALLINT type, void *parent) { hdr->type = type; init_diagnostic(&hdr->diag); + ESODBC_MUX_INIT(&hdr->mutex); hdr->parent = parent; } @@ -262,6 +263,8 @@ SQLRETURN EsSQLAllocHandle(SQLSMALLINT HandleType, stmt->metadata_id = dbc->metadata_id; stmt->sql2c_conversion = CONVERSION_UNCHECKED; + ESODBC_MUX_INIT(&dbc->curl_mux); + DBGH(dbc, "new Statement handle allocated @0x%p.", *OutputHandle); break; @@ -301,6 +304,7 @@ SQLRETURN EsSQLAllocHandle(SQLSMALLINT HandleType, SQLRETURN EsSQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) { + esodbc_dbc_st *dbc; esodbc_stmt_st *stmt; esodbc_desc_st *desc; @@ -312,13 +316,13 @@ SQLRETURN EsSQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) switch(HandleType) { case SQL_HANDLE_ENV: /* Environment Handle */ // TODO: check if there are connections (_DBC) - free(Handle); break; case SQL_HANDLE_DBC: /* Connection Handle */ // TODO: remove from (potential) list? + dbc = DBCH(Handle); /* app/DM should have SQLDisconnect'ed, but just in case */ - cleanup_dbc(DBCH(Handle)); - free(Handle); + cleanup_dbc(dbc); + ESODBC_MUX_DEL(&dbc->curl_mux); break; case SQL_HANDLE_STMT: // TODO: remove from (potential) list? @@ -330,7 +334,6 @@ SQLRETURN EsSQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) clear_desc(stmt->ird, FALSE); clear_desc(stmt->apd, FALSE); clear_desc(stmt->ipd, FALSE); - free(stmt); break; // FIXME: @@ -354,6 +357,8 @@ SQLRETURN EsSQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) return SQL_INVALID_HANDLE; } + ESODBC_MUX_DEL(&HDRH(Handle)->mutex); + free(Handle); return SQL_SUCCESS; } @@ -477,7 +482,7 @@ SQLRETURN EsSQLSetEnvAttr(SQLHENV EnvironmentHandle, case SQL_ATTR_CONNECTION_POOLING: case SQL_ATTR_CP_MATCH: RET_HDIAG(ENVH(EnvironmentHandle), SQL_STATE_HYC00, - "Connection pooling not yet supported", 0); + "Connection pooling not supported", 0); case SQL_ATTR_ODBC_VERSION: switch ((intptr_t)Value) { diff --git a/driver/handles.h b/driver/handles.h index e4ff5f4e..aef5aebf 100644 --- a/driver/handles.h +++ b/driver/handles.h @@ -28,6 +28,8 @@ typedef struct struct_hheader { /* handle header */ SQLSMALLINT type; /* diagnostic/state keeping */ esodbc_diag_st diag; + /* ODBC API multi-threading exclusive lock */ + esodbc_mutex_lt mutex; /* back reference to "parent" structure (in type hierarchy) */ union { struct struct_env *env; @@ -145,13 +147,10 @@ typedef struct struct_dbc { size_t alen; /* size of abuff */ size_t apos; /* current write position in the abuff */ size_t amax; /* maximum length (bytes) that abuff can grow to */ + esodbc_mutex_lt curl_mux; /* mutex for above 'networking' members */ /* window handler */ HWND hwin; - /* "the catalog is a database", "For a single-tier driver, the catalog - * might be a directory" */ - SQLWCHAR *catalog; - // TODO: statement list? /* options */ SQLULEN metadata_id; // default: SQL_FALSE @@ -435,6 +434,9 @@ SQLRETURN EsSQLSetDescRec( _Inout_opt_ SQLLEN *Indicator); +/* + * Macros to convert ODBC API generic handles into implementation types. + */ #define ENVH(_h) ((esodbc_env_st *)(_h)) #define DBCH(_h) ((esodbc_dbc_st *)(_h)) #define STMH(_h) ((esodbc_stmt_st *)(_h)) @@ -442,6 +444,13 @@ SQLRETURN EsSQLSetDescRec( /* this will only work if member stays first in handles (see struct decl). */ #define HDRH(_h) ((esodbc_hhdr_st *)(_h)) +/* + * Locking macros for ODBC API calls. + */ +#define HND_LOCK(_h) ESODBC_MUX_LOCK(&HDRH(_h)->mutex) +#define HND_TRYLOCK(_h) ESODBC_MUX_TRYLOCK(&HDRH(_h)->mutex) +#define HND_UNLOCK(_h) ESODBC_MUX_UNLOCK(&HDRH(_h)->mutex) + /* wraper of RET_CDIAG, compatible with any defined handle */ #define RET_HDIAG(_hp/*handle ptr*/, _s/*tate*/, _t/*char text*/, _c/*ode*/) \ diff --git a/driver/info.c b/driver/info.c index a8b5e367..6cfb718f 100644 --- a/driver/info.c +++ b/driver/info.c @@ -743,9 +743,10 @@ SQLRETURN EsSQLGetDiagFieldW( return write_wstr(&dummy, DiagInfoPtr, wstrp, BufferLength, StringLengthPtr); - case SQL_DIAG_CONNECTION_NAME: /* same as SQLGetInfo(SQL_DATA_SOURCE_NAME) */ - case SQL_DIAG_SERVER_NAME: /* TODO: keep same as _CONNECTION_NAME? */ + case SQL_DIAG_CONNECTION_NAME: + /* TODO: this must be the server name, not DSN. */ + case SQL_DIAG_SERVER_NAME: switch (HandleType) { case SQL_HANDLE_DBC: wstrp = &DBCH(Handle)->dsn; @@ -920,7 +921,6 @@ SQLRETURN EsSQLGetFunctions(SQLHDBC ConnectionHandle, } } - // TODO: does this require connecting to the server? return SQL_SUCCESS; } diff --git a/driver/log.c b/driver/log.c index 4dbd4513..5ff40d5c 100644 --- a/driver/log.c +++ b/driver/log.c @@ -32,11 +32,7 @@ int _esodbc_log_level = LOG_LEVEL_DISABLED; /* log file path -- process variable */ static TCHAR *log_path = NULL; /* log file mutex -- process variable */ -static SRWLOCK log_mux = SRWLOCK_INIT; - -#define MUTEX_LOCK(_mux) \ - (WaitForSingleObject(_mux, INFINITE) == WAIT_OBJECT_0) -#define MUTEX_UNLOCK(_mux) ReleaseMutex(_mux) +static esodbc_mutex_lt log_mux = ESODBC_MUX_SINIT; static inline HANDLE log_file_handle(BOOL open) @@ -143,8 +139,8 @@ BOOL log_init() void log_cleanup() { - /* There is no need/function to destroy the SRWLOCK */ - log_file_handle(/* close */FALSE); + log_file_handle(/*open?*/FALSE); + ESODBC_MUX_DEL(&log_mux); } @@ -258,9 +254,9 @@ static inline void log_file(int level, int werrno, const char *func, } assert(pos <= sizeof(buff)); - AcquireSRWLockExclusive(&log_mux); + ESODBC_MUX_LOCK(&log_mux); log_file_write(buff, pos); - ReleaseSRWLockExclusive(&log_mux); + ESODBC_MUX_UNLOCK(&log_mux); } void _esodbc_log(int lvl, int werrno, const char *func, diff --git a/driver/odbc.c b/driver/odbc.c index a423a813..84a7a11b 100644 --- a/driver/odbc.c +++ b/driver/odbc.c @@ -71,7 +71,7 @@ BOOL WINAPI DllMain( // Perform any necessary cleanup. case DLL_PROCESS_DETACH: - INFO("process %u dettached.", GetCurrentProcessId()); + INFO("process %u dettaching.", GetCurrentProcessId()); driver_cleanup(); break; } @@ -88,6 +88,7 @@ SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT HandleType, { SQLRETURN ret; TRACE3(_IN, "dpp", HandleType, InputHandle, OutputHandle); + /* no synchronization required */ ret = EsSQLAllocHandle(HandleType, InputHandle, OutputHandle); TRACE4(_OUT, "ddpp", ret, HandleType, InputHandle, *OutputHandle); return ret; @@ -132,8 +133,10 @@ SQLRETURN SQL_API SQLDriverConnectW SQLRETURN ret; TRACE8(_IN, "pppdpdpd", hdbc, hwnd, szConnStrIn, cchConnStrIn, szConnStrOut, cchConnStrOutMax, pcchConnStrOut, fDriverCompletion); + HND_LOCK(hdbc); ret = EsSQLDriverConnectW(hdbc, hwnd, szConnStrIn, cchConnStrIn, szConnStrOut, cchConnStrOutMax, pcchConnStrOut, fDriverCompletion); + HND_UNLOCK(hdbc); TRACE9(_OUT, "dppWdWdtd", ret, hdbc, hwnd, szConnStrIn, cchConnStrIn, szConnStrOut, cchConnStrOutMax, pcchConnStrOut, fDriverCompletion); return ret; @@ -208,8 +211,14 @@ SQLRETURN SQL_API SQLGetInfoW(SQLHDBC ConnectionHandle, SQLRETURN ret; TRACE5(_IN, "pupdp", ConnectionHandle, InfoType, InfoValue, BufferLength, StringLengthPtr); + /* Note_sync: no synchronization really required for setting/getting of + * integer attributes (atomic) or string ones (= reading static string + * locations), but error handling involves posting an SQL state & string, + * which needs serialization. */ + HND_LOCK(ConnectionHandle); ret = EsSQLGetInfoW(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLengthPtr); + HND_UNLOCK(ConnectionHandle); TRACE6(_OUT, "dpupdt", ret, ConnectionHandle, InfoType, InfoValue, BufferLength, StringLengthPtr); return ret; @@ -223,6 +232,7 @@ SQLRETURN SQL_API SQLGetFunctions(SQLHDBC ConnectionHandle, { SQLRETURN ret; TRACE3(_IN, "pdp", ConnectionHandle, FunctionId, Supported); + /* no synchronization required */ ret = EsSQLGetFunctions(ConnectionHandle, FunctionId, Supported); TRACE4(_IN, "dpdT", ret, ConnectionHandle, FunctionId, Supported); return ret; @@ -234,7 +244,9 @@ SQLRETURN SQL_API SQLGetTypeInfoW( { SQLRETURN ret; TRACE2(_IN, "pd", StatementHandle, DataType); + HND_LOCK(StatementHandle); ret = EsSQLGetTypeInfoW(StatementHandle, DataType); + HND_UNLOCK(StatementHandle); TRACE3(_OUT, "dpd", ret, StatementHandle, DataType); return ret; //RET_NOT_IMPLEMENTED; @@ -255,8 +267,10 @@ SQLRETURN SQL_API SQLSetConnectAttrW( { SQLRETURN ret; TRACE4(_IN, "pdpd", ConnectionHandle, Attribute, Value, StringLength); + HND_LOCK(ConnectionHandle); /* see Note_sync above */ ret = EsSQLSetConnectAttrW(ConnectionHandle, Attribute, Value, StringLength); + HND_UNLOCK(ConnectionHandle); TRACE5(_OUT, "dpdpd", ret, ConnectionHandle, Attribute, Value, StringLength); return ret; @@ -272,8 +286,10 @@ SQLRETURN SQL_API SQLGetConnectAttrW( SQLRETURN ret; TRACE5(_IN, "pdpdp", ConnectionHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr); + HND_LOCK(ConnectionHandle); ret = EsSQLGetConnectAttrW(ConnectionHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr); + HND_UNLOCK(ConnectionHandle); TRACE6(_OUT, "dpdpdg", ret, ConnectionHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr); return ret; @@ -287,7 +303,9 @@ SQLRETURN SQL_API SQLSetEnvAttr(SQLHENV EnvironmentHandle, { SQLRETURN ret; TRACE4(_IN, "pdpd", EnvironmentHandle, Attribute, Value, StringLength); + HND_LOCK(EnvironmentHandle); /* see Note_sync above */ ret = EsSQLSetEnvAttr(EnvironmentHandle, Attribute, Value, StringLength); + HND_UNLOCK(EnvironmentHandle); TRACE5(_OUT, "dpdpd", ret, EnvironmentHandle, Attribute, Value, StringLength); return ret; @@ -301,8 +319,10 @@ SQLRETURN SQL_API SQLGetEnvAttr(SQLHENV EnvironmentHandle, SQLRETURN ret; TRACE5(_IN, "pdpdp", EnvironmentHandle, Attribute, Value, BufferLength, StringLength); + HND_LOCK(EnvironmentHandle); /* see Note_sync above */ ret = EsSQLGetEnvAttr(EnvironmentHandle, Attribute, Value, BufferLength, StringLength); + HND_UNLOCK(EnvironmentHandle); TRACE6(_OUT, "dpdpdg", ret, EnvironmentHandle, Attribute, Value, BufferLength, StringLength); return ret; @@ -316,8 +336,10 @@ SQLRETURN SQL_API SQLSetStmtAttrW( { SQLRETURN ret; TRACE4(_IN, "pdpd", StatementHandle, Attribute, ValuePtr, BufferLength); + HND_LOCK(StatementHandle); ret = EsSQLSetStmtAttrW(StatementHandle, Attribute, ValuePtr, BufferLength); + HND_UNLOCK(StatementHandle); TRACE5(_OUT, "dpdpd", ret, StatementHandle, Attribute, ValuePtr, BufferLength); return ret; @@ -333,8 +355,10 @@ SQLRETURN SQL_API SQLGetStmtAttrW( SQLRETURN ret; TRACE5(_IN, "pdpdp", StatementHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr); + HND_LOCK(StatementHandle); ret = EsSQLGetStmtAttrW(StatementHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr); + HND_UNLOCK(StatementHandle); TRACE6(_OUT, "dpdpdg", ret, StatementHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr); return ret; @@ -359,13 +383,42 @@ SQLRETURN SQL_API SQLGetDescFieldW( SQLRETURN ret; TRACE6(_IN, "pddpdp", DescriptorHandle, RecNumber, FieldIdentifier, ValuePtr, BufferLength, StringLengthPtr); + /* Note_stmt_sync: API descriptor access is serialized by statement's + * mutex, not descriptor's, since statement functions working on + * descriptors won't lock these, but will lock the statement instead + * (which keeps the code simpler; besides, no "high-speed" concurrent + * thread access on descriptors is necessary anyway). */ + HND_LOCK(DSCH(DescriptorHandle)->hdr.stmt); ret = EsSQLGetDescFieldW(DescriptorHandle, RecNumber, FieldIdentifier, ValuePtr, BufferLength, StringLengthPtr); + HND_UNLOCK(DSCH(DescriptorHandle)->hdr.stmt); TRACE7(_OUT, "dpddpdg", ret, DescriptorHandle, RecNumber, FieldIdentifier, ValuePtr, BufferLength, StringLengthPtr); return ret; } +SQLRETURN SQL_API SQLSetDescFieldW +( + SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, + SQLSMALLINT FieldIdentifier, + SQLPOINTER Value, + SQLINTEGER BufferLength +) +{ + SQLRETURN ret; + TRACE5(_IN, "pddpd", DescriptorHandle, RecNumber, FieldIdentifier, + Value, BufferLength); + HND_LOCK(DSCH(DescriptorHandle)->hdr.stmt); /* see Note_stmt_sync */ + ret = EsSQLSetDescFieldW(DescriptorHandle, RecNumber, FieldIdentifier, + Value, BufferLength); + HND_UNLOCK(DSCH(DescriptorHandle)->hdr.stmt); + TRACE6(_OUT, "dpddpd", ret, DescriptorHandle, RecNumber, FieldIdentifier, + Value, BufferLength); + return ret; +} + +#if WITH_EMPTY SQLRETURN SQL_API SQLGetDescRecW( SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, @@ -388,43 +441,10 @@ SQLRETURN SQL_API SQLGetDescRecW( _Out_opt_ SQLSMALLINT *NullablePtr) { -#if 0 - SQLRETURN ret; - TRACE11(_IN, "pdpdppppppp", DescriptorHandle, RecNumber, Name, - BufferLength, StringLengthPtr, TypePtr, SubTypePtr, LengthPtr, - PrecisionPtr, ScalePtr, NullablePtr); - ret = EsSQLGetDescRecW(DescriptorHandle, RecNumber, Name, - BufferLength, StringLengthPtr, TypePtr, SubTypePtr, LengthPtr, - PrecisionPtr, ScalePtr, NullablePtr); - TRACE12(_OUT, "dpdWdttttttt", ret, DescriptorHandle, RecNumber, Name, - BufferLength, StringLengthPtr, TypePtr, SubTypePtr, LengthPtr, - PrecisionPtr, ScalePtr, NullablePtr); - return ret; -#else //0 RET_NOT_IMPLEMENTED; -#endif //0 } -SQLRETURN SQL_API SQLSetDescFieldW -( - SQLHDESC DescriptorHandle, - SQLSMALLINT RecNumber, - SQLSMALLINT FieldIdentifier, - SQLPOINTER Value, - SQLINTEGER BufferLength -) -{ - SQLRETURN ret; - TRACE5(_IN, "pddpd", DescriptorHandle, RecNumber, FieldIdentifier, - Value, BufferLength); - ret = EsSQLSetDescFieldW(DescriptorHandle, RecNumber, FieldIdentifier, - Value, BufferLength); - TRACE6(_OUT, "dpddpd", ret, DescriptorHandle, RecNumber, FieldIdentifier, - Value, BufferLength); - return ret; -} - SQLRETURN SQL_API SQLSetDescRec( SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, @@ -437,21 +457,9 @@ SQLRETURN SQL_API SQLSetDescRec( _Inout_opt_ SQLLEN *StringLength, _Inout_opt_ SQLLEN *Indicator) { -#if 0 - SQLRETURN ret; - TRACE10(_IN, "pddddddppp", DescriptorHandle, RecNumber, Type, SubType, - Length, Precision, Scale, Data, StringLength, Indicator); - ret = EsSQLSetDescRec(DescriptorHandle, RecNumber, Type, SubType, - Length, Precision, Scale, Data, StringLength, Indicator); - TRACE11(_OUT, "dpddddddpnn", ret, DescriptorHandle, RecNumber, Type, - SubType, Length, Precision, Scale, Data, StringLength, Indicator); - return ret; -#else //0 RET_NOT_IMPLEMENTED; -#endif //0 } -#if WITH_EMPTY /* * "SQLCopyDesc function is called to copy the fields of one descriptor to * another descriptor. Fields can be copied only to an application descriptor @@ -487,7 +495,9 @@ SQLRETURN SQL_API SQLPrepareW { SQLRETURN ret; TRACE3(_IN, "ppd", hstmt, szSqlStr, cchSqlStr); + HND_LOCK(hstmt); ret = EsSQLPrepareW(hstmt, szSqlStr, cchSqlStr); + HND_UNLOCK(hstmt); TRACE4(_OUT, "dpWd", ret, hstmt, szSqlStr, cchSqlStr); return ret; } @@ -513,8 +523,10 @@ SQLRETURN SQL_API SQLBindParameter( SQLRETURN ret; TRACE10(_IN, "pudddudpdp", hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue); + HND_LOCK(hstmt); ret = EsSQLBindParameter(hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue); + HND_UNLOCK(hstmt); TRACE11(_OUT, "dpudddudpdn", ret, hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue); return ret; @@ -573,10 +585,11 @@ SQLRETURN SQL_API SQLSetScrollOptions( /* Use SQLSetStmtOptions */ */ SQLRETURN SQL_API SQLExecute(SQLHSTMT hstmt) { - // TODO: set .stmt_curs = 0; in resultset SQLRETURN ret; TRACE1(_IN, "p", hstmt); + HND_LOCK(hstmt); ret = EsSQLExecute(hstmt); + HND_UNLOCK(hstmt); TRACE2(_OUT, "dp", ret, hstmt); return ret; } @@ -602,7 +615,9 @@ SQLRETURN SQL_API SQLExecDirectW { SQLRETURN ret; TRACE3(_IN, "ppd", hstmt, szSqlStr, cchSqlStr); + HND_LOCK(hstmt); ret = EsSQLExecDirectW(hstmt, szSqlStr, cchSqlStr); + HND_UNLOCK(hstmt); TRACE4(_OUT, "dpWd", ret, hstmt, szSqlStr, cchSqlStr); return ret; } @@ -652,7 +667,9 @@ SQLRETURN SQL_API SQLNumParams( { SQLRETURN ret; TRACE2(_IN, "pp", hstmt, pcpar); + HND_LOCK(hstmt); ret = EsSQLNumParams(hstmt, pcpar); + HND_UNLOCK(hstmt); TRACE3(_OUT, "dpt", ret, hstmt, pcpar); return ret; } @@ -683,7 +700,9 @@ SQLRETURN SQL_API SQLRowCount(_In_ SQLHSTMT StatementHandle, { SQLRETURN ret; TRACE2(_IN, "pp", StatementHandle, RowCount); + HND_LOCK(StatementHandle); /* see Note_sync */ ret = EsSQLRowCount(StatementHandle, RowCount); + HND_UNLOCK(StatementHandle); TRACE3(_OUT, "dpn", ret, StatementHandle, RowCount); return ret; } @@ -693,7 +712,9 @@ SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT StatementHandle, { SQLRETURN ret; TRACE2(_IN, "pp", StatementHandle, ColumnCount); + HND_LOCK(StatementHandle); /* see Note_sync */ ret = EsSQLNumResultCols(StatementHandle, ColumnCount); + HND_UNLOCK(StatementHandle); TRACE3(_OUT, "dpt", ret, StatementHandle, ColumnCount); return ret; } @@ -721,8 +742,10 @@ SQLRETURN SQL_API SQLDescribeColW SQLRETURN ret; TRACE9(_IN, "pupdppppp", hstmt, icol, szColName, cchColNameMax, pcchColName, pfSqlType, pcbColDef, pibScale, pfNullable); + HND_LOCK(hstmt); ret = EsSQLDescribeColW(hstmt, icol, szColName, cchColNameMax, pcchColName, pfSqlType, pcbColDef, pibScale, pfNullable); + HND_UNLOCK(hstmt); TRACE10(_OUT, "dpuWdttNtt", ret, hstmt, icol, szColName, cchColNameMax, pcchColName, pfSqlType, pcbColDef, pibScale, pfNullable); return ret; @@ -749,8 +772,10 @@ SQLRETURN SQL_API SQLColAttributeW SQLRETURN ret; TRACE7(_IN, "pddpdtp", hstmt, iCol, iField, pCharAttr, cbDescMax, pcbCharAttr, pNumAttr); + HND_LOCK(hstmt); ret = EsSQLColAttributeW(hstmt, iCol, iField, pCharAttr, cbDescMax, pcbCharAttr, pNumAttr); + HND_UNLOCK(hstmt); #ifdef _WIN64 TRACE8(_OUT, "dpddpdtn", ret, hstmt, iCol, iField, pCharAttr, cbDescMax, pcbCharAttr, pNumAttr); @@ -771,8 +796,10 @@ SQLRETURN SQL_API SQLBindCol(SQLHSTMT StatementHandle, SQLRETURN ret; TRACE6(_IN, "pddpdp", StatementHandle, ColumnNumber, TargetType, TargetValue, BufferLength, StrLen_or_Ind); + HND_LOCK(StatementHandle); ret = EsSQLBindCol(StatementHandle, ColumnNumber, TargetType, TargetValue, BufferLength, StrLen_or_Ind); + HND_UNLOCK(StatementHandle); TRACE7(_OUT, "dpddpdn", ret, StatementHandle, ColumnNumber, TargetType, TargetValue, BufferLength, StrLen_or_Ind); return ret; @@ -783,7 +810,9 @@ SQLRETURN SQL_API SQLFetch(SQLHSTMT StatementHandle) { SQLRETURN ret; TRACE1(_IN, "p", StatementHandle); + HND_LOCK(StatementHandle); ret = EsSQLFetch(StatementHandle); + HND_UNLOCK(StatementHandle); TRACE2(_OUT, "dp", ret, StatementHandle); return ret; } @@ -833,8 +862,10 @@ SQLRETURN SQL_API SQLGetData(SQLHSTMT StatementHandle, SQLRETURN ret; TRACE6(_IN, "pHhplp", StatementHandle, ColumnNumber, TargetType, TargetValuePtr, BufferLength, StrLen_or_IndPtr); + HND_LOCK(StatementHandle); ret = EsSQLGetData(StatementHandle, ColumnNumber, TargetType, TargetValuePtr, BufferLength, StrLen_or_IndPtr); + HND_UNLOCK(StatementHandle); TRACE7(_OUT, "dpHhpln", ret, StatementHandle, ColumnNumber, TargetType, TargetValuePtr, BufferLength, StrLen_or_IndPtr); return ret; @@ -848,7 +879,9 @@ SQLRETURN SQL_API SQLSetPos( { SQLRETURN ret; TRACE4(_IN, "puuu", StatementHandle, RowNumber, Operation, LockType); + HND_LOCK(StatementHandle); ret = EsSQLSetPos(StatementHandle, RowNumber, Operation, LockType); + HND_UNLOCK(StatementHandle); TRACE5(_OUT, "dpuuu", ret,StatementHandle, RowNumber, Operation, LockType); return ret; } @@ -859,7 +892,9 @@ SQLRETURN SQL_API SQLBulkOperations( { SQLRETURN ret; TRACE2(_IN, "pd", StatementHandle, Operation); + HND_LOCK(StatementHandle); ret = EsSQLBulkOperations(StatementHandle, Operation); + HND_UNLOCK(StatementHandle); TRACE3(_OUT, "dpd", ret, StatementHandle, Operation); return ret; } @@ -868,6 +903,7 @@ SQLRETURN SQL_API SQLMoreResults(SQLHSTMT StatementHandle) { SQLRETURN ret; TRACE1(_IN, "p", StatementHandle); + /* no synchronization required */ ret = EsSQLMoreResults(StatementHandle); TRACE2(_OUT, "dp", ret, StatementHandle); return ret; @@ -886,8 +922,12 @@ SQLRETURN SQL_API SQLGetDiagFieldW( SQLRETURN ret; TRACE7(_IN, "dpddpdp", HandleType, Handle, RecNumber, DiagIdentifier, DiagInfoPtr, BufferLength, StringLengthPtr); + /* Note_diag: locking here only really makes sense for stmt and dbc, but + * uniformly locking env and desc too is harmless and simple */ + HND_LOCK(Handle); ret = EsSQLGetDiagFieldW(HandleType, Handle, RecNumber, DiagIdentifier, DiagInfoPtr, BufferLength, StringLengthPtr); + HND_UNLOCK(Handle); TRACE8(_OUT, "ddpddpdt", ret, HandleType, Handle, RecNumber, DiagIdentifier, DiagInfoPtr, BufferLength, StringLengthPtr); return ret; @@ -908,8 +948,10 @@ SQLRETURN SQL_API SQLGetDiagRecW SQLRETURN ret; TRACE8(_IN, "dpdpppdp", HandleType, Handle, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength); + HND_LOCK(Handle); /* see Note_diag */ ret = EsSQLGetDiagRecW(HandleType, Handle, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength); + HND_UNLOCK(Handle); TRACE9(_OUT, "ddpdWgWdt", ret, HandleType, Handle, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength); return ret; @@ -956,9 +998,11 @@ SQLRETURN SQL_API SQLColumnsW TRACE9(_IN, "ppdpdpdpd", hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, szColumnName, cchColumnName); + HND_LOCK(hstmt); ret = EsSQLColumnsW(hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, szColumnName, cchColumnName); + HND_UNLOCK(hstmt); TRACE10(_OUT, "dpWdWdWdWd", ret, hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, szColumnName, cchColumnName); @@ -990,6 +1034,7 @@ SQLRETURN SQL_API SQLForeignKeysW szFkCatalogName, cchFkCatalogName, szFkSchemaName, cchFkSchemaName, szFkTableName, cchFkTableName); + HND_LOCK(hstmt); ret = EsSQLForeignKeysW(hstmt, szPkCatalogName, cchPkCatalogName, szPkSchemaName, cchPkSchemaName, @@ -997,6 +1042,7 @@ SQLRETURN SQL_API SQLForeignKeysW szFkCatalogName, cchFkCatalogName, szFkSchemaName, cchFkSchemaName, szFkTableName, cchFkTableName); + HND_UNLOCK(hstmt); TRACE14(_OUT, "dpWdWdWdWdWdWd", ret, hstmt, szPkCatalogName, cchPkCatalogName, szPkSchemaName, cchPkSchemaName, @@ -1024,10 +1070,12 @@ SQLRETURN SQL_API SQLPrimaryKeysW szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName); + HND_LOCK(hstmt); ret = EsSQLPrimaryKeysW(hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName); + HND_UNLOCK(hstmt); TRACE8(_OUT, "dpWdWdWd", ret, hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, @@ -1085,9 +1133,11 @@ SQLRETURN SQL_API SQLSpecialColumnsW TRACE10(_IN, "pupdpdpduu", hstmt, fColType, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, fScope, fNullable); + HND_LOCK(hstmt); ret = EsSQLSpecialColumnsW(hstmt, fColType, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, fScope, fNullable); + HND_UNLOCK(hstmt); TRACE11(_OUT, "dpuWdWdWduu", ret, hstmt, fColType, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, fScope, fNullable); @@ -1144,9 +1194,11 @@ SQLRETURN SQL_API SQLTablesW TRACE9(_IN, "ppdpdpdpd", hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, szTableType, cchTableType); + HND_LOCK(hstmt); ret = EsSQLTablesW(hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, szTableType, cchTableType); + HND_UNLOCK(hstmt); TRACE10(_OUT, "dpWdWdWdWd", ret, hstmt, szCatalogName, cchCatalogName, szSchemaName, cchSchemaName, szTableName, cchTableName, szTableType, cchTableType); @@ -1164,7 +1216,9 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT StatementHandle, SQLUSMALLINT Option) { SQLRETURN ret; TRACE2(_IN, "pd", StatementHandle, Option); + HND_LOCK(StatementHandle); ret = EsSQLFreeStmt(StatementHandle, Option); + HND_UNLOCK(StatementHandle); TRACE3(_OUT, "dpd", ret, StatementHandle, Option); return ret; } @@ -1173,30 +1227,42 @@ SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT StatementHandle) { SQLRETURN ret; TRACE1(_IN, "p", StatementHandle); + HND_LOCK(StatementHandle); ret = EsSQLCloseCursor(StatementHandle); - TRACE2(_OUT, "dpd", ret, StatementHandle); + HND_UNLOCK(StatementHandle); + TRACE2(_OUT, "dp", ret, StatementHandle); return ret; } -#if WITH_EMPTY - SQLRETURN SQL_API SQLCancel(SQLHSTMT StatementHandle) { - RET_NOT_IMPLEMENTED; + SQLRETURN ret; + TRACE1(_IN, "p", StatementHandle); + HND_LOCK(StatementHandle); + ret = EsSQLCancel(StatementHandle); + HND_UNLOCK(StatementHandle); + TRACE2(_OUT, "dp", ret, StatementHandle); + return ret; } SQLRETURN SQL_API SQLCancelHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle) { - RET_NOT_IMPLEMENTED; + SQLRETURN ret; + TRACE2(_IN, "hp", HandleType, InputHandle); + HND_LOCK(InputHandle); + ret = EsSQLCancelHandle(HandleType, InputHandle); + HND_UNLOCK(InputHandle); + TRACE3(_IN, "dhp", ret, HandleType, InputHandle); + return ret; } +#if WITH_EMPTY SQLRETURN SQL_API SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT CompletionType) { RET_NOT_IMPLEMENTED; } - #endif /* WITH_EMPTY */ @@ -1209,7 +1275,9 @@ SQLRETURN SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) { SQLRETURN ret; TRACE1(_IN, "p", ConnectionHandle); + HND_LOCK(ConnectionHandle); ret = EsSQLDisconnect(ConnectionHandle); + HND_UNLOCK(ConnectionHandle); TRACE2(_OUT, "dp", ret, ConnectionHandle); return ret; } @@ -1218,126 +1286,14 @@ SQLRETURN SQL_API SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) { SQLRETURN ret; TRACE2(_IN, "dp", HandleType, Handle); + if (! HND_TRYLOCK(Handle)) { + BUGH(Handle, "handle still locked while freeing attempt."); + return SQL_ERROR; + } ret = EsSQLFreeHandle(HandleType, Handle); TRACE3(_OUT, "ddp", ret, HandleType, Handle); return ret; } -#if 0 -// API - -SQLAllocHandle -SQLConnect -SQLDriverConnect -SQLBrowseConnect - -SQLDataSources -SQLDrivers -SQLGetInfo -SQLGetFunctions -SQLGetTypeInfo - -SQLSetConnectAttr -SQLGetConnectAttr -SQLSetEnvAttr -SQLGetEnvAttr -SQLSetStmtAttr -SQLGetStmtAttr - -SQLGetDescField -SQLGetDescRec -SQLSetDescField -SQLSetDescRec -SQLCopyDesc -SQLPrepare -SQLBindParameter -SQLGetCursorName -SQLSetCursorName -SQLSetScrollOptions - -SQLExecute -SQLExecDirect -SQLNativeSql -SQLDescribeParam -SQLNumParams -SQLParamData -SQLPutData - -SQLRowCount -SQLNumResultCols -SQLDescribeCol -SQLColAttribute -SQLBindCol -SQLFetch -SQLFetchScroll -SQLGetData -SQLSetPos -SQLBulkOperations -SQLMoreResults -SQLGetDiagField -SQLGetDiagRec - -SQLColumnPrivileges -SQLColumns -SQLForeignKeys -SQLPrimaryKeys -SQLProcedureColumns -SQLProcedures -SQLSpecialColumns -SQLStatistics -SQLTablePrivileges -SQLTables - -SQLFreeStmt -SQLCloseCursor -SQLCancel -SQLCancelHandle -SQLEndTran - -SQLDisconnect -SQLFreeHandle -#endif - -#if 0 -//ANSI / Unicode - -SQLBrowseConnect -SQLColAttribute -SQLColAttributes -SQLColumnPrivileges -SQLColumns -SQLConnect -SQLDataSources -SQLDescribeCol -SQLDriverConnect -SQLDrivers -SQLError -SQLExecDirect -SQLForeignKeys -SQLGetConnectAttr -SQLGetConnectOption -SQLGetCursorName -SQLGetDescField -SQLGetDescRec -SQLGetDiagField -SQLGetDiagRec -SQLGetInfo -SQLGetStmtAttr -SQLNativeSQL -SQLPrepare -SQLPrimaryKeys -SQLProcedureColumns -SQLProcedures -SQLSetConnectAttr -SQLSetConnectOption -SQLSetCursorName -SQLSetDescField -SQLSetStmtAttr -SQLSpecialColumns -SQLStatistics -SQLTablePrivileges -SQLTables -#endif - /* vim: set noet fenc=utf-8 ff=dos sts=0 sw=4 ts=4 : */ diff --git a/driver/queries.c b/driver/queries.c index 2b526c77..429950cb 100644 --- a/driver/queries.c +++ b/driver/queries.c @@ -1180,6 +1180,32 @@ SQLRETURN EsSQLCloseCursor(SQLHSTMT StatementHandle) return EsSQLFreeStmt(StatementHandle, SQL_CLOSE); } +SQLRETURN EsSQLCancel(SQLHSTMT StatementHandle) +{ + esodbc_stmt_st *stmt = STMH(StatementHandle); + + /* + * Use cases: + * - "A function running asynchronously on the statement.": no async + * support. + * - "A function on a statement that needs data." TODO: if data-at-exec. + * - "A function running on the statement on another thread.": this could + * theoretically cancel an ongoing fetch/connect/etc. For now libcurl is + * left to timeout -- TODO: if swiching to "multi" API in libcurl. + * XXX: for this last case: stmt lock is being held here. + */ + + DBGH(stmt, "canceling current statement operation -- NOOP."); + return SQL_SUCCESS; +} + +SQLRETURN EsSQLCancelHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle) +{ + /* see EsSQLCancel() */ + DBGH(InputHandle, "canceling current handle operation -- NOOP."); + return SQL_SUCCESS; +} + SQLRETURN EsSQLNumResultCols(SQLHSTMT StatementHandle, _Out_ SQLSMALLINT *ColumnCount) { diff --git a/driver/queries.h b/driver/queries.h index ea018450..becfeab6 100644 --- a/driver/queries.h +++ b/driver/queries.h @@ -45,6 +45,8 @@ SQLRETURN EsSQLBulkOperations( SQLSMALLINT Operation); SQLRETURN EsSQLMoreResults(SQLHSTMT hstmt); SQLRETURN EsSQLCloseCursor(SQLHSTMT StatementHandle); +SQLRETURN EsSQLCancel(SQLHSTMT StatementHandle); +SQLRETURN EsSQLCancelHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle); SQLRETURN EsSQLNumResultCols(SQLHSTMT StatementHandle, _Out_ SQLSMALLINT *ColumnCount); diff --git a/driver/util.h b/driver/util.h index 9efd0c05..781dd171 100644 --- a/driver/util.h +++ b/driver/util.h @@ -172,7 +172,22 @@ size_t ui64tot(uint64_t ui64, void *buff, BOOL wide); (GetLastError() == ERROR_INSUFFICIENT_BUFFER) #define WCS2U8_ERRNO() GetLastError() + +/* + * Locking type and primitives. + */ +typedef SRWLOCK esodbc_mutex_lt; + +#define ESODBC_MUX_SINIT SRWLOCK_INIT +#define ESODBC_MUX_INIT(_m) InitializeSRWLock(_m) +#define ESODBC_MUX_DEL(_m) /* not needed/possible */ + +#define ESODBC_MUX_LOCK(_m) AcquireSRWLockExclusive(_m) +#define ESODBC_MUX_TRYLOCK(_m) TryAcquireSRWLockExclusive(_m) +#define ESODBC_MUX_UNLOCK(_m) ReleaseSRWLockExclusive(_m) + #else /* _WIN32 */ + #error "unsupported platform" /* TODO */ /* "[R]eturns the number of bytes written into the multibyte output * string, excluding the terminating NULL (if any)". Copies until \0 is From bca34f4f622eac1291932a2b7fb34424b8581cca Mon Sep 17 00:00:00 2001 From: Bogdan Pintea Date: Tue, 28 Aug 2018 16:47:29 +0200 Subject: [PATCH 4/4] message typo fix s/dettaching/detaching/ --- driver/odbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/odbc.c b/driver/odbc.c index 84a7a11b..3f64ad98 100644 --- a/driver/odbc.c +++ b/driver/odbc.c @@ -71,7 +71,7 @@ BOOL WINAPI DllMain( // Perform any necessary cleanup. case DLL_PROCESS_DETACH: - INFO("process %u dettaching.", GetCurrentProcessId()); + INFO("process %u detaching.", GetCurrentProcessId()); driver_cleanup(); break; }