mirror of
https://github.com/mdbtools/mdbtools.git
synced 2026-01-21 18:48:34 +08:00
Merge pull request #24 from evanmiller/odbc-thread-safety
Make the ODBC driver thread-safe. Multiple simultaneous handles should work fine now, but individual handles should only be used by one thread at at time.
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);
|
||||||
@@ -204,7 +201,7 @@ void DumpParams (ConnectParams* params, FILE* output)
|
|||||||
|
|
||||||
gchar* ExtractDSN (ConnectParams* params, const gchar* connectString)
|
gchar* ExtractDSN (ConnectParams* params, const gchar* connectString)
|
||||||
{
|
{
|
||||||
char *p, *q, *s;
|
char *p, *q;
|
||||||
|
|
||||||
if (!params)
|
if (!params)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -224,24 +221,19 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString)
|
gchar* ExtractDBQ (ConnectParams* params, const gchar* connectString)
|
||||||
{
|
{
|
||||||
char *p, *q, *s;
|
char *p, *q;
|
||||||
|
|
||||||
if (!params)
|
if (!params)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,12 +37,19 @@ extern "C" {
|
|||||||
|
|
||||||
struct _henv {
|
struct _henv {
|
||||||
GPtrArray *connections;
|
GPtrArray *connections;
|
||||||
|
char sqlState[6];
|
||||||
};
|
};
|
||||||
struct _hdbc {
|
struct _hdbc {
|
||||||
struct _henv *henv;
|
struct _henv *henv;
|
||||||
MdbSQL *sqlconn;
|
MdbSQL *sqlconn;
|
||||||
ConnectParams* params;
|
ConnectParams* params;
|
||||||
GPtrArray *statements;
|
GPtrArray *statements;
|
||||||
|
char lastError[256];
|
||||||
|
char sqlState[6];
|
||||||
|
#ifdef ENABLE_ODBC_W
|
||||||
|
iconv_t iconv_in;
|
||||||
|
iconv_t iconv_out;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
struct _hstmt {
|
struct _hstmt {
|
||||||
MdbSQL *sql;
|
MdbSQL *sql;
|
||||||
@@ -51,6 +58,10 @@ struct _hstmt {
|
|||||||
* please make dynamic before checking in
|
* please make dynamic before checking in
|
||||||
*/
|
*/
|
||||||
char query[4096];
|
char query[4096];
|
||||||
|
char lastError[256];
|
||||||
|
char sqlState[6];
|
||||||
|
char *ole_str;
|
||||||
|
size_t ole_len;
|
||||||
struct _sql_bind_info *bind_head;
|
struct _sql_bind_info *bind_head;
|
||||||
int rows_affected;
|
int rows_affected;
|
||||||
int icol; /* SQLGetData: last column */
|
int icol; /* SQLGetData: last column */
|
||||||
|
|||||||
285
src/odbc/odbc.c
285
src/odbc/odbc.c
@@ -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);
|
||||||
@@ -46,13 +42,6 @@ static void unbind_columns (struct _hstmt*);
|
|||||||
|
|
||||||
#define FILL_FIELD(f,v,s) mdb_fill_temp_field(f,v,s,0,0,0,0)
|
#define FILL_FIELD(f,v,s) mdb_fill_temp_field(f,v,s,0,0,0,0)
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#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];
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SQLCHAR *type_name;
|
SQLCHAR *type_name;
|
||||||
SQLSMALLINT data_type;
|
SQLSMALLINT data_type;
|
||||||
@@ -94,11 +83,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,43 +100,33 @@ 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(struct _hdbc* dbc, char *_in, size_t *_lin, char *_out, size_t *_lout){
|
||||||
char *in=_in, *out=_out;
|
char *in=_in, *out=_out;
|
||||||
size_t lin=*_lin, lout=*_lout;
|
size_t lin=*_lin, lout=*_lout;
|
||||||
int ret = iconv(iconv_in, &in, &lin, &out, &lout);
|
int ret = iconv(dbc->iconv_in, &in, &lin, &out, &lout);
|
||||||
*_lin -= lin;
|
*_lin -= lin;
|
||||||
*_lout -= lout;
|
*_lout -= lout;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ascii2unicode(char *_in, size_t *_lin, char *_out, size_t *_lout){
|
static int ascii2unicode(struct _hdbc* dbc, char *_in, size_t *_lin, char *_out, size_t *_lout){
|
||||||
//fprintf(stderr,"ascii2unicode %08x %08x %08x %08x\n",_in,_lin,_out,_lout);
|
//fprintf(stderr,"ascii2unicode %08x %08x %08x %08x\n",_in,_lin,_out,_lout);
|
||||||
char *in=_in, *out=_out;
|
char *in=_in, *out=_out;
|
||||||
size_t lin=*_lin, lout=*_lout;
|
size_t lin=*_lin, lout=*_lout;
|
||||||
//fprintf(stderr,"ascii2unicode %zd %zd\n",lin,lout);
|
//fprintf(stderr,"ascii2unicode %zd %zd\n",lin,lout);
|
||||||
int ret = iconv(iconv_out, &in, &lin, &out, &lout);
|
int ret = iconv(dbc->iconv_out, &in, &lin, &out, &lout);
|
||||||
*_lin -= lin;
|
*_lin -= lin;
|
||||||
*_lout -= lout;
|
*_lout -= lout;
|
||||||
return ret;
|
return ret;
|
||||||
@@ -163,18 +140,19 @@ static int sqlwlen(SQLWCHAR *p){
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_ODBC_W
|
#endif // ENABLE_ODBC_W
|
||||||
|
|
||||||
/* The SQL engine is presently non-reenterrant and non-thread safe.
|
static void LogHandleError(struct _hdbc* dbc, const char* format, ...)
|
||||||
See SQLExecute for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void LogError (const char* format, ...)
|
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Someday, I might make this store more than one error.
|
|
||||||
*/
|
|
||||||
va_list argp;
|
va_list argp;
|
||||||
va_start(argp, format);
|
va_start(argp, format);
|
||||||
vsnprintf(lastError, _MAX_ERROR_LEN, format, argp);
|
vsnprintf(dbc->lastError, sizeof(dbc->lastError), format, argp);
|
||||||
|
va_end(argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogStatementError(struct _hstmt* stmt, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list argp;
|
||||||
|
va_start(argp, format);
|
||||||
|
vsnprintf(stmt->lastError, sizeof(stmt->lastError), format, argp);
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,14 +183,14 @@ SQLRETURN SQL_API SQLDriverConnect(
|
|||||||
SQLRETURN ret;
|
SQLRETURN ret;
|
||||||
|
|
||||||
TRACE("SQLDriverConnect");
|
TRACE("SQLDriverConnect");
|
||||||
strcpy (lastError, "");
|
strcpy(((struct _hdbc*)hdbc)->lastError, "");
|
||||||
|
|
||||||
params = ((struct _hdbc*) hdbc)->params;
|
params = ((struct _hdbc*) hdbc)->params;
|
||||||
|
|
||||||
if (ExtractDSN(params, (gchar*)szConnStrIn)) {
|
if (ExtractDSN(params, (gchar*)szConnStrIn)) {
|
||||||
SetConnectString (params, (gchar*)szConnStrIn);
|
SetConnectString (params, (gchar*)szConnStrIn);
|
||||||
if (!(database = GetConnectParam (params, "Database"))){
|
if (!(database = GetConnectParam (params, "Database"))){
|
||||||
LogError ("Could not find Database parameter in '%s'", szConnStrIn);
|
LogHandleError(hdbc, "Could not find Database parameter in '%s'", szConnStrIn);
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
ret = do_connect (hdbc, database);
|
ret = do_connect (hdbc, database);
|
||||||
@@ -222,7 +200,7 @@ SQLRETURN SQL_API SQLDriverConnect(
|
|||||||
ret = do_connect (hdbc, database);
|
ret = do_connect (hdbc, database);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
LogError ("Could not find DSN nor DBQ in connect string '%s'", szConnStrIn);
|
LogHandleError(hdbc, "Could not find DSN nor DBQ in connect string '%s'", szConnStrIn);
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +221,7 @@ SQLRETURN SQL_API SQLDriverConnectW(
|
|||||||
size_t l = cbConnStrIn*sizeof(SQLWCHAR), z = (cbConnStrIn+1)*3;
|
size_t l = cbConnStrIn*sizeof(SQLWCHAR), z = (cbConnStrIn+1)*3;
|
||||||
SQLCHAR *tmp = malloc(z);
|
SQLCHAR *tmp = malloc(z);
|
||||||
SQLRETURN ret;
|
SQLRETURN ret;
|
||||||
unicode2ascii((char*)szConnStrIn, &l, (char*)tmp, &z);
|
unicode2ascii((struct _hdbc *)hdbc, (char*)szConnStrIn, &l, (char*)tmp, &z);
|
||||||
tmp[z] = 0;
|
tmp[z] = 0;
|
||||||
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
|
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
@@ -306,7 +284,7 @@ SQLRETURN SQL_API SQLExtendedFetch(
|
|||||||
|
|
||||||
TRACE("SQLExtendedFetch");
|
TRACE("SQLExtendedFetch");
|
||||||
if (fFetchType!=SQL_FETCH_NEXT) {
|
if (fFetchType!=SQL_FETCH_NEXT) {
|
||||||
LogError("Fetch type not supported in SQLExtendedFetch");
|
LogStatementError(stmt, "Fetch type not supported in SQLExtendedFetch");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (pcrow)
|
if (pcrow)
|
||||||
@@ -500,6 +478,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;
|
||||||
@@ -628,7 +609,7 @@ SQLRETURN SQL_API SQLConnect(
|
|||||||
SQLRETURN ret;
|
SQLRETURN ret;
|
||||||
|
|
||||||
TRACE("SQLConnect");
|
TRACE("SQLConnect");
|
||||||
strcpy (lastError, "");
|
strcpy(((struct _hdbc*)hdbc)->lastError, "");
|
||||||
|
|
||||||
params = ((struct _hdbc*) hdbc)->params;
|
params = ((struct _hdbc*) hdbc)->params;
|
||||||
|
|
||||||
@@ -636,7 +617,7 @@ SQLRETURN SQL_API SQLConnect(
|
|||||||
|
|
||||||
if (!(database = GetConnectParam (params, "Database")))
|
if (!(database = GetConnectParam (params, "Database")))
|
||||||
{
|
{
|
||||||
LogError ("Could not find Database parameter in '%s'", szDSN);
|
LogHandleError(hdbc, "Could not find Database parameter in '%s'", szDSN);
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,9 +645,9 @@ SQLRETURN SQL_API SQLConnectW(
|
|||||||
size_t l2=cbUID*4,z2=cbUID*2;
|
size_t l2=cbUID*4,z2=cbUID*2;
|
||||||
size_t l3=cbAuthStr*4,z3=cbAuthStr*2;
|
size_t l3=cbAuthStr*4,z3=cbAuthStr*2;
|
||||||
SQLRETURN ret;
|
SQLRETURN ret;
|
||||||
unicode2ascii((char*)szDSN, &z1, (char*)tmp1, &l1);
|
unicode2ascii((struct _hdbc *)hdbc, (char*)szDSN, &z1, (char*)tmp1, &l1);
|
||||||
unicode2ascii((char*)szUID, &z2, (char*)tmp2, &l2);
|
unicode2ascii((struct _hdbc *)hdbc, (char*)szUID, &z2, (char*)tmp2, &l2);
|
||||||
unicode2ascii((char*)szAuthStr, &z3, (char*)tmp3, &l3);
|
unicode2ascii((struct _hdbc *)hdbc, (char*)szAuthStr, &z3, (char*)tmp3, &l3);
|
||||||
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
|
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
|
||||||
free(tmp1),free(tmp2),free(tmp3);
|
free(tmp1),free(tmp2),free(tmp3);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -695,7 +676,7 @@ SQLRETURN SQL_API SQLDescribeCol(
|
|||||||
|
|
||||||
TRACE("SQLDescribeCol");
|
TRACE("SQLDescribeCol");
|
||||||
if (icol<1 || icol>sql->num_columns) {
|
if (icol<1 || icol>sql->num_columns) {
|
||||||
strcpy(sqlState, "07009"); // Invalid descriptor index
|
strcpy(stmt->sqlState, "07009"); // Invalid descriptor index
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
sqlcol = g_ptr_array_index(sql->columns,icol - 1);
|
sqlcol = g_ptr_array_index(sql->columns,icol - 1);
|
||||||
@@ -708,7 +689,7 @@ SQLRETURN SQL_API SQLDescribeCol(
|
|||||||
}
|
}
|
||||||
if (i==table->num_cols) {
|
if (i==table->num_cols) {
|
||||||
fprintf(stderr, "Column %s lost\n", (char*)sqlcol->name);
|
fprintf(stderr, "Column %s lost\n", (char*)sqlcol->name);
|
||||||
strcpy(sqlState, "07009"); // Invalid descriptor index
|
strcpy(stmt->sqlState, "07009"); // Invalid descriptor index
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,11 +698,11 @@ SQLRETURN SQL_API SQLDescribeCol(
|
|||||||
*pcbColName=strlen(sqlcol->name);
|
*pcbColName=strlen(sqlcol->name);
|
||||||
if (szColName) {
|
if (szColName) {
|
||||||
if (cbColNameMax < 0) {
|
if (cbColNameMax < 0) {
|
||||||
strcpy(sqlState, "HY090"); // Invalid string or buffer length
|
strcpy(stmt->sqlState, "HY090"); // Invalid string or buffer length
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (snprintf((char *)szColName, cbColNameMax, "%s", sqlcol->name) + 1 > cbColNameMax) {
|
if (snprintf((char *)szColName, cbColNameMax, "%s", sqlcol->name) + 1 > cbColNameMax) {
|
||||||
strcpy(sqlState, "01004"); // String data, right truncated
|
strcpy(stmt->sqlState, "01004"); // String data, right truncated
|
||||||
ret = SQL_SUCCESS_WITH_INFO;
|
ret = SQL_SUCCESS_WITH_INFO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -760,7 +741,7 @@ SQLRETURN SQL_API SQLDescribeColW(
|
|||||||
SQLCHAR *tmp=calloc(cbColNameMax*4,1);
|
SQLCHAR *tmp=calloc(cbColNameMax*4,1);
|
||||||
size_t l=cbColNameMax*4;
|
size_t l=cbColNameMax*4;
|
||||||
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, cbColNameMax*4, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
|
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, cbColNameMax*4, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
|
||||||
ascii2unicode((char*)tmp, &l, (char*)szColName, (size_t*)pcbColName);
|
ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, &l, (char*)szColName, (size_t*)pcbColName);
|
||||||
*pcbColName/=sizeof(SQLWCHAR);
|
*pcbColName/=sizeof(SQLWCHAR);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -799,7 +780,7 @@ SQLRETURN SQL_API SQLColAttributes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (icol<1 || icol>sql->num_columns) {
|
if (icol<1 || icol>sql->num_columns) {
|
||||||
strcpy(sqlState, "07009"); // Invalid descriptor index
|
strcpy(stmt->sqlState, "07009"); // Invalid descriptor index
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,7 +794,7 @@ SQLRETURN SQL_API SQLColAttributes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i==table->num_cols) {
|
if (i==table->num_cols) {
|
||||||
strcpy(sqlState, "07009"); // Invalid descriptor index
|
strcpy(stmt->sqlState, "07009"); // Invalid descriptor index
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -823,11 +804,11 @@ SQLRETURN SQL_API SQLColAttributes(
|
|||||||
case SQL_COLUMN_NAME: case SQL_DESC_NAME:
|
case SQL_COLUMN_NAME: case SQL_DESC_NAME:
|
||||||
case SQL_COLUMN_LABEL: /* = SQL_DESC_LABEL */
|
case SQL_COLUMN_LABEL: /* = SQL_DESC_LABEL */
|
||||||
if (cbDescMax < 0) {
|
if (cbDescMax < 0) {
|
||||||
strcpy(sqlState, "HY090"); // Invalid string or buffer length
|
strcpy(stmt->sqlState, "HY090"); // Invalid string or buffer length
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (snprintf(rgbDesc, cbDescMax, "%s", sqlcol->name) + 1 > cbDescMax) {
|
if (snprintf(rgbDesc, cbDescMax, "%s", sqlcol->name) + 1 > cbDescMax) {
|
||||||
strcpy(sqlState, "01004"); // String data, right truncated
|
strcpy(stmt->sqlState, "01004"); // String data, right truncated
|
||||||
ret = SQL_SUCCESS_WITH_INFO;
|
ret = SQL_SUCCESS_WITH_INFO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -866,7 +847,7 @@ SQLRETURN SQL_API SQLColAttributes(
|
|||||||
*pfDesc = SQL_ATTR_READONLY;
|
*pfDesc = SQL_ATTR_READONLY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcpy(sqlState, "HYC00"); // Driver not capable
|
strcpy(stmt->sqlState, "HYC00"); // Driver not capable
|
||||||
ret = SQL_ERROR;
|
ret = SQL_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -890,7 +871,7 @@ SQLRETURN SQL_API SQLColAttributesW(
|
|||||||
SQLCHAR *tmp=calloc(cbDescMax*4,1);
|
SQLCHAR *tmp=calloc(cbDescMax*4,1);
|
||||||
size_t l=cbDescMax*4;
|
size_t l=cbDescMax*4;
|
||||||
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,cbDescMax*4,(SQLSMALLINT*)&l,pfDesc);
|
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,cbDescMax*4,(SQLSMALLINT*)&l,pfDesc);
|
||||||
ascii2unicode((char*)tmp, &l, (char*)rgbDesc, (size_t*)pcbDesc);
|
ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, &l, (char*)rgbDesc, (size_t*)pcbDesc);
|
||||||
*pcbDesc/=sizeof(SQLWCHAR);
|
*pcbDesc/=sizeof(SQLWCHAR);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -928,18 +909,31 @@ SQLRETURN SQL_API SQLError(
|
|||||||
|
|
||||||
TRACE("SQLError");
|
TRACE("SQLError");
|
||||||
//if(pfNativeError)fprintf(stderr,"NativeError %05d\n", *pfNativeError);
|
//if(pfNativeError)fprintf(stderr,"NativeError %05d\n", *pfNativeError);
|
||||||
if (strlen (lastError) > 0)
|
char *src = NULL;
|
||||||
{
|
char *state = NULL;
|
||||||
strcpy ((char*)szSqlState, "08001");
|
if (hstmt) {
|
||||||
strcpy ((char*)szErrorMsg, lastError);
|
src = ((struct _hstmt *)hstmt)->lastError;
|
||||||
if (pcbErrorMsg)
|
state = ((struct _hstmt *)hstmt)->sqlState;
|
||||||
*pcbErrorMsg = strlen (lastError);
|
} else if (hdbc) {
|
||||||
if (pfNativeError)
|
src = ((struct _hdbc *)hdbc)->lastError;
|
||||||
*pfNativeError = 1;
|
state = ((struct _hdbc *)hdbc)->sqlState;
|
||||||
|
} else if (henv) {
|
||||||
|
state = ((struct _henv *)henv)->sqlState;
|
||||||
|
}
|
||||||
|
|
||||||
result = SQL_SUCCESS;
|
if (state)
|
||||||
strcpy (lastError, "");
|
strcpy((char*)szSqlState, state);
|
||||||
}
|
|
||||||
|
if (src && src[0]) {
|
||||||
|
int l = snprintf((char*)szErrorMsg, cbErrorMsgMax, "%s", src);
|
||||||
|
if (pcbErrorMsg)
|
||||||
|
*pcbErrorMsg = l;
|
||||||
|
if (pfNativeError)
|
||||||
|
*pfNativeError = 1;
|
||||||
|
|
||||||
|
result = SQL_SUCCESS;
|
||||||
|
strcpy(src, "");
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -964,10 +958,11 @@ SQLRETURN SQL_API SQLErrorW(
|
|||||||
|
|
||||||
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
|
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
|
||||||
if (result == SQL_SUCCESS) {
|
if (result == SQL_SUCCESS) {
|
||||||
|
struct _hdbc *dbc = hstmt ? ((struct _hstmt *)hstmt)->hdbc : hdbc;
|
||||||
size_t l=6, z=6*sizeof(SQLWCHAR);
|
size_t l=6, z=6*sizeof(SQLWCHAR);
|
||||||
ascii2unicode((char*)szSqlState8, &l, (char*)szSqlState, &z);
|
ascii2unicode(dbc, (char*)szSqlState8, &l, (char*)szSqlState, &z);
|
||||||
l = cbErrorMsgMax;
|
l = cbErrorMsgMax;
|
||||||
ascii2unicode((char*)szErrorMsg8, (size_t*)&pcbErrorMsg8, (char*)szErrorMsg, &l);
|
ascii2unicode(dbc, (char*)szErrorMsg8, (size_t*)&pcbErrorMsg8, (char*)szErrorMsg, &l);
|
||||||
if (pcbErrorMsg)
|
if (pcbErrorMsg)
|
||||||
*pcbErrorMsg = l;
|
*pcbErrorMsg = l;
|
||||||
}
|
}
|
||||||
@@ -988,7 +983,7 @@ SQLRETURN SQL_API SQLExecute(SQLHSTMT hstmt)
|
|||||||
|
|
||||||
mdb_sql_run_query(stmt->sql, stmt->query);
|
mdb_sql_run_query(stmt->sql, stmt->query);
|
||||||
if (mdb_sql_has_error(stmt->sql)) {
|
if (mdb_sql_has_error(stmt->sql)) {
|
||||||
LogError("Couldn't parse SQL\n");
|
LogStatementError(stmt, "Couldn't parse SQL\n");
|
||||||
mdb_sql_reset(stmt->sql);
|
mdb_sql_reset(stmt->sql);
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
} else {
|
} else {
|
||||||
@@ -1017,7 +1012,7 @@ SQLRETURN SQL_API SQLExecDirectW(
|
|||||||
SQLCHAR *tmp=calloc(cbSqlStr*4,1);
|
SQLCHAR *tmp=calloc(cbSqlStr*4,1);
|
||||||
size_t l=cbSqlStr*4,z=cbSqlStr*2;
|
size_t l=cbSqlStr*4,z=cbSqlStr*2;
|
||||||
SQLRETURN ret;
|
SQLRETURN ret;
|
||||||
unicode2ascii((char*)szSqlStr, &z, (char*)tmp, &l);
|
unicode2ascii(((struct _hstmt *)hstmt)->hdbc, (char*)szSqlStr, &z, (char*)tmp, &l);
|
||||||
ret = SQLExecDirect(hstmt, tmp, l);
|
ret = SQLExecDirect(hstmt, tmp, l);
|
||||||
TRACE("SQLExecDirectW end");
|
TRACE("SQLExecDirectW end");
|
||||||
free(tmp);
|
free(tmp);
|
||||||
@@ -1106,7 +1101,7 @@ SQLRETURN SQL_API SQLFreeConnect(
|
|||||||
|
|
||||||
if (dbc->statements->len) {
|
if (dbc->statements->len) {
|
||||||
// Function sequence error
|
// Function sequence error
|
||||||
strcpy(sqlState, "HY010");
|
strcpy(dbc->sqlState, "HY010");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (!g_ptr_array_remove(env->connections, dbc))
|
if (!g_ptr_array_remove(env->connections, dbc))
|
||||||
@@ -1115,6 +1110,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;
|
||||||
@@ -1129,7 +1127,7 @@ SQLRETURN SQL_API SQLFreeEnv(
|
|||||||
|
|
||||||
if (env->connections->len) {
|
if (env->connections->len) {
|
||||||
// Function sequence error
|
// Function sequence error
|
||||||
strcpy(sqlState, "HY010");
|
strcpy(env->sqlState, "HY010");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
g_ptr_array_free(env->connections, TRUE);
|
g_ptr_array_free(env->connections, TRUE);
|
||||||
@@ -1160,6 +1158,8 @@ SQLRETURN SQL_API SQLFreeStmt(
|
|||||||
/* Bound parameters not currently implemented */
|
/* Bound parameters not currently implemented */
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
free(stmt->ole_str);
|
||||||
|
stmt->ole_str = NULL;
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1339,7 +1339,7 @@ SQLRETURN SQL_API SQLColumns(
|
|||||||
table = mdb_read_table(entry);
|
table = mdb_read_table(entry);
|
||||||
if ( !table )
|
if ( !table )
|
||||||
{
|
{
|
||||||
LogError ("Could not read table '%s'", szTableName);
|
LogStatementError(stmt, "Could not read table '%s'", szTableName);
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
mdb_read_columns(table);
|
mdb_read_columns(table);
|
||||||
@@ -1396,7 +1396,7 @@ SQLRETURN SQL_API SQLColumnsW(
|
|||||||
SQLCHAR *tmp=calloc(cbTableName*4,1);
|
SQLCHAR *tmp=calloc(cbTableName*4,1);
|
||||||
size_t l=cbTableName*4,z=cbTableName*2;
|
size_t l=cbTableName*4,z=cbTableName*2;
|
||||||
SQLRETURN ret;
|
SQLRETURN ret;
|
||||||
unicode2ascii((char*)szTableName, &z, (char*)tmp, &l);
|
unicode2ascii(((struct _hstmt* )hstmt)->hdbc, (char*)szTableName, &z, (char*)tmp, &l);
|
||||||
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
|
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1435,7 +1435,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
mdb = sql->mdb;
|
mdb = sql->mdb;
|
||||||
|
|
||||||
if (icol<1 || icol>sql->num_columns) {
|
if (icol<1 || icol>sql->num_columns) {
|
||||||
strcpy(sqlState, "07009");
|
strcpy(stmt->sqlState, "07009");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1456,7 +1456,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rgbValue) {
|
if (!rgbValue) {
|
||||||
strcpy(sqlState, "HY009");
|
strcpy(stmt->sqlState, "HY009");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1471,7 +1471,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
/* When NULL data is retrieved, non-null pcbValue is
|
/* When NULL data is retrieved, non-null pcbValue is
|
||||||
required */
|
required */
|
||||||
if (!pcbValue) {
|
if (!pcbValue) {
|
||||||
strcpy(sqlState, "22002");
|
strcpy(stmt->sqlState, "22002");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*pcbValue = SQL_NULL_DATA;
|
*pcbValue = SQL_NULL_DATA;
|
||||||
@@ -1487,7 +1487,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
goto found_bound_type;
|
goto found_bound_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strcpy(sqlState, "07009");
|
strcpy(stmt->sqlState, "07009");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
found_bound_type:
|
found_bound_type:
|
||||||
@@ -1509,7 +1509,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
switch (fCType) {
|
switch (fCType) {
|
||||||
case SQL_C_UTINYINT:
|
case SQL_C_UTINYINT:
|
||||||
if (intValue<0 || intValue>UCHAR_MAX) {
|
if (intValue<0 || intValue>UCHAR_MAX) {
|
||||||
strcpy(sqlState, "22003"); // Numeric value out of range
|
strcpy(stmt->sqlState, "22003"); // Numeric value out of range
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*(SQLCHAR*)rgbValue = (SQLCHAR)intValue;
|
*(SQLCHAR*)rgbValue = (SQLCHAR)intValue;
|
||||||
@@ -1519,7 +1519,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
case SQL_C_TINYINT:
|
case SQL_C_TINYINT:
|
||||||
case SQL_C_STINYINT:
|
case SQL_C_STINYINT:
|
||||||
if (intValue<SCHAR_MIN || intValue>SCHAR_MAX) {
|
if (intValue<SCHAR_MIN || intValue>SCHAR_MAX) {
|
||||||
strcpy(sqlState, "22003"); // Numeric value out of range
|
strcpy(stmt->sqlState, "22003"); // Numeric value out of range
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*(SQLSCHAR*)rgbValue = (SQLSCHAR)intValue;
|
*(SQLSCHAR*)rgbValue = (SQLSCHAR)intValue;
|
||||||
@@ -1529,7 +1529,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
case SQL_C_USHORT:
|
case SQL_C_USHORT:
|
||||||
case SQL_C_SHORT:
|
case SQL_C_SHORT:
|
||||||
if (intValue<0 || intValue>USHRT_MAX) {
|
if (intValue<0 || intValue>USHRT_MAX) {
|
||||||
strcpy(sqlState, "22003"); // Numeric value out of range
|
strcpy(stmt->sqlState, "22003"); // Numeric value out of range
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue;
|
*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue;
|
||||||
@@ -1538,7 +1538,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
break;
|
break;
|
||||||
case SQL_C_SSHORT:
|
case SQL_C_SSHORT:
|
||||||
if (intValue<SHRT_MIN || intValue>SHRT_MAX) {
|
if (intValue<SHRT_MIN || intValue>SHRT_MAX) {
|
||||||
strcpy(sqlState, "22003"); // Numeric value out of range
|
strcpy(stmt->sqlState, "22003"); // Numeric value out of range
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue;
|
*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue;
|
||||||
@@ -1547,7 +1547,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
break;
|
break;
|
||||||
case SQL_C_ULONG:
|
case SQL_C_ULONG:
|
||||||
if (intValue<0 || intValue>UINT_MAX) {
|
if (intValue<0 || intValue>UINT_MAX) {
|
||||||
strcpy(sqlState, "22003"); // Numeric value out of range
|
strcpy(stmt->sqlState, "22003"); // Numeric value out of range
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*(SQLUINTEGER*)rgbValue = (SQLINTEGER)intValue;
|
*(SQLUINTEGER*)rgbValue = (SQLINTEGER)intValue;
|
||||||
@@ -1557,7 +1557,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
case SQL_C_LONG:
|
case SQL_C_LONG:
|
||||||
case SQL_C_SLONG:
|
case SQL_C_SLONG:
|
||||||
if (intValue<INT_MIN || intValue>INT_MAX) {
|
if (intValue<INT_MIN || intValue>INT_MAX) {
|
||||||
strcpy(sqlState, "22003"); // Numeric value out of range
|
strcpy(stmt->sqlState, "22003"); // Numeric value out of range
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
*(SQLINTEGER*)rgbValue = intValue;
|
*(SQLINTEGER*)rgbValue = intValue;
|
||||||
@@ -1565,7 +1565,7 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
*pcbValue = sizeof(SQLINTEGER);
|
*pcbValue = sizeof(SQLINTEGER);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcpy(sqlState, "HYC00"); // Not implemented
|
strcpy(stmt->sqlState, "HYC00"); // Not implemented
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1613,33 +1613,63 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
case MDB_OLE:
|
||||||
|
if (cbValueMax < 0) {
|
||||||
|
strcpy(stmt->sqlState, "HY090"); // Invalid string or buffer length
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
if (stmt->pos == 0) {
|
||||||
|
if (stmt->ole_str) {
|
||||||
|
free(stmt->ole_str);
|
||||||
|
}
|
||||||
|
stmt->ole_str = mdb_ole_read_full(mdb, col, &stmt->ole_len);
|
||||||
|
}
|
||||||
|
if (stmt->pos >= stmt->ole_len) {
|
||||||
|
return SQL_NO_DATA;
|
||||||
|
}
|
||||||
|
if (pcbValue) {
|
||||||
|
*pcbValue = stmt->ole_len - stmt->pos;
|
||||||
|
}
|
||||||
|
if (cbValueMax == 0) {
|
||||||
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
}
|
||||||
|
/* if the column type is OLE, then we don't add terminators
|
||||||
|
see https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetdata-function?view=sql-server-ver15
|
||||||
|
and https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/odbc/src/tpc/db2z_fngetdata.html
|
||||||
|
|
||||||
|
"The buffer that the rgbValue argument specifies contains nul-terminated values, unless you retrieve
|
||||||
|
binary data, or the SQL data type of the column is graphic (DBCS) and the C buffer type is SQL_C_CHAR."
|
||||||
|
*/
|
||||||
|
const int totalSizeRemaining = stmt->ole_len - stmt->pos;
|
||||||
|
const int partsRemain = cbValueMax < totalSizeRemaining;
|
||||||
|
const int sizeToReadThisPart = partsRemain ? cbValueMax : totalSizeRemaining;
|
||||||
|
memcpy(rgbValue, stmt->ole_str + stmt->pos, sizeToReadThisPart);
|
||||||
|
|
||||||
|
if (partsRemain) {
|
||||||
|
stmt->pos += cbValueMax;
|
||||||
|
strcpy(stmt->sqlState, "01004"); // truncated
|
||||||
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
|
}
|
||||||
|
stmt->pos = stmt->ole_len;
|
||||||
|
free(stmt->ole_str);
|
||||||
|
stmt->ole_str = NULL;
|
||||||
|
break;
|
||||||
default: /* FIXME here we assume fCType == SQL_C_CHAR */
|
default: /* FIXME here we assume fCType == SQL_C_CHAR */
|
||||||
to_c_char:
|
to_c_char:
|
||||||
{
|
{
|
||||||
static __thread size_t len = 0;
|
if (cbValueMax < 0) {
|
||||||
static __thread char *str = NULL;
|
strcpy(stmt->sqlState, "HY090"); // Invalid string or buffer length
|
||||||
|
return SQL_ERROR;
|
||||||
if (col->col_type == MDB_OLE) {
|
|
||||||
if (stmt->pos == 0) {
|
|
||||||
str = mdb_ole_read_full(mdb, col, &len);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
str = mdb_col_to_string(mdb, mdb->pg_buf,
|
|
||||||
col->cur_value_start, col->col_type, col->cur_value_len);
|
|
||||||
len = strlen(str);
|
|
||||||
}
|
}
|
||||||
|
char *str = mdb_col_to_string(mdb, mdb->pg_buf,
|
||||||
|
col->cur_value_start, col->col_type, col->cur_value_len);
|
||||||
|
size_t len = strlen(str);
|
||||||
|
|
||||||
if (stmt->pos >= len) {
|
if (stmt->pos >= len) {
|
||||||
free(str);
|
free(str);
|
||||||
str = NULL;
|
str = NULL;
|
||||||
return SQL_NO_DATA;
|
return SQL_NO_DATA;
|
||||||
}
|
}
|
||||||
if (cbValueMax < 0) {
|
|
||||||
strcpy(sqlState, "HY090"); // Invalid string or buffer length
|
|
||||||
free(str);
|
|
||||||
str = NULL;
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
if (pcbValue) {
|
if (pcbValue) {
|
||||||
*pcbValue = len + 1 - stmt->pos;
|
*pcbValue = len + 1 - stmt->pos;
|
||||||
}
|
}
|
||||||
@@ -1649,28 +1679,17 @@ SQLRETURN SQL_API SQLGetData(
|
|||||||
return SQL_SUCCESS_WITH_INFO;
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the column type is OLE, then we don't add terminators
|
|
||||||
see https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetdata-function?view=sql-server-ver15
|
|
||||||
and https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/odbc/src/tpc/db2z_fngetdata.html
|
|
||||||
|
|
||||||
"The buffer that the rgbValue argument specifies contains nul-terminated values, unless you retrieve
|
|
||||||
binary data, or the SQL data type of the column is graphic (DBCS) and the C buffer type is SQL_C_CHAR."
|
|
||||||
*/
|
|
||||||
const int needsTerminator = (col->col_type != MDB_OLE);
|
|
||||||
|
|
||||||
const int totalSizeRemaining = len - stmt->pos;
|
const int totalSizeRemaining = len - stmt->pos;
|
||||||
const int partsRemain = cbValueMax - ( needsTerminator ? 1 : 0 ) < totalSizeRemaining;
|
const int partsRemain = cbValueMax - 1 < totalSizeRemaining;
|
||||||
const int sizeToReadThisPart = partsRemain ? cbValueMax - ( needsTerminator ? 1 : 0 ) : totalSizeRemaining;
|
const int sizeToReadThisPart = partsRemain ? cbValueMax - 1 : totalSizeRemaining;
|
||||||
memcpy(rgbValue, str + stmt->pos, sizeToReadThisPart);
|
memcpy(rgbValue, str + stmt->pos, sizeToReadThisPart);
|
||||||
|
|
||||||
if (needsTerminator)
|
((char *)rgbValue)[sizeToReadThisPart] = '\0';
|
||||||
{
|
|
||||||
((char *)rgbValue)[sizeToReadThisPart] = '\0';
|
|
||||||
}
|
|
||||||
if (partsRemain) {
|
if (partsRemain) {
|
||||||
stmt->pos += cbValueMax - ( needsTerminator ? 1 : 0 );
|
stmt->pos += cbValueMax - 1;
|
||||||
if (col->col_type != MDB_OLE) { free(str); str = NULL; }
|
free(str); str = NULL;
|
||||||
strcpy(sqlState, "01004"); // truncated
|
strcpy(stmt->sqlState, "01004"); // truncated
|
||||||
return SQL_SUCCESS_WITH_INFO;
|
return SQL_SUCCESS_WITH_INFO;
|
||||||
}
|
}
|
||||||
stmt->pos = len;
|
stmt->pos = len;
|
||||||
@@ -1696,7 +1715,7 @@ SQLRETURN SQL_API SQLGetDataW(
|
|||||||
SQLCHAR *tmp=calloc(cbValueMax*4,1);
|
SQLCHAR *tmp=calloc(cbValueMax*4,1);
|
||||||
size_t l=cbValueMax*4;
|
size_t l=cbValueMax*4;
|
||||||
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, cbValueMax*4, (SQLLEN*)&l);
|
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, cbValueMax*4, (SQLLEN*)&l);
|
||||||
ascii2unicode((char*)tmp, &l, (char*)rgbValue, (size_t*)pcbValue);
|
ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, &l, (char*)rgbValue, (size_t*)pcbValue);
|
||||||
*pcbValue/=sizeof(SQLWCHAR);
|
*pcbValue/=sizeof(SQLWCHAR);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1930,7 +1949,7 @@ SQLRETURN SQL_API SQLGetInfo(
|
|||||||
default:
|
default:
|
||||||
if (pcbInfoValue)
|
if (pcbInfoValue)
|
||||||
*pcbInfoValue = 0;
|
*pcbInfoValue = 0;
|
||||||
strcpy(sqlState, "HYC00");
|
strcpy(((struct _hdbc *)hdbc)->sqlState, "HYC00");
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1954,7 +1973,7 @@ SQLRETURN SQL_API SQLGetInfoW(
|
|||||||
size_t l=cbInfoValueMax*4;
|
size_t l=cbInfoValueMax*4;
|
||||||
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, cbInfoValueMax*4,(SQLSMALLINT*)&l);
|
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, cbInfoValueMax*4,(SQLSMALLINT*)&l);
|
||||||
size_t pcb=cbInfoValueMax;
|
size_t pcb=cbInfoValueMax;
|
||||||
ascii2unicode((char*)tmp, &l, (char*)rgbInfoValue, &pcb);
|
ascii2unicode((struct _hdbc *)hdbc, (char*)tmp, &l, (char*)rgbInfoValue, &pcb);
|
||||||
pcb/=sizeof(SQLWCHAR);
|
pcb/=sizeof(SQLWCHAR);
|
||||||
if(pcbInfoValue)*pcbInfoValue=pcb;
|
if(pcbInfoValue)*pcbInfoValue=pcb;
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
|||||||
Reference in New Issue
Block a user