mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-04-05 20:31:00 +08:00
Move Unicode ODBC functions to separate file (remove ODBC's iconv)
Use wcstombs and friends to perform Unicode conversion inside the ODBC driver. Functionality should be identical as before, except that installations without iconv will now be able to compile and install the Unicode (libmdbodbcW) driver. iconv remains present in the main libmdb library.
This commit is contained in:
parent
00d597b6d3
commit
0164b4df1a
@ -149,6 +149,9 @@ mutually exclusive.
|
||||
causes the iODBC driver to be built.
|
||||
```
|
||||
|
||||
By default, the ODBC driver will be installed as /usr/local/lib/odbc/libmdbodbc.so,
|
||||
with a Unicode-capable driver at /usr/local/lib/odbc/libmdbodbcW.so.
|
||||
|
||||
A list of general options is available in the [INSTALL](./INSTALL) file, and
|
||||
`configure --help` will give you the list of mdbtools specific options.
|
||||
|
||||
|
@ -103,9 +103,6 @@ if test "$enable_iconv" = "yes"; then
|
||||
fi
|
||||
AC_SUBST(HAVE_ICONV_H)
|
||||
|
||||
dnl Wide-char ODBC driver still requires iconv
|
||||
AM_CONDITIONAL(ICONV, test "$am_cv_func_iconv" = "yes")
|
||||
|
||||
dnl Fuzz testing
|
||||
AC_ARG_ENABLE([fuzz-testing], AS_HELP_STRING([--enable-fuzz-testing], [enable fuzz testing (requires Clang 6 or later)]), [
|
||||
AC_MSG_CHECKING([whether $CC accepts -fsanitize=fuzzer])
|
||||
|
@ -38,7 +38,9 @@
|
||||
|
||||
#if MDBTOOLS_H_HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#elif MDBTOOLS_H_HAVE_XLOCALE_H
|
||||
#endif
|
||||
|
||||
#if MDBTOOLS_H_HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
|
||||
@ -65,9 +67,7 @@
|
||||
// M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
|
||||
#define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname
|
||||
|
||||
#if !MDBTOOLS_H_HAVE_ICONV_H
|
||||
typedef @LOCALE_T@ mdb_locale_t;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
MDB_PAGE_DB = 0,
|
||||
|
@ -7,12 +7,9 @@ AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) $(ODBC_CFLAGS)
|
||||
libmdbodbc_la_SOURCES = odbc.c connectparams.c
|
||||
libmdbodbc_la_LIBADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(ODBC_LIBS)
|
||||
libmdbodbc_la_LDFLAGS = -avoid-version -export-symbols-regex '^(SQL|ODBCINST)' $(ODBC_LDFLAGS)
|
||||
if ICONV
|
||||
lib_LTLIBRARIES += libmdbodbcW.la
|
||||
libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES)
|
||||
libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD) @LIBICONV@
|
||||
libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES) odbcw.c
|
||||
libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD)
|
||||
libmdbodbcW_la_LDFLAGS = $(libmdbodbc_la_LDFLAGS)
|
||||
libmdbodbcW_la_CFLAGS = $(AM_CFLAGS) -D ENABLE_ODBC_W=1
|
||||
endif
|
||||
LIBS = $(GLIB_LIBS)
|
||||
unittest_LDADD = libmdbodbc.la ../libmdb/libmdb.la ../sql/libmdbsql.la
|
||||
|
@ -50,10 +50,7 @@ struct _hdbc {
|
||||
GPtrArray *statements;
|
||||
char lastError[256];
|
||||
char sqlState[6];
|
||||
#ifdef ENABLE_ODBC_W
|
||||
iconv_t iconv_in;
|
||||
iconv_t iconv_out;
|
||||
#endif
|
||||
mdb_locale_t locale;
|
||||
};
|
||||
struct _hstmt {
|
||||
MdbSQL *sql;
|
||||
|
311
src/odbc/odbc.c
311
src/odbc/odbc.c
@ -16,11 +16,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
#define SQL_NOUNICODEMAP
|
||||
#define UNICODE
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#include <string.h>
|
||||
@ -85,64 +80,6 @@ TypeInfo type_info[] = {
|
||||
#define NUM_TYPE_INFO_COLS 19
|
||||
#define MAX_TYPE_INFO 11
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
static void _init_iconv(struct _hdbc* dbc)
|
||||
{
|
||||
TRACE("_init_iconv");
|
||||
int endian = 1;
|
||||
const char* wcharset;
|
||||
if (sizeof(SQLWCHAR) == 2)
|
||||
if (*(char*)&endian == 1)
|
||||
wcharset = "UCS-2LE";
|
||||
else
|
||||
wcharset = "UCS-2BE";
|
||||
else if (sizeof(SQLWCHAR) == 4)
|
||||
if (*(char*)&endian == 1)
|
||||
wcharset = "UCS-4LE";
|
||||
else
|
||||
wcharset = "UCS-4BE";
|
||||
else
|
||||
fprintf(stderr, "Unsupported SQLWCHAR width %zd\n", sizeof(SQLWCHAR));
|
||||
|
||||
dbc->iconv_out = iconv_open(wcharset, "UTF-8");
|
||||
dbc->iconv_in = iconv_open("UTF-8", wcharset);
|
||||
}
|
||||
|
||||
static void _free_iconv(struct _hdbc *dbc)
|
||||
{
|
||||
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(struct _hdbc* dbc, char *_in, size_t *_lin, char *_out, size_t *_lout){
|
||||
char *in=_in, *out=_out;
|
||||
size_t lin=*_lin, lout=*_lout;
|
||||
int ret = iconv(dbc->iconv_in, &in, &lin, &out, &lout);
|
||||
*_lin -= lin;
|
||||
*_lout -= lout;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
char *in=_in, *out=_out;
|
||||
size_t lin=*_lin, lout=*_lout;
|
||||
//fprintf(stderr,"ascii2unicode %zd %zd\n",lin,lout);
|
||||
int ret = iconv(dbc->iconv_out, &in, &lin, &out, &lout);
|
||||
*_lin -= lin;
|
||||
*_lout -= lout;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sqlwlen(SQLWCHAR *p){
|
||||
int r=0;
|
||||
for(;*p;r++)
|
||||
p++;
|
||||
return r;
|
||||
}
|
||||
#endif // ENABLE_ODBC_W
|
||||
|
||||
static void LogHandleError(struct _hdbc* dbc, const char* format, ...)
|
||||
{
|
||||
va_list argp;
|
||||
@ -213,36 +150,6 @@ SQLRETURN SQL_API SQLDriverConnect(
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLDriverConnectW(
|
||||
SQLHDBC hdbc,
|
||||
SQLHWND hwnd,
|
||||
SQLWCHAR *szConnStrIn,
|
||||
SQLSMALLINT cbConnStrIn,
|
||||
SQLWCHAR *szConnStrOut,
|
||||
SQLSMALLINT cbConnStrOutMax,
|
||||
SQLSMALLINT *pcbConnStrOut,
|
||||
SQLUSMALLINT fDriverCompletion)
|
||||
{
|
||||
TRACE("SQLDriverConnectW");
|
||||
if(cbConnStrIn==SQL_NTS)cbConnStrIn=sqlwlen(szConnStrIn);
|
||||
{
|
||||
size_t l = cbConnStrIn*sizeof(SQLWCHAR), z = (cbConnStrIn+1)*3;
|
||||
SQLCHAR *tmp = malloc(z);
|
||||
SQLRETURN ret;
|
||||
unicode2ascii((struct _hdbc *)hdbc, (char*)szConnStrIn, &l, (char*)tmp, &z);
|
||||
tmp[z] = 0;
|
||||
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
|
||||
free(tmp);
|
||||
if (szConnStrOut && cbConnStrOutMax>0)
|
||||
szConnStrOut[0] = 0;
|
||||
if (pcbConnStrOut)
|
||||
*pcbConnStrOut = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLBrowseConnect(
|
||||
SQLHDBC hdbc,
|
||||
SQLCHAR *szConnStrIn,
|
||||
@ -498,8 +405,10 @@ struct _hdbc* dbc;
|
||||
dbc->params = NewConnectParams ();
|
||||
dbc->statements = g_ptr_array_new();
|
||||
dbc->sqlconn = mdb_sql_init();
|
||||
#ifdef ENABLE_ODBC_W
|
||||
_init_iconv(dbc);
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
|
||||
dbc->locale = _create_locale(LC_CTYPE, ".65001");
|
||||
#else
|
||||
dbc->locale = newlocale(LC_CTYPE_MASK, "C.UTF-8", NULL);
|
||||
#endif
|
||||
*phdbc=dbc;
|
||||
|
||||
@ -645,36 +554,6 @@ SQLRETURN SQL_API SQLConnect(
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLConnectW(
|
||||
SQLHDBC hdbc,
|
||||
SQLWCHAR *szDSN,
|
||||
SQLSMALLINT cbDSN,
|
||||
SQLWCHAR *szUID,
|
||||
SQLSMALLINT cbUID,
|
||||
SQLWCHAR *szAuthStr,
|
||||
SQLSMALLINT cbAuthStr)
|
||||
{
|
||||
TRACE("SQLConnectW");
|
||||
if(cbDSN==SQL_NTS)cbDSN=sqlwlen(szDSN);
|
||||
if(cbUID==SQL_NTS)cbUID=sqlwlen(szUID);
|
||||
if(cbAuthStr==SQL_NTS)cbAuthStr=sqlwlen(szAuthStr);
|
||||
{
|
||||
SQLCHAR *tmp1=calloc(cbDSN*4,1),*tmp2=calloc(cbUID*4,1),*tmp3=calloc(cbAuthStr*4,1);
|
||||
size_t l1=cbDSN*4,z1=cbDSN*2;
|
||||
size_t l2=cbUID*4,z2=cbUID*2;
|
||||
size_t l3=cbAuthStr*4,z3=cbAuthStr*2;
|
||||
SQLRETURN ret;
|
||||
unicode2ascii((struct _hdbc *)hdbc, (char*)szDSN, &z1, (char*)tmp1, &l1);
|
||||
unicode2ascii((struct _hdbc *)hdbc, (char*)szUID, &z2, (char*)tmp2, &l2);
|
||||
unicode2ascii((struct _hdbc *)hdbc, (char*)szAuthStr, &z3, (char*)tmp3, &l3);
|
||||
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
|
||||
free(tmp1),free(tmp2),free(tmp3);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLDescribeCol(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
@ -743,32 +622,6 @@ SQLRETURN SQL_API SQLDescribeCol(
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLDescribeColW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLWCHAR *szColName,
|
||||
SQLSMALLINT cbColNameMax,
|
||||
SQLSMALLINT *pcbColName,
|
||||
SQLSMALLINT *pfSqlType,
|
||||
SQLULEN *pcbColDef, /* precision */
|
||||
SQLSMALLINT *pibScale,
|
||||
SQLSMALLINT *pfNullable)
|
||||
{
|
||||
TRACE("SQLDescribeColW");
|
||||
if(cbColNameMax==SQL_NTS)cbColNameMax=sqlwlen(szColName);
|
||||
{
|
||||
SQLCHAR *tmp=calloc(cbColNameMax*4,1);
|
||||
size_t l=cbColNameMax*4;
|
||||
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, cbColNameMax*4, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
|
||||
ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, &l, (char*)szColName, (size_t*)pcbColName);
|
||||
*pcbColName/=sizeof(SQLWCHAR);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLColAttributes(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
@ -874,31 +727,6 @@ SQLRETURN SQL_API SQLColAttributes(
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLColAttributesW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLUSMALLINT fDescType,
|
||||
SQLPOINTER rgbDesc,
|
||||
SQLSMALLINT cbDescMax,
|
||||
SQLSMALLINT *pcbDesc,
|
||||
SQLLEN *pfDesc)
|
||||
{
|
||||
TRACE("SQLColAttributesW");
|
||||
if (fDescType!=SQL_COLUMN_NAME && fDescType!=SQL_COLUMN_LABEL)
|
||||
return SQLColAttributes(hstmt,icol,fDescType,rgbDesc,cbDescMax,pcbDesc,pfDesc);
|
||||
else{
|
||||
SQLCHAR *tmp=calloc(cbDescMax*4,1);
|
||||
size_t l=cbDescMax*4;
|
||||
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,cbDescMax*4,(SQLSMALLINT*)&l,pfDesc);
|
||||
ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, &l, (char*)rgbDesc, (size_t*)pcbDesc);
|
||||
*pcbDesc/=sizeof(SQLWCHAR);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLDisconnect(
|
||||
SQLHDBC hdbc)
|
||||
{
|
||||
@ -958,39 +786,6 @@ SQLRETURN SQL_API SQLError(
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLErrorW(
|
||||
SQLHENV henv,
|
||||
SQLHDBC hdbc,
|
||||
SQLHSTMT hstmt,
|
||||
SQLWCHAR *szSqlState,
|
||||
SQLINTEGER *pfNativeError,
|
||||
SQLWCHAR *szErrorMsg,
|
||||
SQLSMALLINT cbErrorMsgMax,
|
||||
SQLSMALLINT *pcbErrorMsg)
|
||||
{
|
||||
SQLCHAR szSqlState8[6];
|
||||
SQLCHAR szErrorMsg8[3*cbErrorMsgMax+1];
|
||||
SQLSMALLINT pcbErrorMsg8;
|
||||
SQLRETURN result;
|
||||
|
||||
TRACE("SQLErrorW");
|
||||
|
||||
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
|
||||
if (result == SQL_SUCCESS) {
|
||||
struct _hdbc *dbc = hstmt ? ((struct _hstmt *)hstmt)->hdbc : hdbc;
|
||||
size_t lin=6, lout=6*sizeof(SQLWCHAR);
|
||||
ascii2unicode(dbc, (char*)szSqlState8, &lin, (char*)szSqlState, &lout);
|
||||
lin = pcbErrorMsg8;
|
||||
lout = cbErrorMsgMax;
|
||||
ascii2unicode(dbc, (char*)szErrorMsg8, &lin, (char*)szErrorMsg, &lout);
|
||||
if (pcbErrorMsg)
|
||||
*pcbErrorMsg = lout;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLExecute(SQLHSTMT hstmt)
|
||||
{
|
||||
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
||||
@ -1021,27 +816,6 @@ SQLRETURN SQL_API SQLExecDirect(
|
||||
return SQLExecute(hstmt);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLExecDirectW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLWCHAR *szSqlStr,
|
||||
SQLINTEGER cbSqlStr)
|
||||
{
|
||||
TRACE("SQLExecDirectW");
|
||||
if(cbSqlStr==SQL_NTS)cbSqlStr=sqlwlen(szSqlStr);
|
||||
{
|
||||
SQLCHAR *tmp=calloc(cbSqlStr*4,1);
|
||||
size_t l=cbSqlStr*4,z=cbSqlStr*2;
|
||||
SQLRETURN ret;
|
||||
unicode2ascii(((struct _hstmt *)hstmt)->hdbc, (char*)szSqlStr, &z, (char*)tmp, &l);
|
||||
ret = SQLExecDirect(hstmt, tmp, l);
|
||||
TRACE("SQLExecDirectW end");
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_ODBC_W
|
||||
|
||||
static void
|
||||
unbind_columns(struct _hstmt *stmt)
|
||||
{
|
||||
@ -1111,8 +885,10 @@ 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);
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
|
||||
if (dbc->locale) _free_locale(dbc->locale);
|
||||
#else
|
||||
if (dbc->locale) freelocale(dbc->locale);
|
||||
#endif
|
||||
g_free(dbc);
|
||||
|
||||
@ -1382,31 +1158,6 @@ SQLRETURN SQL_API SQLColumns(
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLColumnsW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLWCHAR *szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLWCHAR *szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLWCHAR *szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLWCHAR *szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
if(cbTableName==SQL_NTS)cbTableName=sqlwlen(szTableName);
|
||||
{
|
||||
SQLCHAR *tmp=calloc(cbTableName*4,1);
|
||||
size_t l=cbTableName*4,z=cbTableName*2;
|
||||
SQLRETURN ret;
|
||||
unicode2ascii(((struct _hstmt* )hstmt)->hdbc, (char*)szTableName, &z, (char*)tmp, &l);
|
||||
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLGetConnectOption(
|
||||
SQLHDBC hdbc,
|
||||
SQLUSMALLINT fOption,
|
||||
@ -1719,27 +1470,6 @@ SQLRETURN SQL_API SQLGetData(
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLGetDataW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLSMALLINT fCType,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLLEN cbValueMax,
|
||||
SQLLEN *pcbValue)
|
||||
{
|
||||
//todo: treat numbers correctly
|
||||
|
||||
SQLCHAR *tmp=calloc(cbValueMax*4,1);
|
||||
size_t l=cbValueMax*4;
|
||||
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, cbValueMax*4, (SQLLEN*)&l);
|
||||
ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, &l, (char*)rgbValue, (size_t*)pcbValue);
|
||||
*pcbValue/=sizeof(SQLWCHAR);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
static void _set_func_exists(SQLUSMALLINT *pfExists, SQLUSMALLINT fFunction)
|
||||
{
|
||||
SQLUSMALLINT *mod;
|
||||
@ -1974,31 +1704,6 @@ SQLRETURN SQL_API SQLGetInfo(
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ODBC_W
|
||||
SQLRETURN SQL_API SQLGetInfoW(
|
||||
SQLHDBC hdbc,
|
||||
SQLUSMALLINT fInfoType,
|
||||
SQLPOINTER rgbInfoValue,
|
||||
SQLSMALLINT cbInfoValueMax,
|
||||
SQLSMALLINT *pcbInfoValue)
|
||||
{
|
||||
TRACE("SQLGetInfoW");
|
||||
|
||||
if(fInfoType==SQL_MAX_STATEMENT_LEN||fInfoType==SQL_SCHEMA_USAGE||fInfoType==SQL_CATALOG_LOCATION)
|
||||
return SQLGetInfo(hdbc,fInfoType,rgbInfoValue,cbInfoValueMax,pcbInfoValue);
|
||||
|
||||
SQLCHAR *tmp=calloc(cbInfoValueMax*4,1);
|
||||
size_t l=cbInfoValueMax*4;
|
||||
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, cbInfoValueMax*4,(SQLSMALLINT*)&l);
|
||||
size_t pcb=cbInfoValueMax;
|
||||
ascii2unicode((struct _hdbc *)hdbc, (char*)tmp, &l, (char*)rgbInfoValue, &pcb);
|
||||
pcb/=sizeof(SQLWCHAR);
|
||||
if(pcbInfoValue)*pcbInfoValue=pcb;
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
#endif //ENABLE_ODBC_W
|
||||
|
||||
SQLRETURN SQL_API SQLGetStmtOption(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT fOption,
|
||||
|
301
src/odbc/odbcw.c
Normal file
301
src/odbc/odbcw.c
Normal file
@ -0,0 +1,301 @@
|
||||
/* MDB Tools - A library for reading MS Access database file
|
||||
* Copyright (C) 2000-2021 Brian Bruns and others
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define SQL_NOUNICODEMAP
|
||||
#define UNICODE
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "mdbodbc.h"
|
||||
|
||||
/** \addtogroup odbc
|
||||
* @{
|
||||
*/
|
||||
|
||||
//#define TRACE(x) fprintf(stderr,"Function %s\n", x);
|
||||
#define TRACE(x)
|
||||
|
||||
static size_t unicode2ascii(struct _hdbc* dbc, const SQLWCHAR *_in, size_t _in_count, SQLCHAR *_out, size_t _out_len){
|
||||
wchar_t *w = malloc((_in_count + 1) * sizeof(wchar_t));
|
||||
size_t i;
|
||||
size_t count = 0;
|
||||
for (i=0; i<_in_count; i++) {
|
||||
w[i] = _in[i]; // wchar_t might be larger than SQLWCHAR
|
||||
}
|
||||
w[_in_count] = '\0';
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
|
||||
count = _wcstombs_l((char *)_out, w, _out_len, dbc->locale);
|
||||
#elif defined(HAVE_WCSTOMBS_L)
|
||||
count = wcstombs_l((char *)_out, w, _out_len, dbc->locale);
|
||||
#else
|
||||
locale_t oldlocale = uselocale(dbc->locale);
|
||||
count = wcstombs((char *)_out, w, _out_len);
|
||||
uselocale(oldlocale);
|
||||
#endif
|
||||
free(w);
|
||||
if (count == (size_t)-1)
|
||||
return 0;
|
||||
|
||||
if (count < _out_len)
|
||||
_out[count] = '\0';
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static size_t ascii2unicode(struct _hdbc* dbc, const char *_in, size_t _in_len, SQLWCHAR *_out, size_t _out_count){
|
||||
wchar_t *w = malloc(_out_count * sizeof(wchar_t));
|
||||
size_t count = 0, i;
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
|
||||
count = _mbstowcs_l(w, _in, _out_count, dbc->locale);
|
||||
#elif defined(HAVE_WCSTOMBS_L)
|
||||
count = mbstowcs_l(w, _in, _out_count, dbc->locale);
|
||||
#else
|
||||
locale_t oldlocale = uselocale(dbc->locale);
|
||||
count = mbstowcs(w, _in, _out_count);
|
||||
uselocale(oldlocale);
|
||||
#endif
|
||||
for (i=0; i<count; i++) {
|
||||
_out[i] = (SQLWCHAR)w[i];
|
||||
}
|
||||
free(w);
|
||||
if (count < _out_count)
|
||||
_out[count] = '\0';
|
||||
return count;
|
||||
}
|
||||
|
||||
static int sqlwlen(SQLWCHAR *p){
|
||||
int r=0;
|
||||
for(;*p;r++)
|
||||
p++;
|
||||
return r;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLDriverConnectW(
|
||||
SQLHDBC hdbc,
|
||||
SQLHWND hwnd,
|
||||
SQLWCHAR *szConnStrIn,
|
||||
SQLSMALLINT cbConnStrIn,
|
||||
SQLWCHAR *szConnStrOut,
|
||||
SQLSMALLINT cbConnStrOutMax,
|
||||
SQLSMALLINT *pcbConnStrOut,
|
||||
SQLUSMALLINT fDriverCompletion)
|
||||
{
|
||||
TRACE("SQLDriverConnectW");
|
||||
if(cbConnStrIn==SQL_NTS)cbConnStrIn=sqlwlen(szConnStrIn);
|
||||
{
|
||||
size_t l = cbConnStrIn*4;
|
||||
SQLCHAR *tmp = malloc(l+1);
|
||||
SQLRETURN ret;
|
||||
l = unicode2ascii((struct _hdbc *)hdbc, szConnStrIn, cbConnStrIn, tmp, l);
|
||||
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
|
||||
free(tmp);
|
||||
if (szConnStrOut && cbConnStrOutMax>0)
|
||||
szConnStrOut[0] = 0;
|
||||
if (pcbConnStrOut)
|
||||
*pcbConnStrOut = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLConnectW(
|
||||
SQLHDBC hdbc,
|
||||
SQLWCHAR *szDSN,
|
||||
SQLSMALLINT cbDSN,
|
||||
SQLWCHAR *szUID,
|
||||
SQLSMALLINT cbUID,
|
||||
SQLWCHAR *szAuthStr,
|
||||
SQLSMALLINT cbAuthStr)
|
||||
{
|
||||
TRACE("SQLConnectW");
|
||||
if(cbDSN==SQL_NTS)cbDSN=sqlwlen(szDSN);
|
||||
if(cbUID==SQL_NTS)cbUID=sqlwlen(szUID);
|
||||
if(cbAuthStr==SQL_NTS)cbAuthStr=sqlwlen(szAuthStr);
|
||||
{
|
||||
size_t l1=cbDSN*4;
|
||||
size_t l2=cbUID*4;
|
||||
size_t l3=cbAuthStr*4;
|
||||
SQLCHAR *tmp1=calloc(l1,1),*tmp2=calloc(l2,1),*tmp3=calloc(l3,1);
|
||||
SQLRETURN ret;
|
||||
l1 = unicode2ascii((struct _hdbc *)hdbc, szDSN, cbDSN, tmp1, l1);
|
||||
l2 = unicode2ascii((struct _hdbc *)hdbc, szUID, cbUID, tmp2, l2);
|
||||
l3 = unicode2ascii((struct _hdbc *)hdbc, szAuthStr, cbAuthStr, tmp3, l3);
|
||||
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
|
||||
free(tmp1),free(tmp2),free(tmp3);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLDescribeColW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLWCHAR *szColName,
|
||||
SQLSMALLINT cbColNameMax,
|
||||
SQLSMALLINT *pcbColName,
|
||||
SQLSMALLINT *pfSqlType,
|
||||
SQLULEN *pcbColDef, /* precision */
|
||||
SQLSMALLINT *pibScale,
|
||||
SQLSMALLINT *pfNullable)
|
||||
{
|
||||
TRACE("SQLDescribeColW");
|
||||
if(cbColNameMax==SQL_NTS)cbColNameMax=sqlwlen(szColName);
|
||||
{
|
||||
size_t l=cbColNameMax*4+1;
|
||||
SQLCHAR *tmp=calloc(l,1);
|
||||
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, l, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
|
||||
*pcbColName = ascii2unicode(((struct _hstmt*)hstmt)->hdbc, (char*)tmp, l, szColName, cbColNameMax);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLColAttributesW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLUSMALLINT fDescType,
|
||||
SQLPOINTER rgbDesc,
|
||||
SQLSMALLINT cbDescMax,
|
||||
SQLSMALLINT *pcbDesc,
|
||||
SQLLEN *pfDesc)
|
||||
{
|
||||
TRACE("SQLColAttributesW");
|
||||
if (fDescType!=SQL_COLUMN_NAME && fDescType!=SQL_COLUMN_LABEL)
|
||||
return SQLColAttributes(hstmt,icol,fDescType,rgbDesc,cbDescMax,pcbDesc,pfDesc);
|
||||
else{
|
||||
size_t l=cbDescMax*4+1;
|
||||
SQLCHAR *tmp=calloc(l,1);
|
||||
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,l,(SQLSMALLINT*)&l,pfDesc);
|
||||
*pcbDesc = ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, l, (SQLWCHAR*)rgbDesc, cbDescMax);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLErrorW(
|
||||
SQLHENV henv,
|
||||
SQLHDBC hdbc,
|
||||
SQLHSTMT hstmt,
|
||||
SQLWCHAR *szSqlState,
|
||||
SQLINTEGER *pfNativeError,
|
||||
SQLWCHAR *szErrorMsg,
|
||||
SQLSMALLINT cbErrorMsgMax,
|
||||
SQLSMALLINT *pcbErrorMsg)
|
||||
{
|
||||
SQLCHAR szSqlState8[6];
|
||||
SQLCHAR szErrorMsg8[3*cbErrorMsgMax+1];
|
||||
SQLSMALLINT pcbErrorMsg8;
|
||||
SQLRETURN result;
|
||||
|
||||
TRACE("SQLErrorW");
|
||||
|
||||
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
|
||||
if (result == SQL_SUCCESS) {
|
||||
struct _hdbc *dbc = hstmt ? ((struct _hstmt *)hstmt)->hdbc : hdbc;
|
||||
size_t pcb;
|
||||
ascii2unicode(dbc, (char*)szSqlState8, sizeof(szSqlState8), szSqlState, sizeof(szSqlState8));
|
||||
pcb = ascii2unicode(dbc, (char*)szErrorMsg8, pcbErrorMsg8, szErrorMsg, cbErrorMsgMax);
|
||||
if (pcbErrorMsg) *pcbErrorMsg = pcb;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLExecDirectW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLWCHAR *szSqlStr,
|
||||
SQLINTEGER cbSqlStr)
|
||||
{
|
||||
TRACE("SQLExecDirectW");
|
||||
if(cbSqlStr==SQL_NTS)cbSqlStr=sqlwlen(szSqlStr);
|
||||
{
|
||||
size_t l=cbSqlStr*4;
|
||||
SQLCHAR *tmp=calloc(l,1);
|
||||
SQLRETURN ret;
|
||||
l = unicode2ascii(((struct _hstmt *)hstmt)->hdbc, szSqlStr, cbSqlStr, tmp, l);
|
||||
ret = SQLExecDirect(hstmt, tmp, l);
|
||||
TRACE("SQLExecDirectW end");
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLColumnsW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLWCHAR *szCatalogName,
|
||||
SQLSMALLINT cbCatalogName,
|
||||
SQLWCHAR *szSchemaName,
|
||||
SQLSMALLINT cbSchemaName,
|
||||
SQLWCHAR *szTableName,
|
||||
SQLSMALLINT cbTableName,
|
||||
SQLWCHAR *szColumnName,
|
||||
SQLSMALLINT cbColumnName)
|
||||
{
|
||||
if(cbTableName==SQL_NTS)cbTableName=sqlwlen(szTableName);
|
||||
{
|
||||
size_t l=cbTableName*4;
|
||||
SQLCHAR *tmp=calloc(l,1);
|
||||
SQLRETURN ret;
|
||||
l = unicode2ascii(((struct _hstmt* )hstmt)->hdbc, szTableName, cbTableName, tmp, l);
|
||||
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLGetDataW(
|
||||
SQLHSTMT hstmt,
|
||||
SQLUSMALLINT icol,
|
||||
SQLSMALLINT fCType,
|
||||
SQLPOINTER rgbValue,
|
||||
SQLLEN cbValueMax,
|
||||
SQLLEN *pcbValue)
|
||||
{
|
||||
//todo: treat numbers correctly
|
||||
|
||||
size_t l=cbValueMax*4+1;
|
||||
SQLCHAR *tmp=calloc(l,1);
|
||||
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, l, (SQLLEN*)&l);
|
||||
*pcbValue = ascii2unicode(((struct _hstmt *)hstmt)->hdbc, (char*)tmp, l, (SQLWCHAR*)rgbValue, cbValueMax);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SQLRETURN SQL_API SQLGetInfoW(
|
||||
SQLHDBC hdbc,
|
||||
SQLUSMALLINT fInfoType,
|
||||
SQLPOINTER rgbInfoValue,
|
||||
SQLSMALLINT cbInfoValueMax,
|
||||
SQLSMALLINT *pcbInfoValue)
|
||||
{
|
||||
TRACE("SQLGetInfoW");
|
||||
|
||||
if(fInfoType==SQL_MAX_STATEMENT_LEN||fInfoType==SQL_SCHEMA_USAGE||fInfoType==SQL_CATALOG_LOCATION)
|
||||
return SQLGetInfo(hdbc,fInfoType,rgbInfoValue,cbInfoValueMax,pcbInfoValue);
|
||||
|
||||
size_t l=cbInfoValueMax*4+1;
|
||||
SQLCHAR *tmp=calloc(l,1);
|
||||
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, l, (SQLSMALLINT*)&l);
|
||||
size_t pcb = ascii2unicode((struct _hdbc *)hdbc, (char*)tmp, l, (SQLWCHAR*)rgbInfoValue, cbInfoValueMax);
|
||||
if(pcbInfoValue)*pcbInfoValue=pcb;
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @}*/
|
Loading…
Reference in New Issue
Block a user