Merge pull request #333 from mdbtools/odbc-sans-iconv

Remove iconv from ODBC Unicode driver
This commit is contained in:
Evan Miller
2021-08-25 08:34:48 -04:00
committed by GitHub
8 changed files with 385 additions and 370 deletions

View File

@@ -149,6 +149,9 @@ mutually exclusive.
causes the iODBC driver to be built. 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 A list of general options is available in the [INSTALL](./INSTALL) file, and
`configure --help` will give you the list of mdbtools specific options. `configure --help` will give you the list of mdbtools specific options.

View File

@@ -38,7 +38,7 @@ AC_CHECK_DECLS([program_invocation_short_name], [], [], [[
dnl Checks for library functions. dnl Checks for library functions.
VL_LIB_READLINE VL_LIB_READLINE
AC_CHECK_FUNCS(strptime fmemopen gmtime_r reallocf wcstombs_l vasprintf vasnprintf) AC_CHECK_FUNCS(strptime fmemopen gmtime_r reallocf wcstombs_l mbstowcs_l vasprintf vasnprintf)
AM_GCC_ATTRIBUTE_ALIAS AM_GCC_ATTRIBUTE_ALIAS
@@ -97,15 +97,15 @@ AC_ARG_ENABLE(iconv,
HAVE_ICONV_H=0 HAVE_ICONV_H=0
if test "$enable_iconv" = "yes"; then if test "$enable_iconv" = "yes"; then
AM_ICONV AM_ICONV
if test "$am_cv_func_iconv" = "yes"; then # Use the "working iconv" test instead of the "iconv" ($am_cv_func_iconv) test
# so that our HAVE_ICONV_H substitution variable has the same value as the HAVE_ICONV
# C macro
if test "$am_func_iconv" = "yes"; then
HAVE_ICONV_H=1 HAVE_ICONV_H=1
fi fi
fi fi
AC_SUBST(HAVE_ICONV_H) 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 dnl Fuzz testing
AC_ARG_ENABLE([fuzz-testing], AS_HELP_STRING([--enable-fuzz-testing], [enable fuzz testing (requires Clang 6 or later)]), [ 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]) AC_MSG_CHECKING([whether $CC accepts -fsanitize=fuzzer])

View File

@@ -38,7 +38,9 @@
#if MDBTOOLS_H_HAVE_ICONV_H #if MDBTOOLS_H_HAVE_ICONV_H
#include <iconv.h> #include <iconv.h>
#elif MDBTOOLS_H_HAVE_XLOCALE_H #endif
#if MDBTOOLS_H_HAVE_XLOCALE_H
#include <xlocale.h> #include <xlocale.h>
#endif #endif
@@ -65,9 +67,7 @@
// M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc // M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
#define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname #define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname
#if !MDBTOOLS_H_HAVE_ICONV_H
typedef @LOCALE_T@ mdb_locale_t; typedef @LOCALE_T@ mdb_locale_t;
#endif
enum { enum {
MDB_PAGE_DB = 0, MDB_PAGE_DB = 0,

View File

@@ -1,11 +1,18 @@
# iconv.m4 serial 19 (gettext-0.18.2) # iconv.m4 serial 24
dnl Copyright (C) 2000-2002, 2007-2014, 2016 Free Software Foundation, Inc. dnl Copyright (C) 2000-2002, 2007-2014, 2016-2021 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it, dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved. dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible. dnl From Bruno Haible.
AC_PREREQ([2.64])
dnl Note: AM_ICONV is documented in the GNU gettext manual
dnl <https://www.gnu.org/software/gettext/manual/html_node/AM_005fICONV.html>.
dnl Don't make changes that are incompatible with that documentation!
AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
[ [
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
@@ -85,8 +92,9 @@ AC_DEFUN([AM_ICONV_LINK],
#endif #endif
]], ]],
[[int result = 0; [[int result = 0;
/* Test against AIX 5.1 bug: Failures are not distinguishable from successful /* Test against AIX 5.1...7.2 bug: Failures are not distinguishable from
returns. */ successful returns. This is even documented in
<https://www.ibm.com/support/knowledgecenter/ssw_aix_72/i_bostechref/iconv.html> */
{ {
iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
if (cd_utf8_to_88591 != (iconv_t)(-1)) if (cd_utf8_to_88591 != (iconv_t)(-1))
@@ -167,15 +175,27 @@ AC_DEFUN([AM_ICONV_LINK],
#endif #endif
/* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
provided. */ provided. */
if (/* Try standardized names. */ {
iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) /* Try standardized names. */
/* Try IRIX, OSF/1 names. */ iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP");
&& iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) /* Try IRIX, OSF/1 names. */
/* Try AIX names. */ iconv_t cd2 = iconv_open ("UTF-8", "eucJP");
&& iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) /* Try AIX names. */
/* Try HP-UX names. */ iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP");
&& iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) /* Try HP-UX names. */
result |= 16; iconv_t cd4 = iconv_open ("utf8", "eucJP");
if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1)
&& cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1))
result |= 16;
if (cd1 != (iconv_t)(-1))
iconv_close (cd1);
if (cd2 != (iconv_t)(-1))
iconv_close (cd2);
if (cd3 != (iconv_t)(-1))
iconv_close (cd3);
if (cd4 != (iconv_t)(-1))
iconv_close (cd4);
}
return result; return result;
]])], ]])],
[am_cv_func_iconv_works=yes], , [am_cv_func_iconv_works=yes], ,
@@ -212,8 +232,7 @@ AC_DEFUN([AM_ICONV_LINK],
AC_SUBST([LTLIBICONV]) AC_SUBST([LTLIBICONV])
]) ])
dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to dnl Define AM_ICONV using AC_DEFUN_ONCE, in order to avoid warnings like
dnl avoid warnings like
dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
dnl This is tricky because of the way 'aclocal' is implemented: dnl This is tricky because of the way 'aclocal' is implemented:
dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN.
@@ -221,51 +240,44 @@ dnl Otherwise aclocal's initial scan pass would miss the macro definition.
dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions.
dnl Otherwise aclocal would emit many "Use of uninitialized value $1" dnl Otherwise aclocal would emit many "Use of uninitialized value $1"
dnl warnings. dnl warnings.
m4_define([gl_iconv_AC_DEFUN], AC_DEFUN_ONCE([AM_ICONV],
m4_version_prereq([2.64],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[m4_ifdef([gl_00GNULIB],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[[AC_DEFUN(
[$1], [$2])]])]))
gl_iconv_AC_DEFUN([AM_ICONV],
[ [
AM_ICONV_LINK AM_ICONV_LINK
if test "$am_cv_func_iconv" = yes; then if test "$am_cv_func_iconv" = yes; then
AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_CHECK([whether iconv is compatible with its POSIX signature],
AC_CACHE_VAL([am_cv_proto_iconv], [ [gl_cv_iconv_nonconst],
AC_COMPILE_IFELSE( [AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM( [AC_LANG_PROGRAM(
[[ [[
#include <stdlib.h> #include <stdlib.h>
#include <iconv.h> #include <iconv.h>
extern extern
#ifdef __cplusplus #ifdef __cplusplus
"C" "C"
#endif #endif
#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else ]],
size_t iconv(); [[]])],
#endif [gl_cv_iconv_nonconst=yes],
]], [gl_cv_iconv_nonconst=no])
[[]])],
[am_cv_proto_iconv_arg1=""],
[am_cv_proto_iconv_arg1="const"])
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([
$am_cv_proto_iconv])
AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1],
[Define as const if the declaration of iconv() needs const.])
dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>.
m4_ifdef([gl_ICONV_H_DEFAULTS],
[AC_REQUIRE([gl_ICONV_H_DEFAULTS])
if test -n "$am_cv_proto_iconv_arg1"; then
ICONV_CONST="const"
fi
]) ])
else
dnl When compiling GNU libiconv on a system that does not have iconv yet,
dnl pick the POSIX compliant declaration without 'const'.
gl_cv_iconv_nonconst=yes
fi fi
if test $gl_cv_iconv_nonconst = yes; then
iconv_arg1=""
else
iconv_arg1="const"
fi
AC_DEFINE_UNQUOTED([ICONV_CONST], [$iconv_arg1],
[Define as const if the declaration of iconv() needs const.])
dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>.
m4_ifdef([gl_ICONV_H_DEFAULTS],
[AC_REQUIRE([gl_ICONV_H_DEFAULTS])
if test $gl_cv_iconv_nonconst != yes; then
ICONV_CONST="const"
fi
])
]) ])

