mirror of
https://github.com/mdbtools/mdbtools.git
synced 2026-02-25 21:26:41 +08:00
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:
@@ -121,7 +121,7 @@ typedef struct GOptionContext {
|
|||||||
/* string functions */
|
/* string functions */
|
||||||
void *g_memdup(const void *src, size_t len);
|
void *g_memdup(const void *src, size_t len);
|
||||||
int g_str_equal(const void *str1, const void *str2);
|
int g_str_equal(const void *str1, const void *str2);
|
||||||
char **g_strsplit(const char *haystack, const char *needle, int something);
|
char **g_strsplit(const char *haystack, const char *needle, int max_tokens);
|
||||||
void g_strfreev(char **dir);
|
void g_strfreev(char **dir);
|
||||||
char *g_strconcat(const char *first, ...);
|
char *g_strconcat(const char *first, ...);
|
||||||
char *g_strdup(const char *src);
|
char *g_strdup(const char *src);
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ int g_str_equal(const void *str1, const void *str2) {
|
|||||||
return strcmp(str1, str2) == 0;
|
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 **ret = NULL;
|
||||||
char *found = NULL;
|
char *found = NULL;
|
||||||
size_t components = 2; // last component + terminating NULL
|
size_t components = 2; // last component + terminating NULL
|
||||||
|
|||||||
@@ -43,9 +43,6 @@
|
|||||||
#define FILENAME_MAX 512
|
#define FILENAME_MAX 512
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define max_line 256
|
|
||||||
static char line[max_line];
|
|
||||||
|
|
||||||
static guint HashFunction (gconstpointer key);
|
static guint HashFunction (gconstpointer key);
|
||||||
|
|
||||||
static void visit (gpointer key, gpointer value, gpointer user_data);
|
static void visit (gpointer key, gpointer value, gpointer user_data);
|
||||||
@@ -224,17 +221,12 @@ gchar* ExtractDSN (ConnectParams* params, const gchar* connectString)
|
|||||||
q++;
|
q++;
|
||||||
while (isspace(*q))
|
while (isspace(*q))
|
||||||
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
|
* 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;
|
return params->dsnName->str;
|
||||||
}
|
}
|
||||||
@@ -261,17 +253,12 @@ gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString)
|
|||||||
q++;
|
q++;
|
||||||
while (isspace(*q))
|
while (isspace(*q))
|
||||||
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
|
* 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;
|
return params->dsnName->str;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ struct _hdbc {
|
|||||||
MdbSQL *sqlconn;
|
MdbSQL *sqlconn;
|
||||||
ConnectParams* params;
|
ConnectParams* params;
|
||||||
GPtrArray *statements;
|
GPtrArray *statements;
|
||||||
|
#ifdef ENABLE_ODBC_W
|
||||||
|
iconv_t iconv_in;
|
||||||
|
iconv_t iconv_out;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
struct _hstmt {
|
struct _hstmt {
|
||||||
MdbSQL *sql;
|
MdbSQL *sql;
|
||||||
|
|||||||
@@ -31,10 +31,6 @@
|
|||||||
//#define TRACE(x) fprintf(stderr,"Function %s\n", x);
|
//#define TRACE(x) fprintf(stderr,"Function %s\n", x);
|
||||||
#define TRACE(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 SQLSMALLINT _odbc_get_client_type(MdbColumn *col);
|
||||||
static const char * _odbc_get_client_type_name(MdbColumn *col);
|
static const char * _odbc_get_client_type_name(MdbColumn *col);
|
||||||
static int _odbc_fix_literals(struct _hstmt *stmt);
|
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)
|
#define MIN(a,b) (a>b ? b : a)
|
||||||
#endif
|
#endif
|
||||||
#define _MAX_ERROR_LEN 255
|
#define _MAX_ERROR_LEN 255
|
||||||
static char lastError[_MAX_ERROR_LEN+1];
|
static __thread char lastError[_MAX_ERROR_LEN+1];
|
||||||
static char sqlState[6];
|
static __thread char sqlState[6];
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SQLCHAR *type_name;
|
SQLCHAR *type_name;
|
||||||
@@ -94,11 +90,9 @@ TypeInfo type_info[] = {
|
|||||||
#define MAX_TYPE_INFO 11
|
#define MAX_TYPE_INFO 11
|
||||||
|
|
||||||
#ifdef ENABLE_ODBC_W
|
#ifdef ENABLE_ODBC_W
|
||||||
void my_fini(void);
|
static void _init_iconv(struct _hdbc* dbc) {
|
||||||
|
|
||||||
MDB_CONSTRUCTOR(my_init)
|
|
||||||
{
|
{
|
||||||
TRACE("my_init");
|
TRACE("_init_iconv");
|
||||||
int endian = 1;
|
int endian = 1;
|
||||||
const char* wcharset;
|
const char* wcharset;
|
||||||
if (sizeof(SQLWCHAR) == 2)
|
if (sizeof(SQLWCHAR) == 2)
|
||||||
@@ -113,26 +107,16 @@ MDB_CONSTRUCTOR(my_init)
|
|||||||
wcharset = "UCS-4BE";
|
wcharset = "UCS-4BE";
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Unsupported SQLWCHAR width %zd\n", sizeof(SQLWCHAR));
|
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");
|
TRACE("_free_iconv");
|
||||||
if(iconv_out != (iconv_t)-1)iconv_close(iconv_out);
|
if(dbc->iconv_out != (iconv_t)-1)iconv_close(dbc->iconv_out);
|
||||||
if(iconv_in != (iconv_t)-1)iconv_close(iconv_in);
|
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){
|
static int unicode2ascii(char *_in, size_t *_lin, char *_out, size_t *_lout){
|
||||||
@@ -500,6 +484,9 @@ struct _hdbc* dbc;
|
|||||||
dbc->params = NewConnectParams ();
|
dbc->params = NewConnectParams ();
|
||||||
dbc->statements = g_ptr_array_new();
|
dbc->statements = g_ptr_array_new();
|
||||||
dbc->sqlconn = mdb_sql_init();
|
dbc->sqlconn = mdb_sql_init();
|
||||||
|
#ifdef ENABLE_ODBC_W
|
||||||
|
_init_iconv(dbc);
|
||||||
|
#endif
|
||||||
*phdbc=dbc;
|
*phdbc=dbc;
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
@@ -1115,6 +1102,9 @@ SQLRETURN SQL_API SQLFreeConnect(
|
|||||||
FreeConnectParams(dbc->params);
|
FreeConnectParams(dbc->params);
|
||||||
g_ptr_array_free(dbc->statements, TRUE);
|
g_ptr_array_free(dbc->statements, TRUE);
|
||||||
mdb_sql_exit(dbc->sqlconn);
|
mdb_sql_exit(dbc->sqlconn);
|
||||||
|
#ifdef ENABLE_ODBC_W
|
||||||
|
_free_iconv(dbc);
|
||||||
|
#endif
|
||||||
g_free(dbc);
|
g_free(dbc);
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
|
|||||||
Reference in New Issue
Block a user