Attempt to make the ODBC driver thread-safe

I'm not sure if this is a complete solution - some of the global state
has been moved to thread-local storage. So passing an ODBC handle across
threads may have unexpected results. But at least it's not global state.

Each ODBC handle now has its own iconv_t object.

See #23
This commit is contained in:
Evan Miller
2020-08-19 15:35:02 -04:00
parent 1ad0dd2d8b
commit 9020ca9a1e
5 changed files with 29 additions and 47 deletions

View File

@@ -22,7 +22,8 @@ int g_str_equal(const void *str1, const void *str2) {
return strcmp(str1, str2) == 0;
}
char **g_strsplit(const char *haystack, const char *needle, int something) {
// max_tokens not yet implemented
char **g_strsplit(const char *haystack, const char *needle, int max_tokens) {
char **ret = NULL;
char *found = NULL;
size_t components = 2; // last component + terminating NULL

View File

@@ -43,9 +43,6 @@
#define FILENAME_MAX 512
#endif
#define max_line 256
static char line[max_line];
static guint HashFunction (gconstpointer key);
static void visit (gpointer key, gpointer value, gpointer user_data);
@@ -224,17 +221,12 @@ gchar* ExtractDSN (ConnectParams* params, const gchar* connectString)
q++;
while (isspace(*q))
q++;
/*
* Copy the DSN value to a buffer
*/
s = line;
while (*q && *q != ';')
*s++ = *q++;
*s = '\0';
/*
* Save it as a string in the params object
*/
params->dsnName = g_string_assign (params->dsnName, line);
char **components = g_strsplit(q, ";", 2);
params->dsnName = g_string_assign(params->dsnName, components[0]);
g_strfreev(components);
return params->dsnName->str;
}
@@ -261,17 +253,12 @@ gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString)
q++;
while (isspace(*q))
q++;
/*
* Copy the DSN value to a buffer
*/
s = line;
while (*q && *q != ';')
*s++ = *q++;
*s = '\0';
/*
* Save it as a string in the params object
*/
params->dsnName = g_string_assign (params->dsnName, line);
char **components = g_strsplit(q, ";", 2);
params->dsnName = g_string_assign(params->dsnName, components[0]);
g_strfreev(components);
return params->dsnName->str;
}

View File

@@ -43,6 +43,10 @@ struct _hdbc {
MdbSQL *sqlconn;
ConnectParams* params;
GPtrArray *statements;
#ifdef ENABLE_ODBC_W
iconv_t iconv_in;
iconv_t iconv_out;
#endif
};
struct _hstmt {
MdbSQL *sql;

View File

@@ -31,10 +31,6 @@
//#define TRACE(x) fprintf(stderr,"Function %s\n", x);
#define TRACE(x)
#ifdef ENABLE_ODBC_W
static iconv_t iconv_in,iconv_out;
#endif //ENABLE_ODBC_W
static SQLSMALLINT _odbc_get_client_type(MdbColumn *col);
static const char * _odbc_get_client_type_name(MdbColumn *col);
static int _odbc_fix_literals(struct _hstmt *stmt);
@@ -50,8 +46,8 @@ static void unbind_columns (struct _hstmt*);
#define MIN(a,b) (a>b ? b : a)
#endif
#define _MAX_ERROR_LEN 255
static char lastError[_MAX_ERROR_LEN+1];
static char sqlState[6];
static __thread char lastError[_MAX_ERROR_LEN+1];
static __thread char sqlState[6];
typedef struct {
SQLCHAR *type_name;
@@ -94,11 +90,9 @@ TypeInfo type_info[] = {
#define MAX_TYPE_INFO 11
#ifdef ENABLE_ODBC_W
void my_fini(void);
MDB_CONSTRUCTOR(my_init)
static void _init_iconv(struct _hdbc* dbc) {
{
TRACE("my_init");
TRACE("_init_iconv");
int endian = 1;
const char* wcharset;
if (sizeof(SQLWCHAR) == 2)
@@ -113,26 +107,16 @@ MDB_CONSTRUCTOR(my_init)
wcharset = "UCS-4BE";
else
fprintf(stderr, "Unsupported SQLWCHAR width %zd\n", sizeof(SQLWCHAR));
//fprintf(stderr,"charset %s\n", wcharset);
//fprintf(stderr, "SQLWCHAR width %d\n", sizeof(SQLWCHAR));
/*
#if __SIZEOF_WCHAR_T__ == 4 || __WCHAR_MAX__ > 0x10000
#define WCHAR_CHARSET "UCS-4LE"
#else
#define WCHAR_CHARSET "UCS-2LE"
#endif
*/
iconv_out = iconv_open(wcharset, "UTF-8");
iconv_in = iconv_open("UTF-8", wcharset);
atexit(my_fini);
dbc->iconv_out = iconv_open(wcharset, "UTF-8");
dbc->iconv_in = iconv_open("UTF-8", wcharset);
}
void my_fini()
static void _free_iconv(struct _hdbc *dbc)
{
TRACE("my_fini");
if(iconv_out != (iconv_t)-1)iconv_close(iconv_out);
if(iconv_in != (iconv_t)-1)iconv_close(iconv_in);
TRACE("_free_iconv");
if(dbc->iconv_out != (iconv_t)-1)iconv_close(dbc->iconv_out);
if(dbc->iconv_in != (iconv_t)-1)iconv_close(dbc->iconv_in);
}
static int unicode2ascii(char *_in, size_t *_lin, char *_out, size_t *_lout){
@@ -500,6 +484,9 @@ struct _hdbc* dbc;
dbc->params = NewConnectParams ();
dbc->statements = g_ptr_array_new();
dbc->sqlconn = mdb_sql_init();
#ifdef ENABLE_ODBC_W
_init_iconv(dbc);
#endif
*phdbc=dbc;
return SQL_SUCCESS;
@@ -1115,6 +1102,9 @@ SQLRETURN SQL_API SQLFreeConnect(
FreeConnectParams(dbc->params);
g_ptr_array_free(dbc->statements, TRUE);
mdb_sql_exit(dbc->sqlconn);
#ifdef ENABLE_ODBC_W
_free_iconv(dbc);
#endif
g_free(dbc);
return SQL_SUCCESS;