View File

@@ -7,12 +7,9 @@ AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) $(ODBC_CFLAGS)
libmdbodbc_la_SOURCES = odbc.c connectparams.c libmdbodbc_la_SOURCES = odbc.c connectparams.c
libmdbodbc_la_LIBADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(ODBC_LIBS) libmdbodbc_la_LIBADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(ODBC_LIBS)
libmdbodbc_la_LDFLAGS = -avoid-version -export-symbols-regex '^(SQL|ODBCINST)' $(ODBC_LDFLAGS) libmdbodbc_la_LDFLAGS = -avoid-version -export-symbols-regex '^(SQL|ODBCINST)' $(ODBC_LDFLAGS)
if ICONV
lib_LTLIBRARIES += libmdbodbcW.la lib_LTLIBRARIES += libmdbodbcW.la
libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES) libmdbodbcW_la_SOURCES = $(libmdbodbc_la_SOURCES) odbcw.c
libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD) @LIBICONV@ libmdbodbcW_la_LIBADD = $(libmdbodbc_la_LIBADD)
libmdbodbcW_la_LDFLAGS = $(libmdbodbc_la_LDFLAGS) libmdbodbcW_la_LDFLAGS = $(libmdbodbc_la_LDFLAGS)
libmdbodbcW_la_CFLAGS = $(AM_CFLAGS) -D ENABLE_ODBC_W=1
endif
LIBS = $(GLIB_LIBS) LIBS = $(GLIB_LIBS)
unittest_LDADD = libmdbodbc.la ../libmdb/libmdb.la ../sql/libmdbsql.la unittest_LDADD = libmdbodbc.la ../libmdb/libmdb.la ../sql/libmdbsql.la

