Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -233,31 +233,31 @@ test: test-jet test-sqlserver test-sqlite test-jet: binaries libraries @echo testing tdbcodbc against Jet - TDBCODBC_TYPE=jet \ + TDBCODBC_TEST_TYPE=jet \ $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ -load "package ifneeded tdbc::odbc $(PACKAGE_VERSION) \ [list source `@CYGPATH@ $(srcdir)/library/tdbcodbc.tcl`]\;[list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" test-sqlserver: binaries libraries @echo testing tdbcodbc against SQL Server - TDBCODBC_TYPE=sqlserver \ + TDBCODBC_TEST_TYPE=sqlserver \ $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ -load "package ifneeded tdbc::odbc ${PACKAGE_VERSION} \ [list source `@CYGPATH@ $(srcdir)/library/tdbcodbc.tcl`]\;[list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" test-sqlite: binaries libraries @echo testing tdbcodbc against SQLite - TDBCODBC_TYPE=sqlite \ + TDBCODBC_TEST_TYPE=sqlite \ $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ -load "package ifneeded tdbc::odbc ${PACKAGE_VERSION} \ [list source `@CYGPATH@ $(srcdir)/library/tdbcodbc.tcl`]\;[list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" valgrind-sqlite: binaries libraries - TDBCODBC_TYPE=sqlite \ + TDBCODBC_TEST_TYPE=sqlite \ $(PKG_ENV) $(TCLSH_ENV) \ LD_PRELOAD=$(PKG_LIB_FILE) \ $(VALGRIND) $(VALGRINDARGS) \ $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ -load "package ifneeded tdbc::odbc ${PACKAGE_VERSION} \ Index: README ================================================================== --- README +++ README @@ -1,8 +1,8 @@ README: tdbcodbc - This is the 1.0.6 source distribution of the bridge between Tcl + This is the 1.1.0 source distribution of the bridge between Tcl Database Connectivity (TDBC) and Open Database Connectivity (ODBC), a database-neutral API layer available on all Windows systems and many others.. TDBC and its drivers are available from a Fossil version control repository at http://tdbc.tcl.tk/ Index: configure ================================================================== --- configure +++ configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for tdbcodbc 1.0.6. +# Generated by GNU Autoconf 2.69 for tdbcodbc 1.1.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # @@ -575,12 +575,12 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tdbcodbc' PACKAGE_TARNAME='tdbcodbc' -PACKAGE_VERSION='1.0.6' -PACKAGE_STRING='tdbcodbc 1.0.6' +PACKAGE_VERSION='1.1.0' +PACKAGE_STRING='tdbcodbc 1.1.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -722,10 +722,11 @@ htmldir infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir @@ -804,10 +805,11 @@ datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' @@ -1055,10 +1057,19 @@ psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) @@ -1193,11 +1204,11 @@ # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) @@ -1306,11 +1317,11 @@ # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures tdbcodbc 1.0.6 to adapt to many kinds of systems. +\`configure' configures tdbcodbc 1.1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. @@ -1346,10 +1357,11 @@ --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] @@ -1367,11 +1379,11 @@ _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of tdbcodbc 1.0.6:";; + short | recursive ) echo "Configuration of tdbcodbc 1.1.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options @@ -1470,11 +1482,11 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -tdbcodbc configure 1.0.6 +tdbcodbc configure 1.1.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -2072,11 +2084,11 @@ } # ac_fn_c_compute_int cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by tdbcodbc $as_me 1.0.6, which was +It was created by tdbcodbc $as_me 1.1.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF @@ -10067,11 +10079,11 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by tdbcodbc $as_me 1.0.6, which was +This file was extended by tdbcodbc $as_me 1.1.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS @@ -10120,11 +10132,11 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -tdbcodbc config.status 1.0.6 +tdbcodbc config.status 1.1.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -9,11 +9,11 @@ # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- -AC_INIT([tdbcodbc], [1.0.6]) +AC_INIT([tdbcodbc], [1.1.0]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. Index: generic/fakesql.h ================================================================== --- generic/fakesql.h +++ generic/fakesql.h @@ -90,10 +90,11 @@ /* Null handles */ #define SQL_NULL_HANDLE ((SQLHANDLE) 0) #define SQL_NULL_HENV ((SQLHENV) 0) +#define SQL_NULL_HDBC ((SQLHDBC) 0) #define SQL_NULL_HSTMT ((SQLHSTMT) 0) /* SQL data types */ enum _SQL_DATATYPE { @@ -142,10 +143,11 @@ #define SQL_ERROR (-1) #define SQL_NO_DATA 100 #define SQL_NO_TOTAL (-4) #define SQL_SUCCESS 0 #define SQL_SUCCESS_WITH_INFO 1 +#define SQL_SUCCEEDED(rc) (((rc)&(~1))==0) /* Diagnostic fields */ enum _SQL_DIAG { SQL_DIAG_SQLSTATE = 4, @@ -173,10 +175,11 @@ #define SQL_ATTR_ACCESS_MODE SQL_ACCESS_MODE #define SQL_ATTR_CONNECTION_TIMEOUT 113 #define SQL_ATTR_ODBC_VERSION 200 #define SQL_ATTR_TXN_ISOLATION SQL_TXN_ISOLATION +#define SQL_ATTR_AUTOCOMMIT SQL_AUTOCOMMIT /* Nullable? */ #define SQL_NULLABLE_UNKNOWN 2 @@ -185,10 +188,11 @@ #define SQL_NULL_DATA (-1) /* ODBC versions */ #define SQL_OV_ODBC3 3UL +#define SQL_ODBC_VER 10 /* SQLDriverConnect flags */ #define SQL_DRIVER_COMPLETE_REQUIRED 3 #define SQL_DRIVER_NOPROMPT 0 Index: generic/odbcStubDefs.txt ================================================================== --- generic/odbcStubDefs.txt +++ generic/odbcStubDefs.txt @@ -10,11 +10,10 @@ # Accordingly, this file is in the public domain. # #----------------------------------------------------------------------------- * STUBSTRUCT: odbcStubs -* LIBRARY: odbc32 odbc libodbc32 libodbc * CONVENTION: SQL_API SQLRETURN SQLAllocHandle(SQLSMALLINT,SQLHANDLE,SQLHANDLE*); SQLRETURN SQLBindParameter(SQLHSTMT,SQLUSMALLINT,SQLSMALLINT,SQLSMALLINT,SQLSMALLINT,SQLULEN,SQLSMALLINT,SQLPOINTER,SQLLEN,SQLLEN*); SQLRETURN SQLCloseCursor(SQLHSTMT); @@ -32,10 +31,11 @@ SQLRETURN SQLFreeHandle(SQLSMALLINT,SQLHANDLE); SQLRETURN SQLGetConnectAttr(SQLHDBC,SQLINTEGER,SQLPOINTER,SQLINTEGER,SQLINTEGER*); SQLRETURN SQLGetData(SQLHSTMT,SQLUSMALLINT,SQLSMALLINT,SQLPOINTER,SQLLEN,SQLLEN*); SQLRETURN SQLGetDiagFieldA(SQLSMALLINT,SQLHANDLE,SQLSMALLINT,SQLSMALLINT,SQLPOINTER,SQLSMALLINT,SQLSMALLINT*); SQLRETURN SQLGetDiagRecW(SQLSMALLINT,SQLHANDLE,SQLSMALLINT,SQLWCHAR*,SQLINTEGER*,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*); +SQLRETURN SQLGetInfoW(SQLHANDLE,SQLUSMALLINT,SQLPOINTER,SQLSMALLINT,SQLSMALLINT*); SQLRETURN SQLGetTypeInfo(SQLHSTMT,SQLSMALLINT); SQLRETURN SQLMoreResults(SQLHSTMT); SQLRETURN SQLNumParams(SQLHSTMT,SQLSMALLINT*); SQLRETURN SQLNumResultCols(SQLHSTMT,SQLSMALLINT*); SQLRETURN SQLPrepareW(SQLHSTMT,SQLWCHAR*,SQLINTEGER); Index: generic/odbcStubInit.c ================================================================== --- generic/odbcStubInit.c +++ generic/odbcStubInit.c @@ -2,11 +2,11 @@ * odbcStubInit.c -- * * Stubs tables for the foreign ODBC libraries so that * Tcl extensions can use them without the linker's knowing about them. * - * @CREATED@ 2017-06-05 16:16:37Z by genExtStubs.tcl from ../generic/odbcStubDefs.txt + * @CREATED@ 2018-05-12 16:18:48Z by genExtStubs.tcl from odbcStubDefs.txt * * Copyright (c) 2010 by Kevin B. Kenny. * * Please refer to the file, 'license.terms' for the conditions on * redistribution of this file and for a DISCLAIMER OF ALL WARRANTIES. @@ -56,17 +56,30 @@ }; #else static const char *const odbcStubLibNames[] = { - /* @LIBNAMES@: DO NOT EDIT THESE NAMES */ - "odbc32", "odbc", "libodbc32", "libodbc", NULL +#if defined(__APPLE__) + "libiodbc.2", +#elif defined(__OpenBSD__) + "libiodbc", +#else + "odbc32", "odbc", "libodbc32", "libodbc", "libiodbc", +#endif + NULL /* @END@ */ }; static const char *const odbcOptLibNames[] = { +#if defined(__APPLE__) + "libiodbcinst.2", +#elif defined(__OpenBSD__) + "libiodbcinst", +#else "odbccp", "odbccp32", "odbcinst", - "libodbccp", "libodbccp32", "libodbcinst", NULL + "libodbccp", "libodbccp32", "libodbcinst", "libiodbcinst", +#endif + NULL }; #endif @@ -93,10 +106,11 @@ "SQLFreeHandle", "SQLGetConnectAttr", "SQLGetData", "SQLGetDiagFieldA", "SQLGetDiagRecW", + "SQLGetInfoW", "SQLGetTypeInfo", "SQLMoreResults", "SQLNumParams", "SQLNumResultCols", "SQLPrepareW", Index: generic/odbcStubs.h ================================================================== --- generic/odbcStubs.h +++ generic/odbcStubs.h @@ -1,22 +1,19 @@ /* *----------------------------------------------------------------------------- * - * ../generic/odbcStubs.h -- + * odbcStubs.h -- * * Stubs for procedures in odbcStubDefs.txt * * Generated by genExtStubs.tcl: DO NOT EDIT - * 2017-06-05 16:16:37Z + * 2018-05-12 16:18:48Z * *----------------------------------------------------------------------------- */ typedef struct odbcStubDefs { - - /* Functions from libraries: odbc32 odbc libodbc32 libodbc */ - SQLRETURN (SQL_API*SQLAllocHandlePtr)(SQLSMALLINT,SQLHANDLE,SQLHANDLE*); SQLRETURN (SQL_API*SQLBindParameterPtr)(SQLHSTMT,SQLUSMALLINT,SQLSMALLINT,SQLSMALLINT,SQLSMALLINT,SQLULEN,SQLSMALLINT,SQLPOINTER,SQLLEN,SQLLEN*); SQLRETURN (SQL_API*SQLCloseCursorPtr)(SQLHSTMT); SQLRETURN (SQL_API*SQLColumnsWPtr)(SQLHSTMT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT ,SQLWCHAR*,SQLSMALLINT ); SQLRETURN (SQL_API*SQLDataSourcesWPtr)(SQLHENV,SQLUSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*); @@ -32,10 +29,11 @@ SQLRETURN (SQL_API*SQLFreeHandlePtr)(SQLSMALLINT,SQLHANDLE); SQLRETURN (SQL_API*SQLGetConnectAttrPtr)(SQLHDBC,SQLINTEGER,SQLPOINTER,SQLINTEGER,SQLINTEGER*); SQLRETURN (SQL_API*SQLGetDataPtr)(SQLHSTMT,SQLUSMALLINT,SQLSMALLINT,SQLPOINTER,SQLLEN,SQLLEN*); SQLRETURN (SQL_API*SQLGetDiagFieldAPtr)(SQLSMALLINT,SQLHANDLE,SQLSMALLINT,SQLSMALLINT,SQLPOINTER,SQLSMALLINT,SQLSMALLINT*); SQLRETURN (SQL_API*SQLGetDiagRecWPtr)(SQLSMALLINT,SQLHANDLE,SQLSMALLINT,SQLWCHAR*,SQLINTEGER*,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*); + SQLRETURN (SQL_API*SQLGetInfoWPtr)(SQLHANDLE,SQLUSMALLINT,SQLPOINTER,SQLSMALLINT,SQLSMALLINT*); SQLRETURN (SQL_API*SQLGetTypeInfoPtr)(SQLHSTMT,SQLSMALLINT); SQLRETURN (SQL_API*SQLMoreResultsPtr)(SQLHSTMT); SQLRETURN (SQL_API*SQLNumParamsPtr)(SQLHSTMT,SQLSMALLINT*); SQLRETURN (SQL_API*SQLNumResultColsPtr)(SQLHSTMT,SQLSMALLINT*); SQLRETURN (SQL_API*SQLPrepareWPtr)(SQLHSTMT,SQLWCHAR*,SQLINTEGER); @@ -63,10 +61,11 @@ #define SQLFreeHandle (odbcStubs->SQLFreeHandlePtr) #define SQLGetConnectAttr (odbcStubs->SQLGetConnectAttrPtr) #define SQLGetData (odbcStubs->SQLGetDataPtr) #define SQLGetDiagFieldA (odbcStubs->SQLGetDiagFieldAPtr) #define SQLGetDiagRecW (odbcStubs->SQLGetDiagRecWPtr) +#define SQLGetInfoW (odbcStubs->SQLGetInfoWPtr) #define SQLGetTypeInfo (odbcStubs->SQLGetTypeInfoPtr) #define SQLMoreResults (odbcStubs->SQLMoreResultsPtr) #define SQLNumParams (odbcStubs->SQLNumParamsPtr) #define SQLNumResultCols (odbcStubs->SQLNumResultColsPtr) #define SQLPrepareW (odbcStubs->SQLPrepareWPtr) Index: generic/tdbcodbc.c ================================================================== --- generic/tdbcodbc.c +++ generic/tdbcodbc.c @@ -47,10 +47,12 @@ static Tcl_LoadHandle odbcInstLoadHandle = NULL; /* Handle to the ODBC installer library */ static SQLHENV hEnv = SQL_NULL_HENV; /* Handle to the global ODBC environment */ static int hEnvRefCount = 0; /* Reference count on the global environment */ +static int sizeofSQLWCHAR = sizeof(SQLWCHAR); + /* Preset, will be autodetected later */ /* * Objects to create within the literal pool */ @@ -781,14 +783,66 @@ Tcl_DString* ds, /* Output string */ SQLWCHAR* ws, /* Input string */ int len /* Length of the input string in characters */ ) { int i; - char buf[4] = ""; - for (i = 0; i < len; ++i) { - int bytes = Tcl_UniCharToUtf((int) ws[i], buf); - Tcl_DStringAppend(ds, buf, bytes); + char buf[TCL_UTF_MAX]; + + if (sizeofSQLWCHAR == sizeof(unsigned short)) { + unsigned short* ptr16 = (unsigned short*) ws; + + for (i = 0; i < len; ++i) { + unsigned int ch; + int bytes; + + ch = ptr16[i]; + if (ch > 0x10ffff) { + ch = 0xfffd; + } +#if TCL_UTF_MAX >= 4 + /* Collapse a surrogate pair, if any. */ + if (ch >= 0xd800 && ch <= 0xdbff) { + if (i + 1 < len) { + unsigned int ch2 = ptr16[i+1]; + + if (ch2 >= 0xdc00 && ch2 <= 0xdfff) { + ch = ((ch & 0x3ff) << 10) + 0x10000 + (ch2 & 0x3ff); + i++; + } + } + } +#endif + bytes = Tcl_UniCharToUtf(ch, buf); + Tcl_DStringAppend(ds, buf, bytes); + } + } else { + unsigned int* ptr32 = (unsigned int*) ws; + + for (i = 0; i < len; ++i) { + unsigned int ch; + int bytes; + + ch = ptr32[i]; + if (ch > 0x10ffff) { + ch = 0xfffd; + } +#if TCL_UTF_MAX >= 4 + /* Collapse a surrogate pair, if any. */ + if (ch >= 0xd800 && ch <= 0xdbff) { + if (i + 1 < len) { + unsigned int ch2 = ptr32[i+1]; + + if (ch2 >= 0xdc00 && ch2 <= 0xdfff) { + ch = ((ch & 0x3ff) << 10) + 0x10000 + (ch2 & 0x3ff); + i++; + } + } + } +#endif + bytes = Tcl_UniCharToUtf(ch, buf); + Tcl_DStringAppend(ds, buf, bytes); + } } } /* *----------------------------------------------------------------------------- @@ -811,24 +865,94 @@ static SQLWCHAR* GetWCharStringFromObj( Tcl_Obj* obj, /* Tcl object whose string rep is desired */ int* lengthPtr /* Length of the string */ ) { - int len = Tcl_GetCharLength(obj); - /* Length of the input string in characters */ - SQLWCHAR* retval = (SQLWCHAR*) ckalloc((len + 1) * sizeof(SQLWCHAR)); - /* Buffer to hold the converted string */ - char* bytes = Tcl_GetString(obj); + int len; /* Length of the input string in bytes */ + char* bytes = Tcl_GetStringFromObj(obj, &len); /* UTF-8 representation of the input string */ - int i; + char* end = bytes + len; /* End of UTF-8 representation */ + SQLWCHAR* retval; /* Buffer to hold the converted string */ + SQLWCHAR* wcPtr; + int shrink = 0; Tcl_UniChar ch = 0; - for (i = 0; i < len; ++i) { - bytes += Tcl_UtfToUniChar(bytes, &ch); - retval[i] = ch; + len = (len + 1) * sizeofSQLWCHAR; +#if TCL_UTF_MAX > 4 + if (sizeofSQLWCHAR < sizeof(Tcl_UniChar)) { + len *= 2; /* doubled space for surrogates */ + shrink = 1; } - retval[i] = 0; +#endif + retval = wcPtr = (SQLWCHAR*) ckalloc(len); + + if (sizeofSQLWCHAR == sizeof(unsigned short)) { + unsigned short *ptr16 = (unsigned short*) wcPtr; + + while (bytes < end) { + unsigned int uch; + + if (Tcl_UtfCharComplete(bytes, end - bytes)) { + bytes += Tcl_UtfToUniChar(bytes, &ch); + } else { + ch = *bytes++ & 0x00ff; + } + uch = ch; +#if TCL_UTF_MAX > 4 + if (uch > 0xffff) { + *ptr16++ = (((uch - 0x10000) >> 10) & 0x3ff) | 0xd800; + uch = ((uch - 0x10000) & 0x3ff) | 0xdc00; + } +#endif + if (uch > 0x7f) { + shrink = 1; + } + *ptr16++ = uch; + } + *ptr16 = 0; + len = ptr16 - (unsigned short*) retval; + wcPtr = (SQLWCHAR*) ptr16; + } else { + unsigned int *ptr32 = (unsigned int*) wcPtr; + + while (bytes < end) { + unsigned int uch; + + if (Tcl_UtfCharComplete(bytes, end - bytes)) { + bytes += Tcl_UtfToUniChar(bytes, &ch); + } else { + ch = *bytes++ & 0x00ff; + } + uch = ch; +#if TCL_UTF_MAX == 4 + if ((uch & 0xfc00) == 0xd800) { + if (Tcl_UtfCharComplete(bytes, end - bytes)) { + len = Tcl_UtfToUniChar(bytes, &ch); + if ((ch & 0xfc00) == 0xdc00) { + bytes += len; + uch = (((uch & 0x3ff) << 10) | (ch & 0x3ff)) + 0x10000; + } + } + } +#endif + if (uch > 0x7f) { + shrink = 1; + } + *ptr32++ = uch; + } + *ptr32 = 0; + len = ptr32 - (unsigned int*) retval; + wcPtr = (SQLWCHAR*) ptr32; + } + + if (shrink) { + /* Shrink buffer to fit result */ + wcPtr = (SQLWCHAR*) ckrealloc(retval, (len + 1) * sizeofSQLWCHAR); + if (wcPtr != NULL) { + retval = wcPtr; + } + } if (lengthPtr != NULL) { *lengthPtr = len; } return retval; } @@ -858,34 +982,39 @@ SQLSMALLINT handleType, /* Type of the handle for which the error * has been reported. */ SQLHANDLE handle, /* Handle that reported the error */ const char* info /* Additional information to report */ ) { - SQLWCHAR state[6]; /* SQL state code */ + SQLWCHAR state[6*2]; /* SQL state code */ SQLINTEGER nativeError; /* Native error code */ SQLSMALLINT msgLen; /* Length of the error message */ - SQLWCHAR msg[SQL_MAX_MESSAGE_LENGTH]; + SQLWCHAR msg[(SQL_MAX_MESSAGE_LENGTH+1)*2]; /* Buffer to hold the error message */ SQLSMALLINT i; /* Loop index for going through diagnostics */ const char* sep = ""; /* Separator string for messages */ const char* sqlstate; /* SQL state */ Tcl_Obj* resultObj; /* Result string containing error message */ Tcl_Obj* codeObj; /* Error code object */ Tcl_Obj* lineObj; /* Object holding one diagnostic */ Tcl_DString bufferDS; /* Buffer for transferring messages */ - - SQLRETURN sqlreturn; + SQLRETURN rc; /* SQL result */ resultObj = Tcl_NewObj(); codeObj = Tcl_NewStringObj("TDBC", -1); /* Loop through the diagnostics */ i = 1; - while ((sqlreturn = SQLGetDiagRecW(handleType, handle, i, state, &nativeError, - msg, SQL_MAX_MESSAGE_LENGTH, &msgLen)) - != SQL_NO_DATA && sqlreturn >= 0) { + while (1) { + msg[0] = msg[1] = 0; + msgLen = 0; + state[0] = state[1] = 0; + rc = SQLGetDiagRecW(handleType, handle, i, state, &nativeError, + msg, SQL_MAX_MESSAGE_LENGTH, &msgLen); + if (!SQL_SUCCEEDED(rc) || rc == SQL_NO_DATA) { + break; + } /* Add the diagnostic to ::errorCode */ Tcl_DStringInit(&bufferDS); DStringAppendWChars(&bufferDS, state, 5); @@ -953,15 +1082,21 @@ const char* sqlstate /* State to look for */ ) { SQLCHAR state[6]; /* SQL state code from the diagnostic record */ SQLSMALLINT stateLen; /* String length of the state code */ SQLSMALLINT i; /* Loop index */ + SQLRETURN rc; /* SQL result */ i = 1; - while (SQLGetDiagFieldA(handleType, handle, i, SQL_DIAG_SQLSTATE, - (SQLPOINTER) state, sizeof (state), &stateLen) - != SQL_NO_DATA) { + while (1) { + state[0] = 0; + stateLen = 0, + rc = SQLGetDiagFieldA(handleType, handle, i, SQL_DIAG_SQLSTATE, + (SQLPOINTER) state, sizeof(state), &stateLen); + if (!SQL_SUCCEEDED(rc) || rc == SQL_NO_DATA) { + break; + } if (stateLen >= 0 && !strcmp(sqlstate, (const char*) state)) { return 1; } } return 0; @@ -1081,15 +1216,15 @@ } /* * Allocate the ODBC environment */ rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv); - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + if (SQL_SUCCEEDED(rc)) { rc = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0); } - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { /* * The call failed. Report the error. */ if (hEnv != SQL_NULL_HENV) { if (interp != NULL) { @@ -1103,10 +1238,57 @@ Tcl_NewStringObj("Could not allocate the " "ODBC SQL environment.", -1)); Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY001", "ODBC", "-1", NULL); } + } else { + /* + * Detect real size of SQLWCHAR used by the driver manager. + */ + SQLHDBC hDBC = SQL_NULL_HDBC; + + sizeofSQLWCHAR = sizeof(SQLWCHAR); /* fallback */ + rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC); + if (SQL_SUCCEEDED(rc)) { + SQLSMALLINT infoLen; + int i; + char info[64]; + + rc = SQLGetInfoW(hDBC, SQL_ODBC_VER, (SQLPOINTER) info, + sizeof(info), &infoLen); + if (SQL_SUCCEEDED(rc) && infoLen >= 8) { + static const char BE32sig[] = { + '\0', '\0', '\0', '#', '\0', '\0', '\0', '#' + }; + static const char LE32sig[] = { + '#', '\0', '\0', '\0', '#', '\0', '\0', '\0' + }; + static const char BE16sig[] = { + '\0', '#', '\0', '#' + }; + static const char LE16sig[] = { + '#', '\0', '#', '\0' + }; + + if (infoLen > sizeof(info)) { + infoLen = sizeof(info); + } + for (i = 0; i < infoLen; i++) { + if (info[i] >= '0' && info[i] <= '9') { + info[i] = '#'; + } + } + if (memcmp(info, BE32sig, sizeof(BE32sig)) == 0 || + memcmp(info, LE32sig, sizeof(LE32sig)) == 0) { + sizeofSQLWCHAR = 4; + } else if (memcmp(info, BE16sig, sizeof(BE16sig)) == 0 || + memcmp(info, LE16sig, sizeof(LE16sig)) == 0) { + sizeofSQLWCHAR = 2; + } + } + SQLFreeHandle(SQL_HANDLE_DBC, hDBC); + } } } /* * On subsequent calls, simply adjust the refcount */ @@ -1178,17 +1360,17 @@ Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot have multiple result " "sets in this context", -1)); return SQL_NULL_HSTMT; } rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &hStmt); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); return SQL_NULL_HSTMT; } rc = SQLPrepareW(hStmt, sdata->nativeSqlW, sdata->nativeSqlLen); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_STMT, hStmt, "(preparing statement)"); SQLFreeHandle(SQL_HANDLE_STMT, hStmt); return SQL_NULL_HSTMT; } @@ -1221,11 +1403,11 @@ SQLHSTMT hStmt = rdata->hStmt; /* Statement handle */ SQLRETURN rc; /* Return code from ODBC operations */ Tcl_Obj* colNames; /* List of the column names */ SQLSMALLINT nColumns; /* Number of result set columns */ - SQLWCHAR colNameBuf[40]; /* Buffer to hold the column name */ + SQLWCHAR colNameBuf[41*2]; /* Buffer to hold the column name */ SQLSMALLINT colNameLen = 40; /* Length of the column name */ SQLSMALLINT colNameAllocLen = 40; /* Allocated length of the column name */ SQLWCHAR* colNameW = colNameBuf; @@ -1250,11 +1432,11 @@ Tcl_SetHashValue(nameEntry, (ClientData) 0); /* Count the columns of the result set */ rc = SQLNumResultCols(hStmt, &nColumns); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_STMT, hStmt, "(getting number of result columns)"); return TCL_ERROR; } colNames = Tcl_NewObj(); @@ -1291,18 +1473,18 @@ colNameAllocLen = 2 * colNameLen + 1; if (colNameW != colNameBuf) { ckfree((char*) colNameW); } colNameW = (SQLWCHAR*) - ckalloc(colNameAllocLen * sizeof(SQLWCHAR)); + ckalloc(colNameAllocLen * sizeofSQLWCHAR); retry = 1; } } while (retry); /* Bail out on an ODBC error */ - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { char info[80]; sprintf(info, "(describing result column #%d)", i+1); TransferSQLError(interp, SQL_HANDLE_STMT, hStmt, info); Tcl_DecrRefCount(colNames); ckfree((char*)rdata->results); @@ -1471,11 +1653,11 @@ /* -isolation */ rc = SQLGetConnectAttr(hDBC, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER) &mode, 0, NULL); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(getting isolation level of connection)"); return TCL_ERROR; } Tcl_ListObjAppendElement(NULL, retval, literals[LIT_ISOLATION]); @@ -1484,11 +1666,11 @@ /* -readonly */ rc = SQLGetConnectAttr(hDBC, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) &mode, 0, NULL); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(getting access mode of connection)"); return TCL_ERROR; } Tcl_ListObjAppendElement(NULL, retval, literals[LIT_READONLY]); @@ -1497,11 +1679,11 @@ /* -timeout */ rc = SQLGetConnectAttr(hDBC, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)&seconds, 0, NULL); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { if (SQLStateIs(SQL_HANDLE_DBC, hDBC, "HYC00")) { seconds = 0; } else { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(getting connection timeout value)"); @@ -1542,11 +1724,11 @@ break; case COPTION_ISOLATION: rc = SQLGetConnectAttr(hDBC, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER) &mode, 0, NULL); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(getting isolation level of connection)"); return TCL_ERROR; } Tcl_SetObjResult(interp, @@ -1563,11 +1745,11 @@ return TCL_ERROR; case COPTION_READONLY: rc = SQLGetConnectAttr(hDBC, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) &mode, 0, NULL); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(getting access mode of connection)"); return TCL_ERROR; } Tcl_SetObjResult(interp, @@ -1578,11 +1760,11 @@ rc = SQLGetConnectAttr(hDBC, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)&seconds, 0, NULL); if (SQLStateIs(SQL_HANDLE_DBC, hDBC, "HYC00")) { seconds = 0; } else { - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(getting connection timeout value)"); return TCL_ERROR; } } @@ -1638,12 +1820,12 @@ &isol) != TCL_OK) { return TCL_ERROR; } mode = isol; rc = SQLSetConnectAttr(hDBC, SQL_ATTR_TXN_ISOLATION, - (SQLPOINTER)mode, 0); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + (SQLPOINTER)(INT2PTR(mode)), 0); + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(setting isolation level of connection)"); return TCL_ERROR; } break; @@ -1709,12 +1891,12 @@ mode = SQL_MODE_READ_ONLY; } else { mode = SQL_MODE_READ_WRITE; } rc = SQLSetConnectAttr(hDBC, SQL_ATTR_ACCESS_MODE, - (SQLPOINTER)mode, 0); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + (SQLPOINTER)(INT2PTR(mode)), 0); + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(setting access mode of connection)"); return TCL_ERROR; } break; @@ -1725,12 +1907,12 @@ if (Tcl_GetIntFromObj(interp, objv[i+1], &j) != TCL_OK) { return TCL_ERROR; } seconds = (SQLINTEGER)((j + 999) / 1000); rc = SQLSetConnectAttr(hDBC, SQL_ATTR_CONNECTION_TIMEOUT, - (SQLPOINTER)seconds, 0); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + (SQLPOINTER)(INT2PTR(seconds)), 0); + if (!SQL_SUCCEEDED(rc)) { /* * A failure is OK if the SQL state is "Optional * Function Not Implemented" and we were trying to set * a zero timeout. */ @@ -1777,18 +1959,19 @@ /* Per-interp data for the ODBC package */ Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext); /* The current connection object */ int skip = Tcl_ObjectContextSkippedArgs(objectContext); /* Number of leading args to skip */ - SQLHDBC hDBC; /* Handle to the database connection */ + SQLHDBC hDBC = SQL_NULL_HDBC; + /* Handle to the database connection */ SQLRETURN rc; /* Return code from ODBC calls */ HWND hParentWindow = NULL; /* Windows handle of the main window */ SQLWCHAR* connectionStringReq; /* Connection string requested by the caller */ int connectionStringReqLen; /* Length of the requested connection string */ - SQLWCHAR connectionString[1025]; + SQLWCHAR connectionString[1025*2]; /* Connection string actually used */ SQLSMALLINT connectionStringLen; /* Length of the actual connection string */ Tcl_DString connectionStringDS; /* Connection string converted to UTF-8 */ @@ -1810,11 +1993,11 @@ /* * Allocate a connection handle */ rc = SQLAllocHandle(SQL_HANDLE_DBC, pidata->hEnv, (SQLHANDLE*) &hDBC); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_ENV, pidata->hEnv, "(allocating connection handle)"); return TCL_ERROR; } @@ -1842,11 +2025,11 @@ ckfree((char*) connectionStringReq); if (rc == SQL_NO_DATA) { Tcl_SetObjResult(interp, Tcl_NewStringObj("operation cancelled", -1)); SQLFreeHandle(SQL_HANDLE_DBC, hDBC); return TCL_ERROR; - } else if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + } else if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, hDBC, "(connecting to database)"); SQLFreeHandle(SQL_HANDLE_DBC, hDBC); return TCL_ERROR; } @@ -2041,11 +2224,11 @@ /* End transaction, turn off "transaction in progress", and report status */ rc = SQLEndTran(SQL_HANDLE_DBC, cdata->hDBC, completionType); cdata->flags &= ~ CONNECTION_FLAG_XCN_ACTIVE; - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(ending the transaction)"); return TCL_ERROR; } return TCL_OK; @@ -2174,24 +2357,13 @@ Tcl_Interp* interp, /* Tcl interpreter */ ConnectionData* cdata, /* Instance data for the connection */ SQLINTEGER flag /* Auto-commit indicator */ ) { SQLRETURN rc; -#if 0 - /* - * This form is allegedly preferred, but fails with the Windows - * SQLite3 driver - */ rc = SQLSetConnectAttr(cdata->hDBC, SQL_ATTR_AUTOCOMMIT, - (SQLPOINTER) flag, 0); -#else - /* - * This form is deprecated, but actually works. - */ - rc = SQLSetConnectOption(cdata->hDBC, SQL_AUTOCOMMIT, flag); -#endif - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + (SQLPOINTER)(INT2PTR(flag)), 0); + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(changing the 'autocommit' attribute)"); return TCL_ERROR; } return TCL_OK; @@ -2497,11 +2669,11 @@ sdata->params[j].scale = 0; sdata->params[j].nullable = SQL_NULLABLE_UNKNOWN; sdata->params[j].flags = PARAM_IN; } rc = SQLNumParams(sdata->hStmt, &nParams); - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + if (SQL_SUCCEEDED(rc)) { if (nParams != i) { Tcl_SetObjResult(interp, Tcl_NewStringObj("The SQL statement appears " "to contain parameters in " "native SQL syntax. You need " @@ -2521,11 +2693,11 @@ rc = SQLDescribeParam(sdata->hStmt, i+1, &(sdata->params[i].dataType), &(sdata->params[i].precision), &(sdata->params[i].scale), &(sdata->params[i].nullable)); - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + if (SQL_SUCCEEDED(rc)) { /* * FIXME: SQLDescribeParam doesn't actually describe * the direction of parameter transmission for * stored procedure calls. It appears simply * to be the caller's responsibility to know @@ -2856,11 +3028,11 @@ sdata = NewStatement(cdata, connectionObject); /* Allocate an ODBC statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &(sdata->hStmt)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); goto freeSData; } @@ -2959,11 +3131,11 @@ sdata = NewStatement(cdata, connectionObject); /* Allocate an ODBC statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &(sdata->hStmt)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); goto freeSData; } @@ -3062,11 +3234,11 @@ sdata = NewStatement(cdata, connectionObject); /* Allocate an ODBC statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &(sdata->hStmt)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); goto freeSData; } @@ -3212,11 +3384,11 @@ } /* Allocate an ODBC statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &(sdata->hStmt)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); goto freeSData; } @@ -3312,11 +3484,11 @@ sdata = NewStatement(cdata, connectionObject); /* Allocate an ODBC statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, cdata->hDBC, &(sdata->hStmt)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_DBC, cdata->hDBC, "(allocating statement handle)"); goto freeSData; } @@ -3697,11 +3869,11 @@ dataType = SQL_C_WCHAR; rdata->bindStrings[nBound] = (SQLCHAR*) GetWCharStringFromObj(paramValObj, ¶mLen); rdata->bindStringLengths[nBound] = paramExternalLen = - paramLen * sizeof(SQLWCHAR); + paramLen * sizeofSQLWCHAR; } else { /* * We need to convert the character string to system @@ -3741,11 +3913,11 @@ sdata->params[nBound].precision, sdata->params[nBound].scale, rdata->bindStrings[nBound], paramExternalLen, rdata->bindStringLengths + nBound); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { char* info = ckalloc(80 * strlen(paramName)); sprintf(info, "(binding the '%s' parameter)", paramName); TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info); ckfree(info); return TCL_ERROR; @@ -3773,12 +3945,11 @@ sdata->nativeMatchPatternW, sdata->nativeMatchPatLen); } else { rc = SQLExecute(rdata->hStmt); } - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO - && rc != SQL_NO_DATA) { + if (!SQL_SUCCEEDED(rc) && rc != SQL_NO_DATA) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(executing the statement)"); return TCL_ERROR; } @@ -3789,11 +3960,11 @@ } /* Determine and store the row count */ rc = SQLRowCount(rdata->hStmt, &(rdata->rowCount)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(counting rows in the result)"); return TCL_ERROR; } @@ -3905,11 +4076,11 @@ rc = SQLMoreResults(rdata->hStmt); if (rc == SQL_NO_DATA) { Tcl_SetObjResult(interp, literals[LIT_0]); return TCL_OK; } - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(advancing to next result set)"); return TCL_ERROR; } if (GetResultSetDescription(interp, rdata) != TCL_OK) { @@ -3917,11 +4088,11 @@ } /* Determine and store the row count */ rc = SQLRowCount(rdata->hStmt, &(rdata->rowCount)); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(counting rows in the result)"); return TCL_ERROR; } else { Tcl_SetObjResult(interp, literals[LIT_1]); @@ -4017,11 +4188,11 @@ rc = SQLFetch(rdata->hStmt); if (rc == SQL_NO_DATA) { Tcl_SetObjResult(interp, literals[LIT_0]); return TCL_OK; - } else if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + } else if (!SQL_SUCCEEDED(rc)) { TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, "(fetching the next row of the result set)"); return TCL_ERROR; } @@ -4093,16 +4264,17 @@ #define BUFSIZE 256 StatementData* sdata = rdata->sdata; ConnectionData* cdata = sdata->cdata; SQLSMALLINT dataType; /* Type of character data to retrieve */ - SQLWCHAR colWBuf[BUFSIZE+1];/* Buffer to hold the string value of a + SQLWCHAR colWBuf[(BUFSIZE+1)*2]; + /* Buffer to hold the string value of a * column */ SQLCHAR* colBuf = (SQLCHAR*) colWBuf; SQLCHAR* colPtr = colBuf; /* Pointer to the current allocated buffer * (which may have grown) */ - SQLLEN colAllocLen = BUFSIZE * sizeof(SQLWCHAR); + SQLLEN colAllocLen = BUFSIZE * sizeofSQLWCHAR; /* Current allocated size of the buffer, * in bytes */ SQLLEN colLen; /* Actual size of the return value, in bytes */ SQLINTEGER colLong; /* Integer value of the column */ SQLBIGINT colWide; /* Wide-integer value of the column */ @@ -4152,11 +4324,11 @@ convertWide: /* A wide integer */ colLen = sizeof(colWide); colWide = 0; rc = SQLGetData(rdata->hStmt, i+1, SQL_C_SBIGINT, (SQLPOINTER) &colWide, sizeof(colWide), &colLen); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { char info[80]; sprintf(info, "(retrieving result set column #%d)\n", i+1); TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info); return TCL_ERROR; } @@ -4172,11 +4344,11 @@ convertLong: /* An integer no larger than 'long' */ colLen = sizeof(colLong); colLong = 0; rc = SQLGetData(rdata->hStmt, i+1, SQL_C_SLONG, (SQLPOINTER) &colLong, sizeof(colLong), &colLen); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { char info[80]; sprintf(info, "(retrieving result set column #%d)\n", i+1); TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info); ckfree(info); return TCL_ERROR; @@ -4206,11 +4378,11 @@ */ colLen = sizeof(colDouble); colDouble = 0.0; rc = SQLGetData(rdata->hStmt, i+1, SQL_C_DOUBLE, (SQLPOINTER) &colDouble, sizeof(colDouble), &colLen); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { char info[80]; sprintf(info, "(retrieving result set column #%d)\n", i+1); TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info); ckfree(info); return TCL_ERROR; @@ -4276,11 +4448,11 @@ if (dataType == SQL_C_BINARY) { /* no NULL terminator */ } else if (dataType == SQL_C_CHAR) { --offset; } else { - offset -= sizeof(SQLWCHAR); + offset -= sizeofSQLWCHAR; } if (colLen == SQL_NO_TOTAL) { /* * The driver wouldn't tell us how much space was * needed, but we got a full bufferload (less the @@ -4289,20 +4461,20 @@ colAllocLen = 2 * colAllocLen; } else { colAllocLen += colLen; } if (colPtr == colBuf) { - colPtr = (SQLCHAR*) ckalloc(colAllocLen + sizeof(SQLWCHAR)); - memcpy(colPtr, colBuf, BUFSIZE * sizeof(SQLWCHAR)); + colPtr = (SQLCHAR*) ckalloc(colAllocLen + sizeofSQLWCHAR); + memcpy(colPtr, colBuf, BUFSIZE * sizeofSQLWCHAR); } else { colPtr = (SQLCHAR*) - ckrealloc((char*)colPtr, colAllocLen + sizeof(SQLWCHAR)); + ckrealloc((char*)colPtr, colAllocLen + sizeofSQLWCHAR); } retry = 1; } } while (retry); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + if (!SQL_SUCCEEDED(rc)) { char info[80]; sprintf(info, "(retrieving result set column #%d)\n", i+1); TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info); if (colPtr != colBuf) { ckfree((char*) colPtr); @@ -4320,11 +4492,11 @@ (int) (colLen + offset), &colDS); } else { DStringAppendWChars(&colDS, (SQLWCHAR*) colPtr, (int)((colLen + offset) - / sizeof(SQLWCHAR))); + / sizeofSQLWCHAR)); } colObj = Tcl_NewStringObj(Tcl_DStringValue(&colDS), Tcl_DStringLength(&colDS)); Tcl_DStringFree(&colDS); } @@ -4529,11 +4701,11 @@ { "-user", SQL_FETCH_FIRST_USER }, { NULL, 0 } }; int flagIndex; SQLRETURN rc; /* SQL result code */ - SQLWCHAR serverName[SQL_MAX_DSN_LENGTH + 1]; + SQLWCHAR serverName[(SQL_MAX_DSN_LENGTH+1)*2]; /* Data source name */ SQLSMALLINT serverNameLen; /* Length of the DSN */ SQLWCHAR *description; /* Data source descroption */ SQLSMALLINT descLen; /* Length of the description */ SQLSMALLINT descAllocLen; /* Allocated size of the description */ @@ -4571,11 +4743,11 @@ direction = initDirection; finished = 1; descAllocLen = descLenNeeded; description = (SQLWCHAR*) - ckalloc(sizeof(SQLWCHAR) * (descAllocLen + 1)); + ckalloc(sizeofSQLWCHAR * (descAllocLen + 1)); Tcl_SetListObj(retval, 0, NULL); /* Enumerate the data sources */ while (1) { @@ -4590,11 +4762,11 @@ descLenNeeded = 2 * descLen; finished = 0; break; - } else if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + } else if (SQL_SUCCEEDED(rc)) { /* Got a data source; add key and value to the dictionary */ Tcl_DStringInit(&nameDS); DStringAppendWChars(&nameDS, serverName, serverNameLen); @@ -4702,15 +4874,15 @@ while (!finished) { finished = 1; driverAllocLen = driverLenNeeded; driver = (SQLWCHAR*) - ckalloc(sizeof(SQLWCHAR) * (driverAllocLen + 1)); + ckalloc(sizeofSQLWCHAR * (driverAllocLen + 1)); *driver = 0; attrAllocLen = attrLenNeeded; attributes = (SQLWCHAR*) - ckalloc(sizeof(SQLWCHAR) * (attrAllocLen + 1)); + ckalloc(sizeofSQLWCHAR * (attrAllocLen + 1)); *attributes = 0; Tcl_SetListObj(retval, 0, NULL); direction = SQL_FETCH_FIRST; /* Enumerate the data sources */ @@ -4737,11 +4909,11 @@ finished = 0; break; } if (finished) { - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + if (SQL_SUCCEEDED(rc)) { /* Got a data source; add key and value to the dictionary */ Tcl_DStringInit(&nameDS); DStringAppendWChars(&nameDS, driver, driverLen);