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.
```
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.

View File

@@ -38,7 +38,7 @@ AC_CHECK_DECLS([program_invocation_short_name], [], [], [[
dnl Checks for library functions.
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
@@ -97,15 +97,15 @@ AC_ARG_ENABLE(iconv,
HAVE_ICONV_H=0
if test "$enable_iconv" = "yes"; then
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
fi
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])

View File

@@ -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,

View File

@@ -1,11 +1,18 @@
# iconv.m4 serial 19 (gettext-0.18.2)
dnl Copyright (C) 2000-2002, 2007-2014, 2016 Free Software Foundation, Inc.
# iconv.m4 serial 24
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 gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
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],
[
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
@@ -85,8 +92,9 @@ AC_DEFUN([AM_ICONV_LINK],
#endif
]],
[[int result = 0;
/* Test against AIX 5.1 bug: Failures are not distinguishable from successful
returns. */
/* Test against AIX 5.1...7.2 bug: Failures are not distinguishable from
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");
if (cd_utf8_to_88591 != (iconv_t)(-1))
@@ -167,15 +175,27 @@ AC_DEFUN([AM_ICONV_LINK],
#endif
/* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
provided. */
if (/* Try standardized names. */
iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
/* Try IRIX, OSF/1 names. */
&& iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
/* Try AIX names. */
&& iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
/* Try HP-UX names. */
&& iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
result |= 16;
{
/* Try standardized names. */
iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP");
/* Try IRIX, OSF/1 names. */
iconv_t cd2 = iconv_open ("UTF-8", "eucJP");
/* Try AIX names. */
iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP");
/* Try HP-UX names. */
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;
]])],
[am_cv_func_iconv_works=yes], ,
@@ -212,8 +232,7 @@ AC_DEFUN([AM_ICONV_LINK],
AC_SUBST([LTLIBICONV])
])
dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to
dnl avoid warnings like
dnl Define AM_ICONV using AC_DEFUN_ONCE, in order to avoid warnings like
dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
dnl This is tricky because of the way 'aclocal' is implemented:
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 Otherwise aclocal would emit many "Use of uninitialized value $1"
dnl warnings.
m4_define([gl_iconv_AC_DEFUN],
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],
AC_DEFUN_ONCE([AM_ICONV],
[
AM_ICONV_LINK
if test "$am_cv_func_iconv" = yes; then
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL([am_cv_proto_iconv], [
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[
AC_CACHE_CHECK([whether iconv is compatible with its POSIX signature],
[gl_cv_iconv_nonconst],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdlib.h>
#include <iconv.h>
extern
#ifdef __cplusplus
"C"
#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);
#else
size_t iconv();
#endif
]],
[[]])],
[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
]],
[[]])],
[gl_cv_iconv_nonconst=yes],
[gl_cv_iconv_nonconst=no])
])
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
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_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

View File

@@ -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;

View File

@@ -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
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;
}
/** @}*/