View File

@@ -50,10 +50,7 @@ struct _hdbc {
GPtrArray *statements; GPtrArray *statements;
char lastError[256]; char lastError[256];
char sqlState[6]; char sqlState[6];
#ifdef ENABLE_ODBC_W mdb_locale_t locale;
iconv_t iconv_in;
iconv_t iconv_out;
#endif
}; };
struct _hstmt { struct _hstmt {
MdbSQL *sql; MdbSQL *sql;

View File

@@ -16,11 +16,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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 <sql.h>
#include <sqlext.h> #include <sqlext.h>
#include <string.h> #include <string.h>
@@ -85,64 +80,6 @@ TypeInfo type_info[] = {
#define NUM_TYPE_INFO_COLS 19 #define NUM_TYPE_INFO_COLS 19
#define MAX_TYPE_INFO 11 #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, ...) static void LogHandleError(struct _hdbc* dbc, const char* format, ...)
{ {
va_list argp; va_list argp;
@@ -213,36 +150,6 @@ SQLRETURN SQL_API SQLDriverConnect(
return SQL_ERROR; 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( SQLRETURN SQL_API SQLBrowseConnect(
SQLHDBC hdbc, SQLHDBC hdbc,
SQLCHAR *szConnStrIn, SQLCHAR *szConnStrIn,
@@ -498,8 +405,10 @@ 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 #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
_init_iconv(dbc); dbc->locale = _create_locale(LC_CTYPE, ".65001");
#else
dbc->locale = newlocale(LC_CTYPE_MASK, "C.UTF-8", NULL);
#endif #endif
*phdbc=dbc; *phdbc=dbc;
@@ -645,36 +554,6 @@ SQLRETURN SQL_API SQLConnect(
return ret; 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( SQLRETURN SQL_API SQLDescribeCol(
SQLHSTMT hstmt, SQLHSTMT hstmt,
SQLUSMALLINT icol, SQLUSMALLINT icol,
@@ -743,32 +622,6 @@ SQLRETURN SQL_API SQLDescribeCol(
return ret; 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( SQLRETURN SQL_API SQLColAttributes(
SQLHSTMT hstmt, SQLHSTMT hstmt,
SQLUSMALLINT icol, SQLUSMALLINT icol,
@@ -874,31 +727,6 @@ SQLRETURN SQL_API SQLColAttributes(
return ret; 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( SQLRETURN SQL_API SQLDisconnect(
SQLHDBC hdbc) SQLHDBC hdbc)
{ {
@@ -958,39 +786,6 @@ SQLRETURN SQL_API SQLError(
return result; 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) SQLRETURN SQL_API SQLExecute(SQLHSTMT hstmt)
{ {
struct _hstmt *stmt = (struct _hstmt *) hstmt; struct _hstmt *stmt = (struct _hstmt *) hstmt;
@@ -1021,27 +816,6 @@ SQLRETURN SQL_API SQLExecDirect(
return SQLExecute(hstmt); 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 static void
unbind_columns(struct _hstmt *stmt) unbind_columns(struct _hstmt *stmt)
{ {
@@ -1111,8 +885,10 @@ 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 #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(WINDOWS)
_free_iconv(dbc); if (dbc->locale) _free_locale(dbc->locale);
#else
if (dbc->locale) freelocale(dbc->locale);
#endif #endif
g_free(dbc); g_free(dbc);
@@ -1382,31 +1158,6 @@ SQLRETURN SQL_API SQLColumns(
return SQL_SUCCESS; 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( SQLRETURN SQL_API SQLGetConnectOption(
SQLHDBC hdbc, SQLHDBC hdbc,
SQLUSMALLINT fOption, SQLUSMALLINT fOption,
@@ -1719,27 +1470,6 @@ SQLRETURN SQL_API SQLGetData(
return SQL_SUCCESS; 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) static void _set_func_exists(SQLUSMALLINT *pfExists, SQLUSMALLINT fFunction)
{ {
SQLUSMALLINT *mod; SQLUSMALLINT *mod;
@@ -1974,31 +1704,6 @@ SQLRETURN SQL_API SQLGetInfo(
return SQL_SUCCESS; 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( SQLRETURN SQL_API SQLGetStmtOption(
SQLHSTMT hstmt, SQLHSTMT hstmt,
SQLUSMALLINT fOption, SQLUSMALLINT fOption,

301
src/odbc/odbcw.c Normal file
View 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_MBSTOWCS_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;
}
/** @}*/