Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

sqlite3odbc.c

Go to the documentation of this file.
00001 
00014 #if defined(SQLITE_HAS_CODEC) && defined(SQLITE_API)
00015 #undef WITH_SQLITE_DLLS
00016 #undef SQLITE_DYNLOAD
00017 #include "sqlite3.c"
00018 #endif
00019 
00020 #if defined(WITH_SQLITE_DLLS) && (WITH_SQLITE_DLLS > 1)
00021 #define SQLITE_DYNLOAD 1
00022 #endif
00023 
00024 #include "sqlite3odbc.h"
00025 
00026 #ifdef SQLITE_DYNLOAD
00027 
00028 #undef MEMORY_DEBUG
00029 
00030 #if defined(_WIN32) || defined(_WIN64)
00031 static void dls_init(void);
00032 static void dls_fini(void);
00033 #else
00034 void dls_init(void);
00035 void dls_fini(void);
00036 #endif
00037 
00038 static struct dl_sqlite3_funcs {
00039     void (*activate_see)(const char *p0);
00040     int (*bind_blob)(sqlite3_stmt *p0, int p1, const void *p2, int p3,
00041                      void (*p4)(void *));
00042     int (*bind_double)(sqlite3_stmt *p0, int p1, double p2);
00043     int (*bind_int)(sqlite3_stmt *p0, int p1, int p2);
00044     int (*bind_int64)(sqlite3_stmt *p0, int p1, sqlite_int64 p2);
00045     int (*bind_null)(sqlite3_stmt *p0, int p1);
00046     int (*bind_parameter_count)(sqlite3_stmt *p0);
00047     int (*bind_text)(sqlite3_stmt *p0, int p1, const char *p2, int p3,
00048                      void (*p4)(void *));
00049     int (*busy_handler)(sqlite3 *p0, int (*p2)(void *, int), void *p3);
00050     int (*changes)(sqlite3 *p0);
00051     int (*close)(sqlite3 *p0);
00052     const void * (*column_blob)(sqlite3_stmt *p0, int p1);
00053     int (*column_bytes)(sqlite3_stmt *p0, int p1);
00054     int (*column_count)(sqlite3_stmt *p0);
00055     const char * (*column_database_name)(sqlite3_stmt *p0, int p1);
00056     const char * (*column_decltype)(sqlite3_stmt *p0, int p1);
00057     double (*column_double)(sqlite3_stmt *p0, int p1);
00058     const char * (*column_name)(sqlite3_stmt *p0, int p1);
00059     const char * (*column_origin_name)(sqlite3_stmt *p0, int p1);
00060     const char * (*column_table_name)(sqlite3_stmt *p0, int p1);
00061     const unsigned char * (*column_text)(sqlite3_stmt *p0, int p1);
00062     int (*column_type)(sqlite3_stmt *p0, int p1);
00063     int (*create_function)(sqlite3 *p0, const char *p1, int p2, int p3,
00064                            void *p4,
00065                            void (*p5)(sqlite3_context *, int, sqlite3_value **),
00066                            void (*p6)(sqlite3_context *, int, sqlite3_value **),
00067                            void (*p7)(sqlite3_context *));
00068     int (*enable_load_extension)(sqlite3 *p0, int p1);
00069     int (*errcode)(sqlite3 *p0);
00070     const char * (*errmsg)(sqlite3 *p0);
00071     int (*exec)(sqlite3 *p0, const char *p1,
00072                 int (*p2)(void *, int, char **, char **),
00073                 void *p3, char **p4);
00074     int (*finalize)(sqlite3_stmt *p0);
00075     void (*free)(void *p0);
00076     void (*free_table)(char **p0);
00077     int (*get_table)(sqlite3 *p0, const char *p1, char ***p2,
00078                      int *p3, int *p4, char **p5);
00079     void (*interrupt)(sqlite3 *p0);
00080     int (*key)(sqlite3 *p0, const void *p1, int p2);
00081     const char * (*libversion)(void);
00082     int (*load_extension)(sqlite3 *p0, const char *p1, const char *p2,
00083                           char **p3);
00084     void * (*malloc)(int p0);
00085     char * (*mprintf)(const char *p0, ...);
00086     int (*open)(const char *p0, sqlite3 **p1);
00087     int (*open16)(const void *p0, sqlite3 **p1);
00088     int (*open_v2)(const char *p0, sqlite3 **p1, int p2, const char *p3);
00089     int (*prepare)(sqlite3 *p0, const char *p1, int p2, sqlite3_stmt **p3,
00090                    const char **p4);
00091     int (*prepare_v2)(sqlite3 *p0, const char *p1, int p2, sqlite3_stmt **p3,
00092                       const char **p4);
00093     void * (*profile)(sqlite3 *p0,
00094                       void (*p1)(void *, const char *, sqlite3_uint64),
00095                       void *p2);
00096     void * (*realloc)(void *p0, int p1);
00097     int (*rekey)(sqlite3 *p0, const void *p1, int p2);
00098     int (*reset)(sqlite3_stmt *p0);
00099     void (*result_blob)(sqlite3_context *p0, const void *p1,
00100                         int p2, void (*p3)(void *));
00101     void (*result_error)(sqlite3_context *p0, const char *p1, int p2);
00102     void (*result_int)(sqlite3_context *p0, int p1);
00103     void (*result_null)(sqlite3_context *p0);
00104     int (*step)(sqlite3_stmt *p0);
00105     int (*xstrnicmp)(const char *p0, const char *p1, int p2);
00106     int (*table_column_metadata)(sqlite3 *p0, const char *p1,
00107                                  const char *p2, const char *p3,
00108                                  char const **p4, char const **p5,
00109                                  int *p6, int *p7, int *p8);
00110     void * (*trace)(sqlite3 *p0, void (*p1)(void *, const char *), void *p2);
00111     void * (*user_data)(sqlite3_context *p0);
00112     const void * (*value_blob)(sqlite3_value *p0);
00113     int (*value_bytes)(sqlite3_value *p0);
00114     const unsigned char * (*value_text)(sqlite3_value *p0);
00115     int (*value_type)(sqlite3_value *p0);
00116 } dls_funcs;
00117 
00118 #define sqlite3_activate_see          dls_funcs.activate_see
00119 #define sqlite3_bind_blob             dls_funcs.bind_blob
00120 #define sqlite3_bind_double           dls_funcs.bind_double
00121 #define sqlite3_bind_int              dls_funcs.bind_int
00122 #define sqlite3_bind_int64            dls_funcs.bind_int64
00123 #define sqlite3_bind_null             dls_funcs.bind_null
00124 #define sqlite3_bind_parameter_count  dls_funcs.bind_parameter_count
00125 #define sqlite3_bind_text             dls_funcs.bind_text
00126 #define sqlite3_busy_handler          dls_funcs.busy_handler
00127 #define sqlite3_changes               dls_funcs.changes
00128 #define sqlite3_close                 dls_funcs.close
00129 #define sqlite3_column_blob           dls_funcs.column_blob
00130 #define sqlite3_column_bytes          dls_funcs.column_bytes
00131 #define sqlite3_column_count          dls_funcs.column_count
00132 #define sqlite3_column_database_name  dls_funcs.column_database_name
00133 #define sqlite3_column_decltype       dls_funcs.column_decltype
00134 #define sqlite3_column_double         dls_funcs.column_double
00135 #define sqlite3_column_name           dls_funcs.column_name
00136 #define sqlite3_column_origin_name    dls_funcs.column_origin_name
00137 #define sqlite3_column_table_name     dls_funcs.column_table_name
00138 #define sqlite3_column_text           dls_funcs.column_text
00139 #define sqlite3_column_type           dls_funcs.column_type
00140 #define sqlite3_create_function       dls_funcs.create_function
00141 #define sqlite3_enable_load_extension dls_funcs.enable_load_extension
00142 #define sqlite3_errcode               dls_funcs.errcode
00143 #define sqlite3_errmsg                dls_funcs.errmsg
00144 #define sqlite3_exec                  dls_funcs.exec
00145 #define sqlite3_finalize              dls_funcs.finalize
00146 #define sqlite3_free                  dls_funcs.free
00147 #define sqlite3_free_table            dls_funcs.free_table
00148 #define sqlite3_get_table             dls_funcs.get_table
00149 #define sqlite3_interrupt             dls_funcs.interrupt
00150 #define sqlite3_key                   dls_funcs.key
00151 #define sqlite3_libversion            dls_funcs.libversion
00152 #define sqlite3_load_extension        dls_funcs.load_extension
00153 #define sqlite3_malloc                dls_funcs.malloc
00154 #define sqlite3_mprintf               dls_funcs.mprintf
00155 #define sqlite3_open                  dls_funcs.open
00156 #define sqlite3_open16                dls_funcs.open16
00157 #define sqlite3_open_v2               dls_funcs.open_v2
00158 #define sqlite3_prepare               dls_funcs.prepare
00159 #define sqlite3_prepare_v2            dls_funcs.prepare_v2
00160 #define sqlite3_profile               dls_funcs.profile
00161 #define sqlite3_realloc               dls_funcs.realloc
00162 #define sqlite3_rekey                 dls_funcs.rekey
00163 #define sqlite3_reset                 dls_funcs.reset
00164 #define sqlite3_result_blob           dls_funcs.result_blob
00165 #define sqlite3_result_error          dls_funcs.result_error
00166 #define sqlite3_result_int            dls_funcs.result_int
00167 #define sqlite3_result_null           dls_funcs.result_null
00168 #define sqlite3_step                  dls_funcs.step
00169 #define sqlite3_strnicmp              dls_funcs.xstrnicmp
00170 #define sqlite3_table_column_metadata dls_funcs.table_column_metadata
00171 #define sqlite3_trace                 dls_funcs.trace
00172 #define sqlite3_user_data             dls_funcs.user_data
00173 #define sqlite3_value_blob            dls_funcs.value_blob
00174 #define sqlite3_value_bytes           dls_funcs.value_bytes
00175 #define sqlite3_value_text            dls_funcs.value_text
00176 #define sqlite3_value_type            dls_funcs.value_type
00177 
00178 #endif
00179 
00180 #ifndef WITHOUT_WINTERFACE
00181 #define WINTERFACE
00182 #define WCHARSUPPORT
00183 #endif
00184 
00185 #if !defined(_WIN32) && !defined(_WIN64)
00186 #if !defined(WCHARSUPPORT) && defined(HAVE_SQLWCHAR) && (HAVE_SQLWCHAR)
00187 #define WCHARSUPPORT
00188 #endif
00189 #endif
00190 
00191 #if defined(WINTERFACE)
00192 #include <sqlucode.h>
00193 #endif
00194 
00195 #if defined(_WIN32) || defined(_WIN64)
00196 #include "resource3.h"
00197 #define ODBC_INI "ODBC.INI"
00198 #ifndef DRIVER_VER_INFO
00199 #define DRIVER_VER_INFO VERSION
00200 #endif
00201 #else
00202 #define ODBC_INI ".odbc.ini"
00203 #endif
00204 
00205 #ifndef DRIVER_VER_INFO
00206 #define DRIVER_VER_INFO "0.0"
00207 #endif
00208 
00209 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
00210 #ifdef _WIN64
00211 #define COLATTRIBUTE_LAST_ARG_TYPE SQLLEN *
00212 #else
00213 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
00214 #endif
00215 #endif
00216 
00217 #ifndef SETSTMTOPTION_LAST_ARG_TYPE
00218 #define SETSTMTOPTION_LAST_ARG_TYPE SQLROWCOUNT
00219 #endif
00220 
00221 #undef min
00222 #define min(a, b) ((a) < (b) ? (a) : (b))
00223 #undef max
00224 #define max(a, b) ((a) < (b) ? (b) : (a))
00225 
00226 #ifndef PTRDIFF_T
00227 #define PTRDIFF_T int
00228 #endif
00229 
00230 #define array_size(x) (sizeof (x) / sizeof (x[0]))
00231 
00232 #define stringify1(s) #s
00233 #define stringify(s) stringify1(s)
00234 
00235 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
00236 
00237 /* Column types for static string column descriptions (SQLTables etc.) */
00238 
00239 #if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
00240 #define SCOL_VARCHAR SQL_WVARCHAR
00241 #define SCOL_CHAR SQL_WCHAR
00242 #else
00243 #define SCOL_VARCHAR SQL_VARCHAR
00244 #define SCOL_CHAR SQL_CHAR
00245 #endif
00246 
00247 #define ENV_MAGIC  0x53544145
00248 #define DBC_MAGIC  0x53544144
00249 #define DEAD_MAGIC 0xdeadbeef
00250 
00251 static const char *xdigits = "0123456789ABCDEFabcdef";
00252 
00253 #ifdef MEMORY_DEBUG
00254 
00255 static void *
00256 xmalloc_(int n, char *file, int line)
00257 {
00258     int nn = n + 4 * sizeof (long);
00259     long *p;
00260 
00261     p = malloc(nn);
00262     if (!p) {
00263 #if (MEMORY_DEBUG > 1)
00264         fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
00265 #endif
00266         return NULL;
00267     }
00268     p[0] = 0xdead1234;
00269     nn = nn / sizeof (long) - 1;
00270     p[1] = n;
00271     p[nn] = 0xdead5678;
00272 #if (MEMORY_DEBUG > 1)
00273     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
00274 #endif
00275     return (void *) &p[2];
00276 }
00277 
00278 static void *
00279 xrealloc_(void *old, int n, char *file, int line)
00280 {
00281     int nn = n + 4 * sizeof (long), nnn;
00282     long *p, *pp;
00283 
00284     if (n == 0 || !old) {
00285         return xmalloc_(n, file, line);
00286     }
00287     p = &((long *) old)[-2];
00288     if (p[0] != 0xdead1234) {
00289         fprintf(stderr, "*** low end corruption @ %p\n", old);
00290         abort();
00291     }
00292     nnn = p[1] + 4 * sizeof (long);
00293     nnn = nnn / sizeof (long) - 1;
00294     if (p[nnn] != 0xdead5678) {
00295         fprintf(stderr, "*** high end corruption @ %p\n", old);
00296         abort();
00297     }
00298     pp = realloc(p, nn);
00299     if (!pp) {
00300 #if (MEMORY_DEBUG > 1)
00301         fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
00302 #endif
00303         return NULL;
00304     }
00305 #if (MEMORY_DEBUG > 1)
00306     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
00307 #endif
00308     p = pp;
00309     p[1] = n;
00310     nn = nn / sizeof (long) - 1;
00311     p[nn] = 0xdead5678;
00312     return (void *) &p[2];
00313 }
00314 
00315 static void
00316 xfree_(void *x, char *file, int line)
00317 {
00318     long *p;
00319     int n;
00320 
00321     if (!x) {
00322         return;
00323     }
00324     p = &((long *) x)[-2];
00325     if (p[0] != 0xdead1234) {
00326         fprintf(stderr, "*** low end corruption @ %p\n", x);
00327         abort();
00328     }
00329     n = p[1] + 4 * sizeof (long);
00330     n = n / sizeof (long) - 1;
00331     if (p[n] != 0xdead5678) {
00332         fprintf(stderr, "*** high end corruption @ %p\n", x);
00333         abort();
00334     }
00335 #if (MEMORY_DEBUG > 1)
00336     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
00337 #endif
00338     free(p);
00339 }
00340 
00341 static void
00342 xfree__(void *x)
00343 {
00344     xfree_(x, "unknown location", 0);
00345 }
00346 
00347 static char *
00348 xstrdup_(const char *str, char *file, int line)
00349 {
00350     char *p;
00351 
00352     if (!str) {
00353 #if (MEMORY_DEBUG > 1)
00354         fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
00355 #endif
00356         return NULL;
00357     }
00358     p = xmalloc_(strlen(str) + 1, file, line);
00359     if (p) {
00360         strcpy(p, str);
00361     }
00362 #if (MEMORY_DEBUG > 1)
00363     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
00364 #endif
00365     return p;
00366 }
00367 
00368 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
00369 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
00370 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
00371 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
00372 
00373 #else
00374 
00375 #define xmalloc(x)    sqlite3_malloc(x)
00376 #define xrealloc(x,y) sqlite3_realloc(x, y)
00377 #define xfree(x)      sqlite3_free(x)
00378 #define xstrdup(x)    strdup_(x)
00379 
00380 #endif
00381 
00382 #if defined(_WIN32) || defined(_WIN64)
00383 
00384 #define vsnprintf   _vsnprintf
00385 #define snprintf    _snprintf
00386 #define strcasecmp  _stricmp
00387 #define strncasecmp _strnicmp
00388 
00389 static HINSTANCE NEAR hModule;  /* Saved module handle for resources */
00390 
00391 #endif
00392 
00393 #ifdef HAVE_SQLITE3STRNICMP
00394 #undef  strncasecmp
00395 #define strncasecmp(A,B,C) sqlite3_strnicmp(A,B,C)
00396 #undef  strcasecmp
00397 #define strcasecmp(A,B) strcasecmp_(A,B)
00398 
00399 #if defined(__GNUC__) && (__GNUC__ >= 2)
00400 static int strcasecmp_(const char *a, const char *b)
00401     __attribute__((__unused__));
00402 #endif
00403 
00404 static int strcasecmp_(const char *a, const char *b)
00405 {
00406     int c = strlen(a), d = strlen(b);
00407 
00408     if (c > d) {
00409         return strncasecmp(a, b, c);
00410     }
00411     return strncasecmp(a, b, d);
00412 }
00413 #endif
00414 
00415 #if defined(_WIN32) || defined(_WIN64)
00416 
00417 /*
00418  * SQLHENV, SQLHDBC, and SQLHSTMT synchronization
00419  * is done using a critical section in ENV structure.
00420  */
00421 
00422 #define HDBC_LOCK(hdbc)                         \
00423 {                                               \
00424     DBC *d;                                     \
00425                                                 \
00426     if ((hdbc) == SQL_NULL_HDBC) {              \
00427         return SQL_INVALID_HANDLE;              \
00428     }                                           \
00429     d = (DBC *) (hdbc);                         \
00430     if (d->magic != DBC_MAGIC || !d->env) {     \
00431         return SQL_INVALID_HANDLE;              \
00432     }                                           \
00433     if (d->env->magic != ENV_MAGIC) {           \
00434         return SQL_INVALID_HANDLE;              \
00435     }                                           \
00436     EnterCriticalSection(&d->env->cs);          \
00437     d->env->owner = GetCurrentThreadId();       \
00438 }
00439 
00440 #define HDBC_UNLOCK(hdbc)                       \
00441     if ((hdbc) != SQL_NULL_HDBC) {              \
00442         DBC *d;                                 \
00443                                                 \
00444         d = (DBC *) (hdbc);                     \
00445         if (d->magic == DBC_MAGIC && d->env &&  \
00446             d->env->magic == ENV_MAGIC) {       \
00447             d->env->owner = 0;                  \
00448             LeaveCriticalSection(&d->env->cs);  \
00449         }                                       \
00450     }
00451 
00452 #define HSTMT_LOCK(hstmt)                       \
00453 {                                               \
00454     DBC *d;                                     \
00455                                                 \
00456     if ((hstmt) == SQL_NULL_HSTMT) {            \
00457         return SQL_INVALID_HANDLE;              \
00458     }                                           \
00459     d = (DBC *) ((STMT *) (hstmt))->dbc;        \
00460     if (d->magic != DBC_MAGIC || !d->env) {     \
00461         return SQL_INVALID_HANDLE;              \
00462     }                                           \
00463     if (d->env->magic != ENV_MAGIC) {           \
00464         return SQL_INVALID_HANDLE;              \
00465     }                                           \
00466     EnterCriticalSection(&d->env->cs);          \
00467     d->env->owner = GetCurrentThreadId();       \
00468 }
00469 
00470 #define HSTMT_UNLOCK(hstmt)                     \
00471     if ((hstmt) != SQL_NULL_HSTMT) {            \
00472         DBC *d;                                 \
00473                                                 \
00474         d = (DBC *) ((STMT *) (hstmt))->dbc;    \
00475         if (d->magic == DBC_MAGIC && d->env &&  \
00476             d->env->magic == ENV_MAGIC) {       \
00477             d->env->owner = 0;                  \
00478             LeaveCriticalSection(&d->env->cs);  \
00479         }                                       \
00480     }
00481 
00482 #else
00483 
00484 /*
00485  * On UN*X assume that we are single-threaded or
00486  * the driver manager provides serialization for us.
00487  *
00488  * In iODBC (3.52.x) serialization can be turned
00489  * on using the DSN property "ThreadManager=yes".
00490  *
00491  * In unixODBC that property is named
00492  * "Threading=0-3" and takes one of these values:
00493  *
00494  *   0 - no protection
00495  *   1 - statement level protection
00496  *   2 - connection level protection
00497  *   3 - environment level protection
00498  *
00499  * unixODBC 2.2.11 uses environment level protection
00500  * by default when it has been built with pthread
00501  * support.
00502  */
00503 
00504 #define HDBC_LOCK(hdbc)
00505 #define HDBC_UNLOCK(hdbc)
00506 #define HSTMT_LOCK(hdbc)
00507 #define HSTMT_UNLOCK(hdbc)
00508 
00509 #endif
00510 
00511 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
00512 extern void nvfs_init(void);
00513 extern const char *nvfs_makevfs(const char *);
00514 #endif
00515 
00516 /*
00517  * tolower() replacement w/o locale
00518  */
00519 
00520 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00521 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
00522 
00523 static int
00524 TOLOWER(int c)
00525 {
00526     if (c) {
00527         char *p = strchr(upper_chars, c);
00528 
00529         if (p) {
00530             c = lower_chars[p - upper_chars];
00531         }
00532     }
00533     return c;
00534 }
00535 
00536 /*
00537  * isdigit() replacement w/o ctype.h
00538  */
00539 
00540 static const char digit_chars[] = "0123456789";
00541 
00542 #define ISDIGIT(c) \
00543     ((c) && strchr(digit_chars, (c)) != NULL)
00544 
00545 /*
00546  * isspace() replacement w/o ctype.h
00547  */
00548 
00549 static const char space_chars[] = " \f\n\r\t\v";
00550 
00551 #define ISSPACE(c) \
00552     ((c) && strchr(space_chars, (c)) != NULL)
00553 
00554 
00555 /*
00556  * Forward declarations of static functions.
00557  */
00558 
00559 static void dbtraceapi(DBC *d, char *fn, const char *sql);
00560 static void freedyncols(STMT *s);
00561 static void freeresult(STMT *s, int clrcols);
00562 static void freerows(char **rowp);
00563 static void unbindcols(STMT *s);
00564 static void s3stmt_drop(STMT *s);
00565 
00566 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
00567 static SQLRETURN freestmt(HSTMT stmt);
00568 static SQLRETURN mkbindcols(STMT *s, int ncols);
00569 static SQLRETURN setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp);
00570 static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
00571 static SQLRETURN starttran(STMT *s);
00572 static SQLRETURN setupparam(STMT *s, char *sql, int pnum);
00573 
00574 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
00575 /* MS Access hack part 1 (reserved error -7748) */
00576 static COL *statSpec2P, *statSpec3P;
00577 #endif
00578 
00579 #if (MEMORY_DEBUG < 1)
00580 
00586 static char *
00587 strdup_(const char *str)
00588 {
00589     char *p = NULL;
00590 
00591     if (str) {
00592         p = xmalloc(strlen(str) + 1);
00593         if (p) {
00594             strcpy(p, str);
00595         }
00596     }
00597     return p;
00598 }
00599 #endif
00600 
00601 #ifdef WCHARSUPPORT
00602 
00609 static int
00610 uc_strlen(SQLWCHAR *str)
00611 {
00612     int len = 0;
00613 
00614     if (str) {
00615         while (*str) {
00616             ++len;
00617             ++str;
00618         }
00619     }
00620     return len;
00621 }
00622 
00631 static SQLWCHAR *
00632 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
00633 {
00634     int i = 0;
00635 
00636     while (i < len) {
00637         if (!src[i]) {
00638             break;
00639         }
00640         dest[i] = src[i];
00641         ++i;
00642     }
00643     if (i < len) {
00644         dest[i] = 0;
00645     }
00646     return dest;
00647 }
00648 
00657 static void
00658 uc_from_utf_buf(unsigned char *str, int len, SQLWCHAR *uc, int ucLen)
00659 {
00660     ucLen = ucLen / sizeof (SQLWCHAR);
00661     if (!uc || ucLen < 0) {
00662         return;
00663     }
00664     if (len < 0) {
00665         len = ucLen * 5;
00666     }
00667     uc[0] = 0;
00668     if (str) {
00669         int i = 0;
00670 
00671         while (i < len && *str && i < ucLen) {
00672             unsigned char c = str[0];
00673 
00674             if (c < 0x80) {
00675                 uc[i++] = c;
00676                 ++str;
00677             } else if (c <= 0xc1 || c >= 0xf5) {
00678                 /* illegal, ignored */
00679                 ++str; 
00680             } else if (c < 0xe0) {
00681                 if ((str[1] & 0xc0) == 0x80) {
00682                     unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
00683 
00684                     uc[i++] = t;
00685                     str += 2;
00686                 } else {
00687                     uc[i++] = c;
00688                     ++str;
00689                 }
00690             } else if (c < 0xf0) {
00691                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
00692                     unsigned long t = ((c & 0x0f) << 12) |
00693                         ((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
00694 
00695                     uc[i++] = t;
00696                     str += 3;
00697                 } else {
00698                     uc[i++] = c;
00699                     ++str;
00700                 }
00701             } else if (c < 0xf8) {
00702                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
00703                     (str[3] & 0xc0) == 0x80) {
00704                     unsigned long t = ((c & 0x03) << 18) |
00705                         ((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
00706                         (str[3] & 0x3f);
00707 
00708                     if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
00709                         t >= 0x10000) {
00710                         t -= 0x10000;
00711                         uc[i++] = 0xd800 | ((t >> 10) & 0x3ff);
00712                         if (i >= ucLen) {
00713                             break;
00714                         }
00715                         t = 0xdc00 | (t & 0x3ff);
00716                     }
00717                     uc[i++] = t;
00718                     str += 4;
00719                 } else {
00720                     uc[i++] = c;
00721                     ++str;
00722                 }
00723             } else if (c < 0xfc) {
00724                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
00725                     (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80) {
00726                     unsigned long t = ((c & 0x01) << 24) |
00727                         ((str[1] & 0x3f) << 18) | ((str[2] & 0x3f) << 12) |
00728                         ((str[3] & 0x3f) << 6) | (str[4] & 0x3f);
00729 
00730                     if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
00731                         t >= 0x10000) {
00732                         t -= 0x10000;
00733                         uc[i++] = 0xd800 | ((t >> 10) & 0x3ff);
00734                         if (i >= ucLen) {
00735                             break;
00736                         }
00737                         t = 0xdc00 | (t & 0x3ff);
00738                     }
00739                     uc[i++] = t;
00740                     str += 5;
00741                 } else {
00742                     uc[i++] = c;
00743                     ++str;
00744                 }
00745             } else {
00746                 /* ignore */
00747                 ++str;
00748             }
00749         }
00750         if (i < ucLen) {
00751             uc[i] = 0;
00752         }
00753     }
00754 }
00755 
00763 static SQLWCHAR *
00764 uc_from_utf(unsigned char *str, int len)
00765 {
00766     SQLWCHAR *uc = NULL;
00767     int ucLen;
00768 
00769     if (str) {
00770         if (len == SQL_NTS) {
00771             len = strlen((char *) str);
00772         }
00773         ucLen = sizeof (SQLWCHAR) * (len + 1);
00774         uc = xmalloc(ucLen);
00775         if (uc) {
00776             uc_from_utf_buf(str, len, uc, ucLen);
00777         }
00778     }
00779     return uc;
00780 }
00781 
00789 static char *
00790 uc_to_utf(SQLWCHAR *str, int len)
00791 {
00792     int i;
00793     char *cp, *ret = NULL;
00794 
00795     if (!str) {
00796         return ret;
00797     }
00798     if (len == SQL_NTS) {
00799         len = uc_strlen(str);
00800     } else {
00801         len = len / sizeof (SQLWCHAR);
00802     }
00803     cp = xmalloc(len * 6 + 1);
00804     if (!cp) {
00805         return ret;
00806     }
00807     ret = cp;
00808     for (i = 0; i < len; i++) {
00809         unsigned long c = str[i];
00810 
00811         if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
00812             c &= 0xffff;
00813         }
00814         if (c < 0x80) {
00815             *cp++ = c;
00816         } else if (c < 0x800) {
00817             *cp++ = 0xc0 | ((c >> 6) & 0x1f);
00818             *cp++ = 0x80 | (c & 0x3f);
00819         } else if (c < 0x10000) {
00820             if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
00821                 c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
00822                 unsigned long c2 = str[i + 1] & 0xffff;
00823 
00824                 if (c2 >= 0xdc00 && c2 <= 0xdfff) {
00825                     c = (((c & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10000;
00826                     *cp++ = 0xf0 | ((c >> 18) & 0x07);
00827                     *cp++ = 0x80 | ((c >> 12) & 0x3f);
00828                     *cp++ = 0x80 | ((c >> 6) & 0x3f);
00829                     *cp++ = 0x80 | (c & 0x3f);
00830                     ++i;
00831                     continue;
00832                 }
00833             }
00834             *cp++ = 0xe0 | ((c >> 12) & 0x0f);
00835             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00836             *cp++ = 0x80 | (c & 0x3f);
00837         } else if (c < 0x200000) {
00838             *cp++ = 0xf0 | ((c >> 18) & 0x07);
00839             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00840             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00841             *cp++ = 0x80 | (c & 0x3f);
00842         } else if (c < 0x4000000) {
00843             *cp++ = 0xf8 | ((c >> 24) & 0x03);
00844             *cp++ = 0x80 | ((c >> 18) & 0x3f);
00845             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00846             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00847             *cp++ = 0x80 | (c & 0x3f);
00848         } else if (c < 0x80000000) {
00849             *cp++ = 0xfc | ((c >> 31) & 0x01);
00850             *cp++ = 0x80 | ((c >> 24) & 0x3f);
00851             *cp++ = 0x80 | ((c >> 18) & 0x3f);
00852             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00853             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00854             *cp++ = 0x80 | (c & 0x3f);
00855         }
00856     }
00857     *cp = '\0';
00858     return ret;
00859 }
00860 
00861 #endif
00862 
00863 #ifdef WINTERFACE
00864 
00872 static char *
00873 uc_to_utf_c(SQLWCHAR *str, int len)
00874 {
00875     if (len != SQL_NTS) {
00876         len = len * sizeof (SQLWCHAR);
00877     }
00878     return uc_to_utf(str, len);
00879 }
00880 
00881 #endif
00882 
00883 #if defined(WCHARSUPPORT) || defined(_WIN32) || defined(_WIN64)
00884 
00890 static void
00891 uc_free(void *str)
00892 {
00893     if (str) {
00894         xfree(str);
00895     }
00896 }
00897 
00898 #endif
00899 
00900 #if defined(_WIN32) || defined(_WIN64)
00901 
00909 static char *
00910 wmb_to_utf(char *str, int len)
00911 {
00912     WCHAR *wstr;
00913     OSVERSIONINFO ovi;
00914     int nchar, is2k, cp = CP_OEMCP;
00915 
00916     ovi.dwOSVersionInfoSize = sizeof (ovi);
00917     GetVersionEx(&ovi);
00918     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
00919     if (AreFileApisANSI()) {
00920         cp = is2k ? CP_THREAD_ACP : CP_ACP;
00921     }
00922     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
00923     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
00924     if (!wstr) {
00925         return NULL;
00926     }
00927     wstr[0] = 0;
00928     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
00929     wstr[nchar] = 0;
00930     str = xmalloc((nchar + 1) * 7);
00931     if (!str) {
00932         xfree(wstr);
00933         return NULL;
00934     }
00935     str[0] = '\0';
00936     nchar = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, nchar * 7, 0, 0);
00937     str[nchar] = '\0';
00938     xfree(wstr);
00939     return str;
00940 }
00941 
00942 #ifndef WINTERFACE
00943 
00951 static char *
00952 wmb_to_utf_c(char *str, int len)
00953 {
00954     if (len == SQL_NTS) {
00955         len = strlen(str);
00956     }
00957     return wmb_to_utf(str, len);
00958 }
00959 
00960 #endif
00961 
00969 static char *
00970 utf_to_wmb(char *str, int len)
00971 {
00972     WCHAR *wstr;
00973     OSVERSIONINFO ovi;
00974     int nchar, is2k, cp = CP_OEMCP;
00975 
00976     ovi.dwOSVersionInfoSize = sizeof (ovi);
00977     GetVersionEx(&ovi);
00978     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
00979     if (AreFileApisANSI()) {
00980         cp = is2k ? CP_THREAD_ACP : CP_ACP;
00981     }
00982     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
00983     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
00984     if (!wstr) {
00985         return NULL;
00986     }
00987     wstr[0] = 0;
00988     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, nchar);
00989     wstr[nchar] = 0;
00990     str = xmalloc((nchar + 1) * 7);
00991     if (!str) {
00992         xfree(wstr);
00993         return NULL;
00994     }
00995     str[0] = '\0';
00996     nchar = WideCharToMultiByte(cp, 0, wstr, -1, str, nchar * 7, 0, 0);
00997     str[nchar] = '\0';
00998     xfree(wstr);
00999     return str;
01000 }
01001 
01002 #ifdef WINTERFACE
01003 
01011 static WCHAR *
01012 wmb_to_uc(char *str, int len)
01013 {
01014     WCHAR *wstr;
01015     OSVERSIONINFO ovi;
01016     int nchar, is2k, cp = CP_OEMCP;
01017 
01018     ovi.dwOSVersionInfoSize = sizeof (ovi);
01019     GetVersionEx(&ovi);
01020     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
01021     if (AreFileApisANSI()) {
01022         cp = is2k ? CP_THREAD_ACP : CP_ACP;
01023     }
01024     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
01025     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
01026     if (!wstr) {
01027         return NULL;
01028     }
01029     wstr[0] = 0;
01030     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
01031     wstr[nchar] = 0;
01032     return wstr;
01033 }
01034 
01042 static char *
01043 uc_to_wmb(WCHAR *wstr, int len)
01044 {
01045     char *str;
01046     OSVERSIONINFO ovi;
01047     int nchar, is2k, cp = CP_OEMCP;
01048 
01049     ovi.dwOSVersionInfoSize = sizeof (ovi);
01050     GetVersionEx(&ovi);
01051     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
01052     if (AreFileApisANSI()) {
01053         cp = is2k ? CP_THREAD_ACP : CP_ACP;
01054     }
01055     nchar = WideCharToMultiByte(cp, 0, wstr, len, NULL, 0, 0, 0);
01056     str = xmalloc((nchar + 1) * 2);
01057     if (!str) {
01058         return NULL;
01059     }
01060     str[0] = '\0';
01061     nchar = WideCharToMultiByte(cp, 0, wstr, len, str, nchar * 2, 0, 0);
01062     str[nchar] = '\0';
01063     return str;
01064 }
01065 
01066 #endif /* WINTERFACE */
01067 
01068 #endif /* _WIN32 || _WIN64 */
01069 
01070 
01071 #ifdef USE_DLOPEN_FOR_GPPS
01072 
01073 #include <dlfcn.h>
01074 
01075 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
01076 
01077 /*
01078  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
01079  * dlopen(), in theory this makes the driver independent from the
01080  * driver manager, i.e. the same driver binary can run with iODBC
01081  * and unixODBC.
01082  */
01083 
01084 static void
01085 drvgetgpps(DBC *d)
01086 {
01087     void *lib;
01088     int (*gpps)();
01089 
01090     lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
01091     if (!lib) {
01092         lib = dlopen("libodbcinst.so", RTLD_LAZY);
01093     }
01094     if (!lib) {
01095         lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
01096     }
01097     if (!lib) {
01098         lib = dlopen("libiodbcinst.so", RTLD_LAZY);
01099     }
01100     if (lib) {
01101         gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
01102         if (!gpps) {
01103             dlclose(lib);
01104             return;
01105         }
01106         d->instlib = lib;
01107         d->gpps = gpps;
01108     }
01109 }
01110 
01111 static void
01112 drvrelgpps(DBC *d)
01113 {
01114     if (d->instlib) {
01115         dlclose(d->instlib);
01116         d->instlib = 0;
01117     }
01118 }
01119 
01120 static int
01121 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
01122         int bufsiz, char *fname)
01123 {
01124     if (d->gpps) {
01125         return d->gpps(sect, ent, def, buf, bufsiz, fname);
01126     }
01127     strncpy(buf, def, bufsiz);
01128     buf[bufsiz - 1] = '\0';
01129     return 1;
01130 }
01131 #else
01132 #include <odbcinst.h>
01133 #define drvgetgpps(d)
01134 #define drvrelgpps(d)
01135 #endif
01136 
01137 /*
01138  * Internal function to bind SQLite3 parameters.
01139  */
01140 
01141 static void
01142 s3bind(DBC *d, sqlite3_stmt *stmt, int nparams, BINDPARM *p)
01143 {
01144     int i;
01145 
01146     if (stmt && p && nparams > 0) {
01147         for (i = 0; i < nparams; i++, p++) {
01148             switch (p->s3type) {
01149             default:
01150             case SQLITE_NULL:
01151                 sqlite3_bind_null(stmt, i + 1);
01152                 if (d->trace) {
01153                     fprintf(d->trace, "-- parameter %d: NULL\n", i + 1);
01154                     fflush(d->trace);
01155                 }
01156                 break;
01157             case SQLITE_TEXT:
01158                 sqlite3_bind_text(stmt, i + 1, p->s3val, p->s3size,
01159                                   SQLITE_STATIC);
01160                 if (d->trace) {
01161                     fprintf(d->trace, "-- parameter %d: '%*s'\n", i + 1,
01162                             p->s3size, (char *) p->s3val);
01163                     fflush(d->trace);
01164                 }
01165                 break;
01166             case SQLITE_BLOB:
01167                 sqlite3_bind_blob(stmt, i + 1, p->s3val, p->s3size,
01168                                   SQLITE_STATIC);
01169                 if (d->trace) {
01170                     fprintf(d->trace, "-- parameter %d: [BLOB]'\n", i + 1);
01171                     fflush(d->trace);
01172                 }
01173                 break;
01174             case SQLITE_FLOAT:
01175                 sqlite3_bind_double(stmt, i + 1, p->s3dval);
01176                 if (d->trace) {
01177                     fprintf(d->trace, "-- parameter %d: %g\n",
01178                             i + 1, p->s3dval);
01179                     fflush(d->trace);
01180                 }
01181                 break;
01182             case SQLITE_INTEGER:
01183                 if (p->s3size > sizeof (int)) {
01184                     sqlite3_bind_int64(stmt, i + 1, p->s3lival);
01185                     if (d->trace) {
01186                         fprintf(d->trace,
01187 #ifdef _WIN32
01188                                 "-- parameter %d: %I64d\n",
01189 #else
01190                                 "-- parameter %d: %lld\n",
01191 #endif
01192                                 i + 1, p->s3lival);
01193                         fflush(d->trace);
01194                     }
01195                 } else {
01196                     sqlite3_bind_int(stmt, i + 1, p->s3ival);
01197                     if (d->trace) {
01198                         fprintf(d->trace, "-- parameter %d: %d\n",
01199                                 i + 1, p->s3ival);
01200                         fflush(d->trace);
01201                     }
01202                 }
01203                 break;
01204             }
01205         }
01206     }
01207 }
01208 
01216 typedef struct tblres {
01217     char **resarr;      
01218     char *errmsg;       
01219     sqlite3_stmt *stmt; 
01220     STMT *s;            
01221     int nalloc;         
01222     int nrow;           
01223     int ncol;           
01224     PTRDIFF_T ndata;    
01225     int rc;             
01226 } TBLRES;
01227 
01228 /*
01229  * Driver's version of sqlite3_get_table() and friends which are
01230  * capable of dealing with blobs.
01231  */
01232 
01233 static int
01234 drvgettable_row(TBLRES *t, int ncol, int rc)
01235 {
01236     int need;
01237     int i;
01238     char *p;
01239 
01240     if (t->nrow == 0 && rc == SQLITE_ROW) {
01241         need = ncol * 2;
01242     } else {
01243         need = ncol;
01244     }
01245     if (t->ndata + need >= t->nalloc) {
01246         char **resnew;
01247         int nalloc = t->nalloc * 2 + need + 1;
01248 
01249         resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
01250         if (!resnew) {
01251 nomem:
01252             t->rc = SQLITE_NOMEM;
01253             return 1;
01254         }
01255         t->nalloc = nalloc;
01256         t->resarr = resnew;
01257     }
01258     /* column names when first row */
01259     if (t->nrow == 0) {
01260         t->ncol = ncol;
01261         for (i = 0; i < ncol; i++) {
01262             p = (char *) sqlite3_column_name(t->stmt, i);
01263             if (p) {
01264                 char *q = xmalloc(strlen(p) + 1);
01265 
01266                 if (!q) {
01267                     goto nomem;
01268                 }
01269                 strcpy(q, p);
01270                 p = q;
01271             }
01272             t->resarr[t->ndata++] = p;
01273         }
01274         if (t->s && t->s->guessed_types) {
01275             int ncol2 = ncol;
01276 
01277             setupdyncols(t->s, t->stmt, &ncol2);
01278             t->s->guessed_types = 0;
01279             t->s->ncols = ncol;
01280         }
01281     } else if (t->ncol != ncol) {
01282         t->errmsg = sqlite3_mprintf("drvgettable() called with two or"
01283                                     " more incompatible queries");
01284         t->rc = SQLITE_ERROR;
01285         return 1;
01286     }
01287     /* copy row data */
01288     if (rc == SQLITE_ROW) {
01289         for (i = 0; i < ncol; i++) {
01290             int coltype = sqlite3_column_type(t->stmt, i);
01291 
01292             p = NULL;
01293             if (coltype == SQLITE_BLOB) {
01294                 int k, nbytes = sqlite3_column_bytes(t->stmt, i);
01295                 char *qp;
01296                 unsigned const char *bp;
01297 
01298                 bp = sqlite3_column_blob(t->stmt, i);
01299                 qp = xmalloc(nbytes * 2 + 4);
01300                 if (!qp) {
01301                     goto nomem;
01302                 }
01303                 p = qp;
01304                 *qp++ = 'X';
01305                 *qp++ = '\'';
01306                 for (k = 0; k < nbytes; k++) {
01307                     *qp++ = xdigits[(bp[k] >> 4)];
01308                     *qp++ = xdigits[(bp[k] & 0xF)];
01309                 }
01310                 *qp++ = '\'';
01311                 *qp = '\0';
01312 #ifdef _MSC_VER
01313             } else if (coltype == SQLITE_FLOAT) {
01314                 static struct lconv *lc = 0;
01315                 double val = sqlite3_column_double(t->stmt, i);
01316                 char buffer[128];
01317 
01318                 /*
01319                  * This avoids floating point rounding
01320                  * and formatting problems of some SQLite
01321                  * versions in conjunction with MSVC 2010.
01322                  */
01323                 snprintf(buffer, sizeof (buffer), "%.15g", val);
01324                 if (!lc) {
01325                     lc = localeconv();
01326                 }
01327                 if (lc && lc->decimal_point && lc->decimal_point[0] &&
01328                     lc->decimal_point[0] != '.') {
01329                     p = strchr(buffer, lc->decimal_point[0]);
01330                     if (p) {
01331                         *p = '.';
01332                     }
01333                 }
01334                 p = xstrdup(buffer);
01335                 if (!p) {
01336                     goto nomem;
01337                 }
01338 #endif
01339             } else if (coltype != SQLITE_NULL) {
01340                 p = xstrdup((char *) sqlite3_column_text(t->stmt, i));
01341                 if (!p) {
01342                     goto nomem;
01343                 }
01344             }
01345             t->resarr[t->ndata++] = p;
01346         }
01347         t->nrow++;
01348     }
01349     return 0;
01350 }
01351 
01352 static int
01353 drvgettable(STMT *s, const char *sql, char ***resp, int *nrowp,
01354             int *ncolp, char **errp, int nparam, BINDPARM *p)
01355 {
01356     DBC *d = (DBC *) s->dbc;
01357     int rc = SQLITE_OK, keep = sql == NULL;
01358     TBLRES tres;
01359     const char *sqlleft = 0;
01360     int nretry = 0, haveerr = 0;
01361 
01362     if (!resp) {
01363         return SQLITE_ERROR;
01364     }
01365     *resp = NULL;
01366     if (nrowp) {
01367         *nrowp = 0;
01368     }
01369     if (ncolp) {
01370         *ncolp = 0;
01371     }
01372     tres.errmsg = NULL;
01373     tres.nrow = 0;
01374     tres.ncol = 0;
01375     tres.ndata = 1;
01376     tres.nalloc = 20;
01377     tres.rc = SQLITE_OK;
01378     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
01379     tres.stmt = NULL;
01380     tres.s = s;
01381     if (!tres.resarr) {
01382         return SQLITE_NOMEM;
01383     }
01384     tres.resarr[0] = 0;
01385     if (sql == NULL) {
01386         tres.stmt = s->s3stmt;
01387         if (tres.stmt == NULL) {
01388             return SQLITE_NOMEM;
01389         }
01390         goto retrieve;
01391     }
01392     while (sql && *sql && (rc == SQLITE_OK ||
01393                            (rc == SQLITE_SCHEMA && (++nretry) < 2))) {
01394         int ncol;
01395 
01396         tres.stmt = NULL;
01397 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
01398         dbtraceapi(d, "sqlite3_prepare_v2", sql);
01399         rc = sqlite3_prepare_v2(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
01400 #else
01401         dbtraceapi(d, "sqlite3_prepare", sql);
01402         rc = sqlite3_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
01403 #endif
01404         if (rc != SQLITE_OK) {
01405             if (tres.stmt) {
01406                 dbtraceapi(d, "sqlite3_finalize", 0);
01407                 sqlite3_finalize(tres.stmt);
01408                 tres.stmt = NULL;
01409             }
01410             continue;
01411         }
01412         if (!tres.stmt) {
01413             /* this happens for a comment or white-space */
01414             sql = sqlleft;
01415             continue;
01416         }
01417 retrieve:
01418         if (sqlite3_bind_parameter_count(tres.stmt) != nparam) {
01419             if (errp) {
01420                 *errp =
01421                     sqlite3_mprintf("%s", "parameter marker count incorrect");
01422             }
01423             haveerr = 1;
01424             rc = SQLITE_ERROR;
01425             goto tbldone;
01426         }
01427         s3bind(d, tres.stmt, nparam, p);
01428         ncol = sqlite3_column_count(tres.stmt);
01429         while (1) {
01430             if (s->max_rows && tres.nrow >= s->max_rows) {
01431                 rc = SQLITE_OK;
01432                 break;
01433             }
01434             rc = sqlite3_step(tres.stmt);
01435             if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
01436                 if (drvgettable_row(&tres, ncol, rc)) {
01437                     rc = SQLITE_ABORT;
01438                     goto tbldone;
01439                 }
01440             }
01441             if (rc != SQLITE_ROW) {
01442                 if (keep) {
01443                     dbtraceapi(d, "sqlite3_reset", 0);
01444                     rc = sqlite3_reset(tres.stmt);
01445                     s->s3stmt_noreset = 1;
01446                 } else {
01447                     dbtraceapi(d, "sqlite3_finalize", 0);
01448                     rc = sqlite3_finalize(tres.stmt);
01449                 }
01450                 tres.stmt = 0;
01451                 if (rc != SQLITE_SCHEMA) {
01452                     nretry = 0;
01453                     sql = sqlleft;
01454                     while (sql && ISSPACE(*sql)) {
01455                         sql++;
01456                     }
01457                 }
01458                 if (rc == SQLITE_DONE) {
01459                     rc = SQLITE_OK;
01460                 }
01461                 break;
01462             }
01463         }
01464     }
01465 tbldone:
01466     if (tres.stmt) {
01467         if (keep) {
01468             if (!s->s3stmt_noreset) {
01469                 dbtraceapi(d, "sqlite3_reset", 0);
01470                 sqlite3_reset(tres.stmt);
01471                 s->s3stmt_noreset = 1;
01472             }
01473         } else {
01474             dbtraceapi(d, "sqlite3_finalize", 0);
01475             sqlite3_finalize(tres.stmt);
01476         }
01477     }
01478     if (haveerr) {
01479         /* message already in *errp if any */
01480     } else if (rc != SQLITE_OK && rc == sqlite3_errcode(d->sqlite) && errp) {
01481         *errp = sqlite3_mprintf("%s", sqlite3_errmsg(d->sqlite));
01482     } else if (errp) {
01483         *errp = NULL;
01484     }
01485     if (tres.resarr) {
01486         tres.resarr[0] = (char *) (tres.ndata - 1);
01487     }
01488     if (rc == SQLITE_ABORT) {
01489         freerows(&tres.resarr[1]);
01490         if (tres.errmsg) {
01491             if (errp) {
01492                 if (*errp) {
01493                     sqlite3_free(*errp);
01494                 }
01495                 *errp = tres.errmsg;
01496             } else {
01497                 sqlite3_free(tres.errmsg);
01498             }
01499         }
01500         return tres.rc;
01501     }
01502     sqlite3_free(tres.errmsg);
01503     if (rc != SQLITE_OK) {
01504         freerows(&tres.resarr[1]);
01505         return rc;
01506     }
01507     *resp = &tres.resarr[1];
01508     if (ncolp) {
01509         *ncolp = tres.ncol;
01510     }
01511     if (nrowp) {
01512         *nrowp = tres.nrow;
01513     }
01514     return rc;
01515 }
01516 
01525 #if defined(__GNUC__) && (__GNUC__ >= 2)
01526 static void setstatd(DBC *, int, char *, char *, ...)
01527     __attribute__((format (printf, 3, 5)));
01528 #endif
01529 
01530 static void
01531 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
01532 {
01533     va_list ap;
01534 
01535     if (!d) {
01536         return;
01537     }
01538     d->naterr = naterr;
01539     d->logmsg[0] = '\0';
01540     if (msg) {
01541         int count;
01542 
01543         va_start(ap, st);
01544         count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
01545         va_end(ap);
01546         if (count < 0) {
01547             d->logmsg[sizeof (d->logmsg) - 1] = '\0';
01548         }
01549     }
01550     if (!st) {
01551         st = "?????";
01552     }
01553     strncpy(d->sqlstate, st, 5);
01554     d->sqlstate[5] = '\0';
01555 }
01556 
01565 #if defined(__GNUC__) && (__GNUC__ >= 2)
01566 static void setstat(STMT *, int, char *, char *, ...)
01567     __attribute__((format (printf, 3, 5)));
01568 #endif
01569 
01570 static void
01571 setstat(STMT *s, int naterr, char *msg, char *st, ...)
01572 {
01573     va_list ap;
01574 
01575     if (!s) {
01576         return;
01577     }
01578     s->naterr = naterr;
01579     s->logmsg[0] = '\0';
01580     if (msg) {
01581         int count;
01582 
01583         va_start(ap, st);
01584         count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
01585         va_end(ap);
01586         if (count < 0) {
01587             s->logmsg[sizeof (s->logmsg) - 1] = '\0';
01588         }
01589     }
01590     if (!st) {
01591         st = "?????";
01592     }
01593     strncpy(s->sqlstate, st, 5);
01594     s->sqlstate[5] = '\0';
01595 }
01596 
01603 static SQLRETURN
01604 drvunimpldbc(HDBC dbc)
01605 {
01606     DBC *d;
01607 
01608     if (dbc == SQL_NULL_HDBC) {
01609         return SQL_INVALID_HANDLE;
01610     }
01611     d = (DBC *) dbc;
01612     setstatd(d, -1, "not supported", "IM001");
01613     return SQL_ERROR;
01614 }
01615 
01622 static SQLRETURN
01623 drvunimplstmt(HSTMT stmt)
01624 {
01625     STMT *s;
01626 
01627     if (stmt == SQL_NULL_HSTMT) {
01628         return SQL_INVALID_HANDLE;
01629     }
01630     s = (STMT *) stmt;
01631     setstat(s, -1, "not supported", "IM001");
01632     return SQL_ERROR;
01633 }
01634 
01640 static void
01641 freep(void *x)
01642 {
01643     if (x && ((char **) x)[0]) {
01644         xfree(((char **) x)[0]);
01645         ((char **) x)[0] = NULL;
01646     }
01647 }
01648 
01655 static SQLRETURN
01656 nomem(STMT *s)
01657 {
01658     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
01659     return SQL_ERROR;
01660 }
01661 
01668 static SQLRETURN
01669 noconn(STMT *s)
01670 {
01671     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
01672     return SQL_ERROR;
01673 }
01674 
01682 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
01683 
01684 static double
01685 ln_strtod(const char *data, char **endp)
01686 {
01687     static struct lconv *lc = 0;
01688     char buf[128], *p, *end;
01689     double value;
01690 
01691     if (!lc) {
01692         lc = localeconv();
01693     }
01694     if (lc && lc->decimal_point && lc->decimal_point[0] &&
01695         lc->decimal_point[0] != '.') {
01696         strncpy(buf, data, sizeof (buf) - 1);
01697         buf[sizeof (buf) - 1] = '\0';
01698         p = strchr(buf, '.');
01699         if (p) {
01700             *p = lc->decimal_point[0];
01701         }
01702         p = buf;
01703     } else {
01704         p = (char *) data;
01705     }
01706     value = strtod(p, &end);
01707     end = (char *) data + (end - p);
01708     if (endp) {
01709         *endp = end;
01710     }
01711     return value;
01712 }
01713 
01714 #else
01715 
01716 #define ln_strtod(A,B) strtod(A,B)
01717 
01718 #endif
01719 
01725 static char *
01726 unquote(char *str)
01727 {
01728     if (str) {
01729         int len = strlen(str);
01730 
01731         if (len > 1) {
01732             if ((str[0] == '\'' && str[len - 1] == '\'') ||
01733                 (str[0] == '"' && str[len - 1] == '"') ||
01734                 (str[0] == '[' && str[len - 1] == ']')) {
01735                 str[len - 1] = '\0';
01736                 strcpy(str, str + 1);
01737             }
01738         }
01739     }
01740     return str;
01741 }
01742 
01750 static int
01751 unescpat(char *str)
01752 {
01753     char *p, *q;
01754     int count = 0;
01755 
01756     p = str;
01757     while ((q = strchr(p, '_')) != NULL) {
01758         if (q == str || q[-1] != '\\') {
01759             count++;
01760         }
01761         p = q + 1;
01762     }
01763     p = str;
01764     while ((q = strchr(p, '%')) != NULL) {
01765         if (q == str || q[-1] != '\\') {
01766             count++;
01767         }
01768         p = q + 1;
01769     }
01770     p = str;
01771     while ((q = strchr(p, '\\')) != NULL) {
01772         if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
01773             strcpy(q, q + 1);
01774         }
01775         p = q + 1;
01776     }
01777     return count;
01778 }
01779 
01788 static int
01789 namematch(char *str, char *pat, int esc)
01790 {
01791     int cp, ch;
01792 
01793     while (1) {
01794         cp = TOLOWER(*pat);
01795         if (cp == '\0') {
01796             if (*str != '\0') {
01797                 goto nomatch;
01798             }
01799             break;
01800         }
01801         if (*str == '\0' && cp != '%') {
01802             goto nomatch;
01803         }
01804         if (cp == '%') {
01805             while (*pat == '%') {
01806                 ++pat;
01807             }
01808             cp = TOLOWER(*pat);
01809             if (cp == '\0') {
01810                 break;
01811             }
01812             while (1) {
01813                 if (cp != '_' && cp != '\\') {
01814                     while (*str) {
01815                         ch = TOLOWER(*str);
01816                         if (ch == cp) {
01817                             break;
01818                         }
01819                         ++str;
01820                     }
01821                 }
01822                 if (namematch(str, pat, esc)) {
01823                     goto match;
01824                 }
01825                 if (*str == '\0') {
01826                     goto nomatch;
01827                 }
01828                 ch = TOLOWER(*str);
01829                 ++str;
01830             }
01831         }
01832         if (cp == '_') {
01833             pat++;
01834             str++;
01835             continue;
01836         }
01837         if (esc && cp == '\\' &&
01838             (pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
01839             ++pat;
01840             cp = TOLOWER(*pat);
01841         }
01842         ch = TOLOWER(*str++);
01843         ++pat;
01844         if (ch != cp) {
01845             goto nomatch;
01846         }
01847     }
01848 match:
01849     return 1;
01850 nomatch:
01851     return 0;
01852 }
01853 
01861 static int
01862 busy_handler(void *udata, int count)
01863 {
01864     DBC *d = (DBC *) udata;
01865     long t1;
01866     int ret = 0;
01867 #if !defined(_WIN32) && !defined(_WIN64)
01868     struct timeval tv;
01869 #ifdef HAVE_NANOSLEEP
01870     struct timespec ts;
01871 #endif
01872 #endif
01873 
01874     if (d->busyint) {
01875         d->busyint = 0;
01876         return ret;
01877     }
01878     if (d->timeout <= 0) {
01879         return ret;
01880     }
01881     if (count <= 1) {
01882 #if defined(_WIN32) || defined(_WIN64)
01883         d->t0 = GetTickCount();
01884 #else
01885         gettimeofday(&tv, NULL);
01886         d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
01887 #endif
01888     }
01889 #if defined(_WIN32) || defined(_WIN64)
01890     t1 = GetTickCount();
01891 #else
01892     gettimeofday(&tv, NULL);
01893     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
01894 #endif
01895     if (t1 - d->t0 > d->timeout) {
01896         goto done;
01897     }
01898 #if defined(_WIN32) || defined(_WIN64)
01899     Sleep(10);
01900 #else
01901 #ifdef HAVE_NANOSLEEP
01902     ts.tv_sec = 0;
01903     ts.tv_nsec = 10000000;
01904     do {
01905         ret = nanosleep(&ts, &ts);
01906         if (ret < 0 && errno != EINTR) {
01907             ret = 0;
01908         }
01909     } while (ret); 
01910 #else
01911 #ifdef HAVE_USLEEP
01912     usleep(10000);
01913 #else
01914     tv.tv_sec = 0;
01915     tv.tv_usec = 10000;
01916     select(0, NULL, NULL, NULL, &tv);
01917 #endif
01918 #endif
01919 #endif
01920     ret = 1;
01921 done:
01922     return ret;
01923 }
01924 
01936 static int
01937 setsqliteopts(sqlite3 *x, DBC *d)
01938 {
01939     int count = 0, step = 0, max, rc = SQLITE_ERROR;
01940 
01941 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
01942     max = d->longnames ? 3 : 1;
01943 #else
01944     max = 3;
01945 #endif
01946     if (d->shortnames) {
01947         max = 3;
01948     }
01949     while (step < max) {
01950         if (step < 1) {
01951             rc = sqlite3_exec(x, "PRAGMA empty_result_callbacks = on;",
01952                               NULL, NULL, NULL);
01953             if (rc == SQLITE_OK) {
01954                 rc = sqlite3_exec(x, d->fksupport ?
01955                                   "PRAGMA foreign_keys = on;" :
01956                                   "PRAGMA foreign_keys = off;",
01957                                   NULL, NULL, NULL);
01958             }
01959         } else if (step < 2) {
01960             rc = sqlite3_exec(x, d->shortnames ?
01961                               "PRAGMA full_column_names = off;" :
01962                               "PRAGMA full_column_names = on;",
01963                               NULL, NULL, NULL);
01964         } else if (step < 3) {
01965             rc = sqlite3_exec(x, d->shortnames ?
01966                               "PRAGMA short_column_names = on;" :
01967                               "PRAGMA short_column_names = off;",
01968                               NULL, NULL, NULL);
01969         }
01970         if (rc != SQLITE_OK) {
01971             if (rc != SQLITE_BUSY ||
01972                 !busy_handler((void *) d, ++count)) {
01973                 return rc;
01974             }
01975             continue;
01976         }
01977         count = 0;
01978         ++step;
01979     }
01980     sqlite3_busy_handler(x, busy_handler, (void *) d);
01981     return SQLITE_OK;
01982 }
01983 
01993 static void
01994 freerows(char **rowp)
01995 {
01996     PTRDIFF_T size, i;
01997 
01998     if (!rowp) {
01999         return;
02000     }
02001     --rowp;
02002     size = (PTRDIFF_T) rowp[0];
02003     for (i = 1; i <= size; i++) {
02004         freep(&rowp[i]);
02005     }
02006     freep(&rowp);
02007 }
02008 
02019 static int
02020 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar,
02021            int dobigint)
02022 {
02023     char *p, *q;
02024     int testsign = 0, result;
02025 
02026 #ifdef WINTERFACE
02027     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
02028 #else
02029     result = SQL_VARCHAR;
02030 #endif
02031     if (!typename) {
02032         return result;
02033     }
02034     q = p = xmalloc(strlen(typename) + 1);
02035     if (!p) {
02036         return result;
02037     }
02038     strcpy(p, typename);
02039     while (*q) {
02040         *q = TOLOWER(*q);
02041         ++q;
02042     }
02043     if (strncmp(p, "inter", 5) == 0) {
02044     } else if (strncmp(p, "int", 3) == 0 ||
02045         strncmp(p, "mediumint", 9) == 0) {
02046         testsign = 1;
02047         result = SQL_INTEGER;
02048     } else if (strncmp(p, "numeric", 7) == 0) {
02049         result = SQL_DOUBLE;
02050     } else if (strncmp(p, "tinyint", 7) == 0) {
02051         testsign = 1;
02052         result = SQL_TINYINT;
02053     } else if (strncmp(p, "smallint", 8) == 0) {
02054         testsign = 1;
02055         result = SQL_SMALLINT;
02056     } else if (strncmp(p, "float", 5) == 0) {
02057         result = SQL_DOUBLE;
02058     } else if (strncmp(p, "double", 6) == 0 ||
02059         strncmp(p, "real", 4) == 0) {
02060         result = SQL_DOUBLE;
02061     } else if (strncmp(p, "timestamp", 9) == 0) {
02062 #ifdef SQL_TYPE_TIMESTAMP
02063         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
02064 #else
02065         result = SQL_TIMESTAMP;
02066 #endif
02067     } else if (strncmp(p, "datetime", 8) == 0) {
02068 #ifdef SQL_TYPE_TIMESTAMP
02069         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
02070 #else
02071         result = SQL_TIMESTAMP;
02072 #endif
02073     } else if (strncmp(p, "time", 4) == 0) {
02074 #ifdef SQL_TYPE_TIME
02075         result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
02076 #else
02077         result = SQL_TIME;
02078 #endif
02079     } else if (strncmp(p, "date", 4) == 0) {
02080 #ifdef SQL_TYPE_DATE
02081         result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
02082 #else
02083         result = SQL_DATE;
02084 #endif
02085 #ifdef SQL_LONGVARCHAR
02086     } else if (strncmp(p, "text", 4) == 0 ||
02087                strncmp(p, "memo", 4) == 0 ||
02088                strncmp(p, "longvarchar", 11) == 0) {
02089 #ifdef WINTERFACE
02090         result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
02091 #else
02092         result = SQL_LONGVARCHAR;
02093 #endif
02094 #ifdef WINTERFACE
02095     } else if (strncmp(p, "wtext", 5) == 0 ||
02096                strncmp(p, "wvarchar", 8) == 0 ||
02097                strncmp(p, "longwvarchar", 12) == 0) {
02098         result = SQL_WLONGVARCHAR;
02099 #endif
02100 #endif
02101 #ifdef SQL_BIT
02102     } else if (strncmp(p, "bool", 4) == 0 ||
02103                strncmp(p, "bit", 3) == 0) {
02104         result = SQL_BIT;
02105 #endif
02106 #ifdef SQL_BIGINT
02107     } else if (strncmp(p, "bigint", 6) == 0) {
02108         testsign = 1;
02109         result = SQL_BIGINT;
02110 #endif
02111     } else if (strncmp(p, "blob", 4) == 0) {
02112         result = SQL_BINARY;
02113     } else if (strncmp(p, "varbinary", 9) == 0) {
02114         result = SQL_VARBINARY;
02115     } else if (strncmp(p, "longvarbinary", 13) == 0) {
02116         result = SQL_LONGVARBINARY;
02117     }
02118     if (nosign) {
02119         if (testsign) {
02120             *nosign = strstr(p, "unsigned") != NULL;
02121         } else {
02122             *nosign = 1;
02123         }
02124     }
02125 #ifdef SQL_BIGINT
02126     if (dobigint && result == SQL_INTEGER) {
02127         result = SQL_BIGINT;
02128     }
02129 #endif
02130     xfree(p);
02131     return result;
02132 }
02133 
02143 static void
02144 getmd(const char *typename, int sqltype, int *mp, int *dp)
02145 {
02146     int m = 0, d = 0;
02147 
02148     switch (sqltype) {
02149     case SQL_INTEGER:       m = 10; d = 9; break;
02150     case SQL_TINYINT:       m = 4; d = 3; break;
02151     case SQL_SMALLINT:      m = 6; d = 5; break;
02152     case SQL_FLOAT:         m = 25; d = 24; break;
02153     case SQL_DOUBLE:        m = 54; d = 53; break;
02154     case SQL_VARCHAR:       m = 255; d = 0; break;
02155 #ifdef WINTERFACE
02156 #ifdef SQL_WVARCHAR
02157     case SQL_WVARCHAR:      m = 255; d = 0; break;
02158 #endif
02159 #endif
02160 #ifdef SQL_TYPE_DATE
02161     case SQL_TYPE_DATE:
02162 #endif
02163     case SQL_DATE:          m = 10; d = 0; break;
02164 #ifdef SQL_TYPE_TIME
02165     case SQL_TYPE_TIME:
02166 #endif
02167     case SQL_TIME:          m = 8; d = 0; break;
02168 #ifdef SQL_TYPE_TIMESTAMP
02169     case SQL_TYPE_TIMESTAMP:
02170 #endif
02171     case SQL_TIMESTAMP:     m = 32; d = 3; break;
02172 #ifdef SQL_LONGVARCHAR
02173     case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
02174 #endif
02175 #ifdef WINTERFACE
02176 #ifdef SQL_WLONGVARCHAR
02177     case SQL_WLONGVARCHAR:  m = 65536; d = 0; break;
02178 #endif
02179 #endif
02180     case SQL_VARBINARY:     m = 255; d = 0; break;
02181     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
02182 #ifdef SQL_BIGINT
02183     case SQL_BIGINT:        m = 20; d = 19; break;
02184 #endif
02185 #ifdef SQL_BIT
02186     case SQL_BIT:           m = 1; d = 1; break;
02187 #endif
02188     }
02189     if (m && typename) {
02190         int mm, dd;
02191 
02192         if (sscanf(typename, "%*[^(](%d)", &mm) == 1) {
02193             if (sqltype == SQL_TIMESTAMP) {
02194                 d = mm;
02195             }
02196 #ifdef SQL_TYPE_TIMESTAMP
02197             else if (sqltype == SQL_TYPE_TIMESTAMP) {
02198                 d = mm;
02199             }
02200 #endif
02201             else {
02202                 m = d = mm;
02203             }
02204         } else if (sscanf(typename, "%*[^(](%d,%d)", &mm, &dd) == 2) {
02205             m = mm;
02206             d = dd;
02207         }
02208     }
02209     if (mp) {
02210         *mp = m;
02211     }
02212     if (dp) {
02213         *dp = d;
02214     }
02215 }
02216 
02226 static int
02227 mapdeftype(int type, int stype, int nosign, int nowchar)
02228 {
02229     if (type == SQL_C_DEFAULT) {
02230         switch (stype) {
02231         case SQL_INTEGER:
02232             type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
02233             break;
02234         case SQL_TINYINT:
02235             type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
02236             break;
02237         case SQL_SMALLINT:
02238             type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
02239             break;
02240         case SQL_FLOAT:
02241             type = SQL_C_FLOAT;
02242             break;
02243         case SQL_DOUBLE:
02244             type = SQL_C_DOUBLE;
02245             break;
02246         case SQL_TIMESTAMP:
02247             type = SQL_C_TIMESTAMP;
02248             break;
02249         case SQL_TIME:
02250             type = SQL_C_TIME;
02251             break;
02252         case SQL_DATE:
02253             type = SQL_C_DATE;
02254             break;
02255 #ifdef SQL_C_TYPE_TIMESTAMP
02256         case SQL_TYPE_TIMESTAMP:
02257             type = SQL_C_TYPE_TIMESTAMP;
02258             break;
02259 #endif
02260 #ifdef SQL_C_TYPE_TIME
02261         case SQL_TYPE_TIME:
02262             type = SQL_C_TYPE_TIME;
02263             break;
02264 #endif
02265 #ifdef SQL_C_TYPE_DATE
02266         case SQL_TYPE_DATE:
02267             type = SQL_C_TYPE_DATE;
02268             break;
02269 #endif
02270 #ifdef WINTERFACE
02271         case SQL_WVARCHAR:
02272         case SQL_WCHAR:
02273 #ifdef SQL_WLONGVARCHAR
02274         case SQL_WLONGVARCHAR:
02275 #endif
02276             type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
02277             break;
02278 #endif
02279         case SQL_BINARY:
02280         case SQL_VARBINARY:
02281         case SQL_LONGVARBINARY:
02282             type = SQL_C_BINARY;
02283             break;
02284 #ifdef SQL_BIT
02285         case SQL_BIT:
02286             type = SQL_C_BIT;
02287             break;
02288 #endif
02289 #ifdef SQL_BIGINT
02290         case SQL_BIGINT:
02291             type = SQL_C_CHAR;
02292             break;
02293 #endif
02294         default:
02295 #ifdef WINTERFACE
02296             type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
02297 #else
02298             type = SQL_C_CHAR;
02299 #endif
02300             break;
02301         }
02302     }
02303     return type;
02304 }
02305 
02316 static char *
02317 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg)
02318 {
02319     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
02320     int np = 0, isddl = -1, size;
02321 
02322     *errmsg = NULL;
02323     if (sqlLen != SQL_NTS) {
02324         qz = q = xmalloc(sqlLen + 1);
02325         if (!qz) {
02326             return NULL;
02327         }
02328         memcpy(q, sql, sqlLen);
02329         q[sqlLen] = '\0';
02330         size = sqlLen * 4;
02331     } else {
02332         size = strlen(sql) * 4;
02333     }
02334     size += sizeof (char *) - 1;
02335     size &= ~(sizeof (char *) - 1);
02336     p = xmalloc(size);
02337     if (!p) {
02338 errout:
02339         freep(&qz);
02340         return NULL;
02341     }
02342     memset(p, 0, size);
02343     out = p;
02344     while (*q) {
02345         switch (*q) {
02346         case '\'':
02347         case '\"':
02348             if (q == inq) {
02349                 inq = NULL;
02350             } else if (!inq) {
02351                 inq = q + 1;
02352 
02353                 while (*inq) {
02354                     if (*inq == *q) {
02355                         if (inq[1] == *q) {
02356                             inq++;
02357                         } else {
02358                             break;
02359                         }
02360                     }
02361                     inq++;
02362                 }
02363             }
02364             *p++ = *q;
02365             break;
02366         case '?':
02367             *p++ = *q;
02368             if (!inq) {
02369                 np++;
02370             }
02371             break;
02372         case ';':
02373             if (!inq) {
02374                 if (isddl < 0) {
02375                     char *qq = out;
02376 
02377                     while (*qq && ISSPACE(*qq)) {
02378                         ++qq;
02379                     }
02380                     if (*qq && *qq != ';') {
02381                         int i;
02382                         static const struct {
02383                             int len;
02384                             const char *str;
02385                         } ddlstr[] = {
02386                             { 5, "alter" },
02387                             { 7, "analyze" },
02388                             { 6, "attach" },
02389                             { 5, "begin" },
02390                             { 6, "commit" },
02391                             { 6, "create" },
02392                             { 6, "detach" },
02393                             { 4, "drop" },
02394                             { 3, "end" },
02395                             { 7, "reindex" },
02396                             { 7, "release" },
02397                             { 8, "rollback" },
02398                             { 9, "savepoint" },
02399                             { 6, "vacuum" }
02400                         };
02401 
02402                         size = strlen(qq);
02403                         for (i = 0; i < array_size(ddlstr); i++) {
02404                             if (size >= ddlstr[i].len &&
02405                                 strncasecmp(qq, ddlstr[i].str, ddlstr[i].len)
02406                                 == 0) {
02407                                 isddl = 1;
02408                                 break;
02409                             }
02410                         }
02411                         if (isddl != 1) {
02412                             isddl = 0;
02413                         }
02414                     }
02415                 }
02416                 if (isddl == 0) {
02417                     char *qq = q;
02418 
02419                     do {
02420                         ++qq;
02421                     } while (*qq && ISSPACE(*qq));
02422                     if (*qq && *qq != ';') {
02423                         freep(&out);
02424                         *errmsg = "only one SQL statement allowed";
02425                         goto errout;
02426                     }
02427                 }
02428             }
02429             *p++ = *q;
02430             break;
02431         case '{':
02432             /*
02433              * Deal with escape sequences:
02434              * {d 'YYYY-MM-DD'}, {t ...}, {ts ...}
02435              * {oj ...}, {fn ...} etc.
02436              */
02437             if (!inq) {
02438                 int ojfn = 0;
02439                 char *inq2 = NULL, *end = q + 1;
02440 
02441                 while (*end && ISSPACE(*end)) {
02442                     ++end;
02443                 }
02444                 if (*end != 'd' && *end != 'D' &&
02445                     *end != 't' && *end != 'T') {
02446                     ojfn = 1;
02447                 }
02448                 while (*end) {
02449                     if (inq2 && *end == *inq2) {
02450                         inq2 = NULL;
02451                     } else if (inq2 == NULL && *end == '}') {
02452                         break;
02453                     } else if (inq2 == NULL && (*end == '\'' || *end == '"')) {
02454                         inq2 = end;
02455                     }
02456                     ++end;
02457                 }
02458                 if (*end == '}') {
02459                     char *start = q + 1;
02460                     char *end2 = end - 1;
02461 
02462                     if (ojfn) {
02463                         while (start < end) {
02464                             if (ISSPACE(*start)) {
02465                                 break;
02466                             }
02467                             ++start;
02468                         }
02469                         while (start < end) {
02470                             *p++ = *start;
02471                             ++start;
02472                         }
02473                         q = end;
02474                         break;
02475                     } else {
02476                         while (start < end2 && *start != '\'') {
02477                             ++start;
02478                         }
02479                         while (end2 > start && *end2 != '\'') {
02480                             --end2;
02481                         }
02482                         if (*start == '\'' && *end2 == '\'') {
02483                             while (start <= end2) {
02484                                 *p++ = *start;
02485                                 ++start;
02486                             }
02487                             q = end;
02488                             break;
02489                         }
02490                     }
02491                 }
02492             }
02493             /* FALL THROUGH */
02494         default:
02495             *p++ = *q;
02496         }
02497         ++q;
02498     }
02499     freep(&qz);
02500     *p = '\0';
02501     if (nparam) {
02502         *nparam = np;
02503     }
02504     if (isselect) {
02505         if (isddl > 0) {
02506             *isselect = 2;
02507         } else {
02508             int incom = 0;
02509 
02510             p = out;
02511             while (*p) {
02512                 switch (*p) {
02513                 case '-':
02514                     if (!incom && p[1] == '-') {
02515                         incom = -1;
02516                     }
02517                     break;
02518                 case '\n':
02519                     if (incom < 0) {
02520                         incom = 0;
02521                     }
02522                     break;
02523                 case '/':
02524                     if (incom > 0 && p[-1] == '*') {
02525                         incom = 0;
02526                         p++;
02527                         continue;
02528                     } else if (!incom && p[1] == '*') {
02529                         incom = 1;
02530                     }
02531                     break;
02532                 }
02533                 if (!incom && !ISSPACE(*p)) {
02534                     break;
02535                 }
02536                 p++;
02537             }
02538             size = strlen(p);
02539             if (size >= 6 &&
02540                 (strncasecmp(p, "select", 6) == 0 ||
02541                  strncasecmp(p, "pragma", 6) == 0)) {
02542                 *isselect = 1;
02543             } else {
02544                 *isselect = 0;
02545             }
02546         }
02547     }
02548     return out;
02549 }
02550 
02559 static int
02560 findcol(char **cols, int ncols, char *name)
02561 {
02562     int i;
02563 
02564     if (cols) {
02565         for (i = 0; i < ncols; i++) {
02566             if (strcmp(cols[i], name) == 0) {
02567                 return i;
02568             }
02569         }
02570     }
02571     return -1;
02572 }
02573 
02590 static void
02591 fixupdyncols(STMT *s, DBC *d)
02592 {
02593     int i;
02594 #if !defined(HAVE_SQLITE3TABLECOLUMNMETADATA) || !(HAVE_SQLITE3TABLECOLUMNMETADATA)
02595     int k, pk, nn, t, r, nrows, ncols;
02596     char **rowp, *flagp, flags[128];
02597 #endif
02598 
02599     if (!s->dyncols) {
02600         return;
02601     }
02602     /* fixup labels */
02603     if (!s->longnames) {
02604         if (s->dcols > 1) {
02605             char *table = s->dyncols[0].table;
02606 
02607             for (i = 1; table[0] && i < s->dcols; i++) {
02608                 if (strcmp(s->dyncols[i].table, table)) {
02609                     break;
02610                 }
02611             }
02612             if (i >= s->dcols) {
02613                 for (i = 0; i < s->dcols; i++) {
02614                     s->dyncols[i].label = s->dyncols[i].column;
02615                 }
02616             }
02617         } else if (s->dcols == 1) {
02618             s->dyncols[0].label = s->dyncols[0].column;
02619         }
02620     }
02621     for (i = 0; i < s->dcols; i++) {
02622         s->dyncols[i].type =
02623             mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3,
02624                        s->nowchar[0] || s->nowchar[1], s->dobigint);
02625         getmd(s->dyncols[i].typename, s->dyncols[i].type,
02626               &s->dyncols[i].size, &s->dyncols[i].prec);
02627 #ifdef SQL_LONGVARCHAR
02628         if (s->dyncols[i].type == SQL_VARCHAR &&
02629             s->dyncols[i].size > 255) {
02630             s->dyncols[i].type = SQL_LONGVARCHAR;
02631         }
02632 #endif
02633 #ifdef WINTERFACE
02634 #ifdef SQL_WLONGVARCHAR
02635         if (s->dyncols[i].type == SQL_WVARCHAR &&
02636             s->dyncols[i].size > 255) {
02637             s->dyncols[i].type = SQL_WLONGVARCHAR;
02638         }
02639 #endif
02640 #endif
02641         if (s->dyncols[i].type == SQL_VARBINARY &&
02642             s->dyncols[i].size > 255) {
02643             s->dyncols[i].type = SQL_LONGVARBINARY;
02644         }
02645     }
02646 #if !defined(HAVE_SQLITE3TABLECOLUMNMETADATA) || !(HAVE_SQLITE3TABLECOLUMNMETADATA)
02647     if (s->dcols > array_size(flags)) {
02648         flagp = xmalloc(sizeof (flags[0]) * s->dcols);
02649         if (flagp == NULL) {
02650             return;
02651         }
02652     } else {
02653         flagp = flags;
02654     }
02655     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
02656     for (i = 0; i < s->dcols; i++) {
02657         s->dyncols[i].autoinc = SQL_FALSE;
02658         s->dyncols[i].notnull = SQL_NULLABLE;
02659     }
02660     for (i = 0; i < s->dcols; i++) {
02661         int ret, lastpk = -1, autoinccount = 0;
02662         char *sql;
02663 
02664         if (!s->dyncols[i].table[0]) {
02665             continue;
02666         }
02667         if (flagp[i]) {
02668             continue;
02669         }
02670         sql = sqlite3_mprintf("PRAGMA table_info(%Q)", s->dyncols[i].table);
02671         if (!sql) {
02672             continue;
02673         }
02674         dbtraceapi(d, "sqlite3_get_table", sql);
02675         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, NULL);
02676         sqlite3_free(sql);
02677         if (ret != SQLITE_OK) {
02678             continue;
02679         }
02680         k = findcol(rowp, ncols, "name");
02681         t = findcol(rowp, ncols, "type");
02682         pk = findcol(rowp, ncols, "pk");
02683         nn = findcol(rowp, ncols, "notnull");
02684         if (k < 0 || t < 0) {
02685             goto freet;
02686         }
02687         for (r = 1; r <= nrows; r++) {
02688             int m;
02689 
02690             for (m = i; m < s->dcols; m++) {
02691                 char *colname = s->dyncols[m].column;
02692 
02693                 if (s->longnames) {
02694                     char *dotp = strchr(colname, '.');
02695 
02696                     if (dotp) {
02697                         colname = dotp + 1;
02698                     }
02699                 }
02700                 if (!flagp[m] &&
02701                     strcmp(colname, rowp[r * ncols + k]) == 0 &&
02702                     strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
02703                     char *typename = rowp[r * ncols + t];
02704 
02705                     flagp[m] = 1;
02706                     freep(&s->dyncols[m].typename);
02707                     s->dyncols[m].typename = xstrdup(typename);
02708                     s->dyncols[m].type =
02709                         mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
02710                                    s->nowchar[0] || s->nowchar[1],
02711                                    s->dobigint);
02712                     getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
02713                           &s->dyncols[m].prec);
02714 #ifdef SQL_LONGVARCHAR
02715                     if (s->dyncols[m].type == SQL_VARCHAR &&
02716                         s->dyncols[m].size > 255) {
02717                         s->dyncols[m].type = SQL_LONGVARCHAR;
02718                     }
02719 #endif
02720 #ifdef WINTERFACE
02721 #ifdef SQL_WLONGVARCHAR
02722                     if (s->dyncols[i].type == SQL_WVARCHAR &&
02723                         s->dyncols[i].size > 255) {
02724                         s->dyncols[i].type = SQL_WLONGVARCHAR;
02725                     }
02726 #endif
02727 #endif
02728                     if (s->dyncols[i].type == SQL_VARBINARY &&
02729                         s->dyncols[i].size > 255) {
02730                         s->dyncols[i].type = SQL_LONGVARBINARY;
02731                     }
02732                     if (pk >= 0 && strcmp(rowp[r * ncols + pk], "1") == 0) {
02733                         if (++autoinccount > 1) {
02734                             if (lastpk >= 0) {
02735                                 s->dyncols[lastpk].autoinc = SQL_FALSE;
02736                                 lastpk = -1;
02737                             }
02738                         } else {
02739                             lastpk = m;
02740                             if (strlen(typename) == 7 &&
02741                                 strncasecmp(typename, "integer", 7) == 0) {
02742                                 s->dyncols[m].autoinc = SQL_TRUE;
02743                             }
02744                         }
02745                     }
02746                     if (nn >= 0 && rowp[r * ncols + nn][0] != '0') {
02747                         s->dyncols[m].notnull = SQL_NO_NULLS;
02748                     }
02749                 }
02750             }
02751         }
02752 freet:
02753         sqlite3_free_table(rowp);
02754     }
02755     if (flagp != flags) {
02756         freep(&flagp);
02757     }
02758 #endif
02759 }
02760 
02767 static void
02768 convJD2YMD(double jd, DATE_STRUCT *ds)
02769 {
02770     int z, a, b, c, d, e, x1;
02771     sqlite_int64 ijd;
02772 
02773     ijd = jd * 86400000.0 + 0.5;
02774     z = (int) ((ijd + 43200000) / 86400000);
02775     a = (int) ((z - 1867216.25) / 36524.25);
02776     a = z + 1 + a - (a / 4);
02777     b = a + 1524;
02778     c = (int) ((b - 122.1) / 365.25);
02779     d = (36525 * c) / 100;
02780     e = (int) ((b - d) / 30.6001);
02781     x1 = (int) (30.6001 * e);
02782     ds->day = b - d - x1;
02783     ds->month = (e < 14) ? (e - 1) : (e - 13);
02784     ds->year = (ds->month > 2) ? (c - 4716) : (c - 4715);
02785 }
02786 
02787 
02795 static void
02796 convJD2HMS(double jd, TIME_STRUCT *ts, int *fp)
02797 {
02798     int s;
02799     double ds;
02800     sqlite_int64 ijd;
02801 
02802     ijd = jd * 86400000.0 + 0.5;
02803     s = (int)((ijd + 43200000) % 86400000);
02804     ds = s / 1000.0;
02805     if (fp) {
02806         *fp = (s % 1000) * 1000000;
02807     }
02808     s = (int) ds;
02809     ds -= s;
02810     ts->hour = s / 3600;
02811     s -= ts->hour * 3600;
02812     ts->minute = s / 60;
02813     ds += s - ts->minute *60;
02814     ts->second = (int) ds;
02815 }
02816 
02824 static int
02825 getmdays(int year, int month)
02826 {
02827     static const int mdays[] = {
02828         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
02829     };
02830     int mday;
02831 
02832     if (month < 1) {
02833         return 0;
02834     }
02835     mday = mdays[(month - 1) % 12];
02836     if (mday == 28 && year % 4 == 0 &&
02837         (!(year % 100 == 0) || year % 400 == 0)) {
02838         mday++;
02839     }
02840     return mday;
02841 }
02842 
02858 static int
02859 str2date(int jdconv, char *str, DATE_STRUCT *ds)
02860 {
02861     int i, err = 0;
02862     double jd;
02863     char *p, *q, sepc = '\0';
02864 
02865     ds->year = ds->month = ds->day = 0;
02866     if (jdconv) {
02867         p = strchr(str, '.');
02868         if (p) {
02869             /* julian day format */
02870             p = 0;
02871             jd = ln_strtod(str, &p);
02872             if (p && p > str) {
02873                 convJD2YMD(jd, ds);
02874                 return 0;
02875             }
02876         }
02877     }
02878     p = str;
02879     while (*p && !ISDIGIT(*p)) {
02880         ++p;
02881     }
02882     q = p;
02883     i = 0;
02884     while (*q && !ISDIGIT(*q)) {
02885         ++i;
02886         ++q;
02887     }
02888     if (i >= 8) {
02889         char buf[8];
02890 
02891         strncpy(buf, p + 0, 4); buf[4] = '\0';
02892         ds->year = strtol(buf, NULL, 10);
02893         strncpy(buf, p + 4, 2); buf[2] = '\0';
02894         ds->month = strtol(buf, NULL, 10);
02895         strncpy(buf, p + 6, 2); buf[2] = '\0';
02896         ds->day = strtol(buf, NULL, 10);
02897         goto done;
02898     }
02899     i = 0;
02900     while (i < 3) {
02901         int n;
02902 
02903         q = NULL; 
02904         n = strtol(p, &q, 10);
02905         if (!q || q == p) {
02906             if (*q == '\0') {
02907                 if (i == 0) {
02908                     err = 1;
02909                 }
02910                 goto done;
02911             }
02912         }
02913         if (!sepc) {
02914             sepc = *q;
02915         }
02916         if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
02917             switch (i) {
02918             case 0: ds->year = n; break;
02919             case 1: ds->month = n; break;
02920             case 2: ds->day = n; break;
02921             }
02922             ++i;
02923             if (*q) {
02924                 ++q;
02925             }
02926         } else {
02927             i = 0;
02928             while (*q && !ISDIGIT(*q)) {
02929                 ++q;
02930             }
02931         }
02932         p = q;
02933     }
02934 done:
02935     /* final check for overflow */
02936     if (err ||
02937         ds->month < 1 || ds->month > 12 ||
02938         ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
02939         if (sepc == '/') {
02940             /* Try MM/DD/YYYY format */
02941             int t[3];
02942 
02943             t[0] = ds->year;
02944             t[1] = ds->month;
02945             t[2] = ds->day;
02946             ds->year = t[2];
02947             ds->day = t[1];
02948             ds->month = t[0];
02949             if (ds->month >= 1 && ds->month <= 12 &&
02950                 (ds->day >= 1 || ds->day <= getmdays(ds->year, ds->month))) {
02951                 return 0;
02952             }
02953         }
02954         return -1;
02955     }
02956     return 0;
02957 }
02958 
02973 static int
02974 str2time(int jdconv, char *str, TIME_STRUCT *ts)
02975 {
02976     int i, err = 0, ampm = -1;
02977     double jd;
02978     char *p, *q;
02979 
02980     ts->hour = ts->minute = ts->second = 0;
02981     if (jdconv) {
02982         p = strchr(str, '.');
02983         if (p) {
02984             /* julian day format */
02985             p = 0;
02986             jd = ln_strtod(str, &p);
02987             if (p && p > str) {
02988                 convJD2HMS(jd, ts, 0);
02989                 return 0;
02990             }
02991         }
02992     }
02993     p = str;
02994     while (*p && !ISDIGIT(*p)) {
02995         ++p;
02996     }
02997     q = p;
02998     i = 0;
02999     while (*q && ISDIGIT(*q)) {
03000         ++i;
03001         ++q;
03002     }
03003     if (i >= 6) {
03004         char buf[4];
03005 
03006         strncpy(buf, p + 0, 2); buf[2] = '\0';
03007         ts->hour = strtol(buf, NULL, 10);
03008         strncpy(buf, p + 2, 2); buf[2] = '\0';
03009         ts->minute = strtol(buf, NULL, 10);
03010         strncpy(buf, p + 4, 2); buf[2] = '\0';
03011         ts->second = strtol(buf, NULL, 10);
03012         goto done;
03013     }
03014     i = 0;
03015     while (i < 3) {
03016         int n;
03017 
03018         q = NULL; 
03019         n = strtol(p, &q, 10);
03020         if (!q || q == p) {
03021             if (*q == '\0') {
03022                 if (i == 0) {
03023                     err = 1;
03024                 }
03025                 goto done;
03026             }
03027         }
03028         if (*q == ':' || *q == '\0' || i == 2) {
03029             switch (i) {
03030             case 0: ts->hour = n; break;
03031             case 1: ts->minute = n; break;
03032             case 2: ts->second = n; break;
03033             }
03034             ++i;
03035             if (*q) {
03036                 ++q;
03037             }
03038         } else {
03039             i = 0;
03040             while (*q && !ISDIGIT(*q)) {
03041                 ++q;
03042             }
03043         }
03044         p = q;
03045     }
03046     if (!err) {
03047         while (*p) {
03048             if ((p[0] == 'p' || p[0] == 'P') &&
03049                 (p[1] == 'm' || p[1] == 'M')) {
03050                 ampm = 1;
03051             } else if ((p[0] == 'a' || p[0] == 'A') &&
03052                 (p[1] == 'm' || p[1] == 'M')) {
03053                 ampm = 0;
03054             }
03055             ++p;
03056         }
03057         if (ampm > 0) {
03058             if (ts->hour < 12) {
03059                 ts->hour += 12;
03060             }
03061         } else if (ampm == 0) {
03062             if (ts->hour == 12) {
03063                 ts->hour = 0;
03064             }
03065         }
03066     }
03067 done:
03068     /* final check for overflow */
03069     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
03070         return -1;
03071     }
03072     return 0;
03073 }
03074 
03094 static int
03095 str2timestamp(int jdconv, char *str, TIMESTAMP_STRUCT *tss)
03096 {
03097     int i, m, n, err = 0, ampm = -1;
03098     double jd;
03099     char *p, *q, in = '\0', sepc = '\0';
03100 
03101     tss->year = tss->month = tss->day = 0;
03102     tss->hour = tss->minute = tss->second = 0;
03103     tss->fraction = 0;
03104     if (jdconv) {
03105         p = strchr(str, '.');
03106         if (p) {
03107             q = strchr(str, '-');
03108             if (q == str) {
03109                 q = 0;
03110             }
03111             if (!q) {
03112                 q = strchr(str, '/');
03113                 if (!q) {
03114                     q = strchr(str, ':');
03115                 }
03116             }
03117             if (!q || q > p) {
03118                 /* julian day format */
03119                 p = 0;
03120                 jd = ln_strtod(str, &p);
03121                 if (p && p > str) {
03122                     DATE_STRUCT ds;
03123                     TIME_STRUCT ts;
03124 
03125                     convJD2YMD(jd, &ds);
03126                     convJD2HMS(jd, &ts, &n);
03127                     tss->year = ds.year;
03128                     tss->month = ds.month;
03129                     tss->day = ds.day;
03130                     tss->hour = ts.hour;
03131                     tss->minute = ts.minute;
03132                     tss->second = ts.second;
03133                     tss->fraction = n;
03134                     return 0;
03135                 }
03136             }
03137         }
03138     }
03139     p = str;
03140     while (*p && !ISDIGIT(*p)) {
03141         ++p;
03142     }
03143     q = p;
03144     i = 0;
03145     while (*q && ISDIGIT(*q)) {
03146         ++i;
03147         ++q;
03148     }
03149     if (i >= 14) {
03150         char buf[16];
03151 
03152         strncpy(buf, p + 0, 4); buf[4] = '\0';
03153         tss->year = strtol(buf, NULL, 10);
03154         strncpy(buf, p + 4, 2); buf[2] = '\0';
03155         tss->month = strtol(buf, NULL, 10);
03156         strncpy(buf, p + 6, 2); buf[2] = '\0';
03157         tss->day = strtol(buf, NULL, 10);
03158         strncpy(buf, p + 8, 2); buf[2] = '\0';
03159         tss->hour = strtol(buf, NULL, 10);
03160         strncpy(buf, p + 10, 2); buf[2] = '\0';
03161         tss->minute = strtol(buf, NULL, 10);
03162         strncpy(buf, p + 12, 2); buf[2] = '\0';
03163         tss->second = strtol(buf, NULL, 10);
03164         if (i > 14) {
03165             m = i - 14;
03166             strncpy(buf, p + 14, m);
03167             while (m < 9) {
03168                 buf[m] = '0';
03169                 ++m;
03170             }
03171             buf[m] = '\0';
03172             tss->fraction = strtol(buf, NULL, 10);
03173         }
03174         m = 7;
03175         goto done;
03176     }
03177     m = i = 0;
03178     while ((m & 7) != 7) {
03179         q = NULL; 
03180         n = strtol(p, &q, 10);
03181         if (!q || q == p) {
03182             if (*q == '\0') {
03183                 if (m < 1) {
03184                     err = 1;
03185                 }
03186                 goto done;
03187             }
03188         }
03189         if (in == '\0') {
03190             switch (*q) {
03191             case '-':
03192             case '/':
03193                 if ((m & 1) == 0) {
03194                     in = *q;
03195                     i = 0;
03196                 }
03197                 break;
03198             case ':':
03199                 if ((m & 2) == 0) {
03200                     in = *q;
03201                     i = 0;
03202                 }
03203                 break;
03204             case ' ':
03205             case '.':
03206                 break;
03207             default:
03208                 in = '\0';
03209                 i = 0;
03210                 break;
03211             }
03212         }
03213         switch (in) {
03214         case '-':
03215         case '/':
03216             if (!sepc) {
03217                 sepc = in;
03218             }
03219             switch (i) {
03220             case 0: tss->year = n; break;
03221             case 1: tss->month = n; break;
03222             case 2: tss->day = n; break;
03223             }
03224             if (++i >= 3) {
03225                 i = 0;
03226                 m |= 1;
03227                 if (!(m & 2)) {
03228                     m |= 8;
03229                 }
03230                 goto skip;
03231             } else {
03232                 ++q;
03233             }
03234             break;
03235         case ':':
03236             switch (i) {
03237             case 0: tss->hour = n; break;
03238             case 1: tss->minute = n; break;
03239             case 2: tss->second = n; break;
03240             }
03241             if (++i >= 3) {
03242                 i = 0;
03243                 m |= 2;
03244                 if (*q == '.') {
03245                     in = '.';
03246                     goto skip2;
03247                 }
03248                 if (*q == ' ') {
03249                     if ((m & 1) == 0) {
03250                         char *e = NULL;
03251 
03252                         (void) strtol(q + 1, &e, 10);
03253                         if (e && *e == '-') {
03254                             goto skip;
03255                         }
03256                     }
03257                     in = '.';
03258                     goto skip2;
03259                 }
03260                 goto skip;
03261             } else {
03262                 ++q;
03263             }
03264             break;
03265         case '.':
03266             if (++i >= 1) {
03267                 int ndig = q - p;
03268 
03269                 if (p[0] == '+' || p[0] == '-') {
03270                     ndig--;
03271                 }
03272                 while (ndig < 9) {
03273                     n = n * 10;
03274                     ++ndig;
03275                 }
03276                 tss->fraction = n;
03277                 m |= 4;
03278                 i = 0;
03279             }
03280         default:
03281         skip:
03282             in = '\0';
03283         skip2:
03284             while (*q && !ISDIGIT(*q)) {
03285                 if ((q[0] == 'a' || q[0] == 'A') &&
03286                     (q[1] == 'm' || q[1] == 'M')) {
03287                     ampm = 0;
03288                     ++q;
03289                 } else if ((q[0] == 'p' || q[0] == 'P') &&
03290                            (q[1] == 'm' || q[1] == 'M')) {
03291                     ampm = 1;
03292                     ++q;
03293                 }
03294                 ++q;
03295             }
03296         }
03297         p = q;
03298     }
03299     if ((m & 7) > 1 && (m & 8)) {
03300         /* ISO8601 timezone */
03301         if (p > str && ISDIGIT(*p)) {
03302             int nn, sign;
03303 
03304             q = p - 1;
03305             if (*q != '+' && *q != '-') {
03306                 goto done;
03307             }
03308             sign = (*q == '+') ? -1 : 1;
03309             q = NULL;
03310             n = strtol(p, &q, 10);
03311             if (!q || *q++ != ':' || !ISDIGIT(*q)) {
03312                 goto done;
03313             }
03314             p = q;
03315             q = NULL;
03316             nn = strtol(p, &q, 10);
03317             tss->minute += nn * sign;
03318             if ((SQLSMALLINT) tss->minute < 0) {
03319                 tss->hour -= 1;
03320                 tss->minute += 60;
03321             } else if (tss->minute >= 60) {
03322                 tss->hour += 1;
03323                 tss->minute -= 60;
03324             }
03325             tss->hour += n * sign;
03326             if ((SQLSMALLINT) tss->hour < 0) {
03327                 tss->day -= 1;
03328                 tss->hour += 24;
03329             } else if (tss->hour >= 24) {
03330                 tss->day += 1;
03331                 tss->hour -= 24;
03332             }
03333             if ((short) tss->day < 1 || tss->day >= 28) {
03334                 int mday, pday, pmon;
03335 
03336                 mday = getmdays(tss->year, tss->month);
03337                 pmon = tss->month - 1;
03338                 if (pmon < 1) {
03339                     pmon = 12;
03340                 }
03341                 pday = getmdays(tss->year, pmon);
03342                 if ((SQLSMALLINT) tss->day < 1) {
03343                     tss->month -= 1;
03344                     tss->day = pday;
03345                 } else if (tss->day > mday) {
03346                     tss->month += 1;
03347                     tss->day = 1;
03348                 }
03349                 if ((SQLSMALLINT) tss->month < 1) {
03350                     tss->year -= 1;
03351                     tss->month = 12;
03352                 } else if (tss->month > 12) {
03353                     tss->year += 1;
03354                     tss->month = 1;
03355                 }
03356             }
03357         }
03358     }
03359 done:
03360     if ((m & 1) &&
03361         (tss->month < 1 || tss->month > 12 ||
03362          tss->day < 1 || tss->day > getmdays(tss->year, tss->month))) {
03363         if (sepc == '/') {
03364             /* Try MM/DD/YYYY format */
03365             int t[3];
03366 
03367             t[0] = tss->year;
03368             t[1] = tss->month;
03369             t[2] = tss->day;
03370             tss->year = t[2];
03371             tss->day = t[1];
03372             tss->month = t[0];
03373         }
03374     }
03375     /* Replace missing year/month/day with current date */
03376     if (!err && (m & 1) == 0) {
03377 #ifdef _WIN32
03378         SYSTEMTIME t;
03379 
03380         GetLocalTime(&t);
03381         tss->year = t.wYear;
03382         tss->month = t.wMonth;
03383         tss->day = t.wDay;
03384 #else
03385         struct timeval tv;
03386         struct tm tm;
03387 
03388         gettimeofday(&tv, NULL);
03389         tm = *localtime(&tv.tv_sec);
03390         tss->year = tm.tm_year + 1900;
03391         tss->month = tm.tm_mon + 1;
03392         tss->day = tm.tm_mday;
03393 #endif
03394     }
03395     /* Normalize fraction */
03396     if (tss->fraction < 0) {
03397         tss->fraction = 0;
03398     }
03399     /* Final check for overflow */
03400     if (err ||
03401         tss->month < 1 || tss->month > 12 ||
03402         tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
03403         tss->hour > 23 || tss->minute > 59 || tss->second > 59) {
03404         return -1;
03405     }
03406     if ((m & 7) > 1) {
03407         if (ampm > 0) {
03408             if (tss->hour < 12) {
03409                 tss->hour += 12;
03410             }
03411         } else if (ampm == 0) {
03412             if (tss->hour == 12) {
03413                 tss->hour = 0;
03414             }
03415         }
03416     }
03417     return ((m & 7) < 1) ? -1 : 0;
03418 }
03419 
03426 static int
03427 getbool(char *string)
03428 {
03429     if (string) {
03430         return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
03431     }
03432     return 0;
03433 }
03434 
03442 static void
03443 blob_import(sqlite3_context *ctx, int nargs, sqlite3_value **args)
03444 {
03445 #if 0
03446     DBC *d = (DBC *) sqlite3_user_data(ctx);
03447 #endif
03448     char *filename = 0;
03449 
03450     if (nargs > 0) {
03451         if (sqlite3_value_type(args[0]) != SQLITE_NULL) {
03452             filename = (char *) sqlite3_value_text(args[0]);
03453         }
03454     }
03455     if (filename) {
03456 #ifdef _WIN32
03457         char *wname = utf_to_wmb(filename, -1);
03458         FILE *f;
03459 #else
03460         FILE *f = fopen(filename, "r");
03461 #endif
03462         char *p;
03463         long n, nn;
03464 
03465 #ifdef _WIN32
03466         if (wname) {
03467             f = fopen(wname, "rb");
03468         } else {
03469             sqlite3_result_error(ctx, "out of memory", -1);
03470             return;
03471         }
03472         uc_free(wname);
03473 #endif
03474         if (f) {
03475             if (fseek(f, 0, SEEK_END) == 0) {
03476                 n = ftell(f);
03477                 if (fseek(f, 0, SEEK_SET) == 0) {
03478                     p = sqlite3_malloc(n);
03479                     if (p) {
03480                         nn = fread(p, 1, n, f);
03481                         if (nn != n) {
03482                             sqlite3_result_error(ctx, "read error", -1);
03483                             sqlite3_free(p);
03484                         } else {
03485                             sqlite3_result_blob(ctx, p, n, sqlite3_free);
03486                         }
03487                     } else {
03488                         sqlite3_result_error(ctx, "out of memory", -1);
03489                     }
03490                 } else {
03491                     sqlite3_result_error(ctx, "seek error", -1);
03492                 }
03493             } else {
03494                 sqlite3_result_error(ctx, "seek error", -1);
03495             }
03496             fclose(f);
03497         } else {
03498             sqlite3_result_error(ctx, "cannot open file", -1);
03499         }
03500     } else {
03501         sqlite3_result_error(ctx, "no filename given", -1);
03502     }
03503 }
03504 
03512 static void
03513 blob_export(sqlite3_context *ctx, int nargs, sqlite3_value **args)
03514 {
03515 #if 0
03516     DBC *d = (DBC *) sqlite3_user_data(ctx);
03517 #endif
03518     char *filename = 0;
03519     char *p = 0;
03520     int n = 0;
03521 
03522     if (nargs > 0) {
03523         p = (char *) sqlite3_value_blob(args[0]);
03524         n = sqlite3_value_bytes(args[0]);
03525     }
03526     if (nargs > 1) {
03527         if (sqlite3_value_type(args[1]) != SQLITE_NULL) {
03528             filename = (char *) sqlite3_value_text(args[1]);
03529         }
03530     }
03531     if (p) {
03532         if (filename) {
03533 #ifdef _WIN32
03534             char *wname = utf_to_wmb(filename, -1);
03535             FILE *f;
03536 #else
03537             FILE *f = fopen(filename, "w");
03538 #endif
03539             int nn;
03540 
03541 #ifdef _WIN32
03542             if (wname) {
03543                 f = fopen(wname, "wb");
03544             } else {
03545                 sqlite3_result_error(ctx, "out of memory", -1);
03546                 return;
03547             }
03548             uc_free(wname);
03549 #endif
03550             if (f) {
03551                 nn = fwrite(p, 1, n, f);
03552                 fclose(f);
03553                 if (nn != n) {
03554                     sqlite3_result_error(ctx, "write error", -1);
03555                 } else {
03556                     sqlite3_result_int(ctx, nn);
03557                 }
03558             } else {
03559                 sqlite3_result_error(ctx, "cannot open file", -1);
03560             }
03561         } else {
03562             sqlite3_result_error(ctx, "no filename given", -1);
03563         }
03564     } else {
03565         sqlite3_result_null(ctx);
03566     }
03567 }
03568 
03576 static void
03577 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
03578 dbtrace(void *arg, const char *msg, sqlite_uint64 et)
03579 #else
03580 dbtrace(void *arg, const char *msg)
03581 #endif
03582 {
03583     DBC *d = (DBC *) arg;
03584 
03585     if (msg && d->trace) {
03586         int len = strlen(msg);
03587 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
03588         unsigned long s, f;
03589 #endif
03590 
03591         if (len > 0) {
03592             char *end = "\n";
03593 
03594             if (msg[len - 1] != ';') {
03595                 end = ";\n";
03596             }
03597             fprintf(d->trace, "%s%s", msg, end);
03598 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
03599             s = et / 1000000000LL;
03600             f = et % 1000000000LL;
03601             fprintf(d->trace, "-- took %lu.%09lu seconds\n", s, f);
03602 #endif
03603             fflush(d->trace);
03604         }
03605     }
03606 }
03607 
03615 static void
03616 dbtraceapi(DBC *d, char *fn, const char *sql)
03617 {
03618     if (fn && d->trace) {
03619         if (sql) {
03620             fprintf(d->trace, "-- %s: %s\n", fn, sql);
03621         } else {
03622             fprintf(d->trace, "-- %s\n", fn);
03623         }
03624         fflush(d->trace);
03625     }
03626 }
03627 
03635 static void
03636 dbtracerc(DBC *d, int rc, char *err)
03637 {
03638     if (rc != SQLITE_OK && d->trace) {
03639         fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
03640         fprintf(d->trace, err ? ": %s\n" : "\n", err);
03641         fflush(d->trace);
03642     }
03643 }
03644 
03659 static SQLRETURN
03660 dbopen(DBC *d, char *name, int isu, char *dsn, char *sflag,
03661        char *spflag, char *ntflag, char *jmode, char *busy)
03662 {
03663     char *endp = NULL;
03664     int rc, tmp, busyto = 100000;
03665 #if defined(HAVE_SQLITE3VFS) && (HAVE_SQLITE3VFS)
03666     int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
03667     char *uname = name;
03668     const char *vfs_name = NULL;
03669 #endif
03670 
03671     if (d->sqlite) {
03672         if (d->trace) {
03673             fprintf(d->trace, "-- sqlite3_close (deferred): '%s'\n",
03674                     d->dbname);
03675             fflush(d->trace);
03676         }
03677         sqlite3_close(d->sqlite);
03678         d->sqlite = NULL;
03679     }
03680 #if defined(HAVE_SQLITE3VFS) && (HAVE_SQLITE3VFS)
03681     if (d->nocreat) {
03682         flags &= ~ SQLITE_OPEN_CREATE;
03683     }
03684 #if defined(_WIN32) || defined(_WIN64)
03685     if (!isu) {
03686         char expname[MAX_PATH];
03687 
03688         expname[0] = '\0';
03689         rc = ExpandEnvironmentStrings(name, expname, sizeof (expname));
03690         if (rc <= sizeof (expname)) {
03691             uname = wmb_to_utf(expname, rc - 1);
03692         } else {
03693             uname = wmb_to_utf(name, -1);
03694         }
03695         if (!uname) {
03696             rc = SQLITE_NOMEM;
03697             setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
03698             return SQL_ERROR;
03699         }
03700     }
03701 #endif
03702 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
03703     vfs_name = nvfs_makevfs(uname);
03704 #endif
03705 #ifdef SQLITE_OPEN_URI
03706     flags |= SQLITE_OPEN_URI;
03707 #endif
03708     rc = sqlite3_open_v2(uname, &d->sqlite, flags, vfs_name);
03709 #if defined(WINTERFACE) || defined(_WIN32) || defined(_WIN64)
03710     if (uname != name) {
03711         uc_free(uname);
03712     }
03713 #endif
03714 #else
03715 #if defined(_WIN32) || defined(_WIN64)
03716     if (d->nocreat) {
03717         char *cname = NULL;
03718 
03719         if (isu) {
03720             cname = utf_to_wmb(name, -1);
03721         }
03722         if (GetFileAttributesA(cname ? cname : name) ==
03723             INVALID_FILE_ATTRIBUTES) {
03724             uc_free(cname);
03725             rc = SQLITE_CANTOPEN;
03726             setstatd(d, rc, "cannot open database",
03727                      (*d->ov3) ? "HY000" : "S1000");
03728             return SQL_ERROR;
03729         }
03730         uc_free(cname);
03731     }
03732 #else
03733     if (d->nocreat && access(name, 004) < 0) {
03734         rc = SQLITE_CANTOPEN;
03735         setstatd(d, rc, "cannot open database", (*d->ov3) ? "HY000" : "S1000");
03736         return SQL_ERROR;
03737     }
03738 #endif
03739 #if defined(_WIN32) || defined(_WIN64)
03740     if (!isu) {
03741         WCHAR *wname = wmb_to_uc(name, -1);
03742 
03743         if (!wname) {
03744             rc = SQLITE_NOMEM;
03745             setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
03746             return SQL_ERROR;
03747         }
03748         rc = sqlite3_open16(wname, &d->sqlite);
03749         uc_free(wname);
03750     } else
03751 #endif
03752     rc = sqlite3_open(name, &d->sqlite);
03753 #endif /* !HAVE_SQLITE3VFS */
03754     if (rc != SQLITE_OK) {
03755 connfail:
03756         setstatd(d, rc, "connect failed", (*d->ov3) ? "HY000" : "S1000");
03757         if (d->sqlite) {
03758             sqlite3_close(d->sqlite);
03759             d->sqlite = NULL;
03760         }
03761         return SQL_ERROR;
03762     }
03763 #if defined(SQLITE_DYNLOAD) || defined(SQLITE_HAS_CODEC)
03764     if (d->pwd) {
03765         sqlite3_key(d->sqlite, d->pwd, d->pwdLen);
03766     }
03767 #endif
03768     d->pwd = NULL;
03769     d->pwdLen = 0;
03770     if (d->trace) {
03771 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
03772         sqlite3_profile(d->sqlite, dbtrace, d);
03773 #else
03774         sqlite3_trace(d->sqlite, dbtrace, d);
03775 #endif
03776     }
03777     d->step_enable = getbool(sflag);
03778     d->trans_disable = getbool(ntflag);
03779     d->curtype = d->step_enable ?
03780         SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
03781     tmp = strtol(busy, &endp, 0);
03782     if (endp && *endp == '\0' && endp != busy) {
03783         busyto = tmp;
03784     }
03785     if (busyto < 1 || busyto > 1000000) {
03786         busyto = 1000000;
03787     }
03788     d->timeout = busyto;
03789     freep(&d->dbname);
03790     d->dbname = xstrdup(name);
03791     freep(&d->dsn);
03792     d->dsn = xstrdup(dsn);
03793     if ((rc = setsqliteopts(d->sqlite, d)) != SQLITE_OK) {
03794         if (d->trace) {
03795             fprintf(d->trace, "-- sqlite3_close: '%s'\n",
03796                     d->dbname);
03797             fflush(d->trace);
03798         }
03799         sqlite3_close(d->sqlite);
03800         d->sqlite = NULL;
03801         goto connfail;
03802     }
03803     if (!spflag || spflag[0] == '\0') {
03804         spflag = "NORMAL";
03805     }
03806     if (spflag[0] != '\0') {
03807         char syncp[128];
03808 
03809         sprintf(syncp, "PRAGMA synchronous = %8.8s;", spflag);
03810         sqlite3_exec(d->sqlite, syncp, NULL, NULL, NULL);
03811     }
03812     if (jmode[0] != '\0') {
03813         char jourp[128];
03814 
03815         sprintf(jourp, "PRAGMA journal_mode = %16.16s;", jmode);
03816         sqlite3_exec(d->sqlite, jourp, NULL, NULL, NULL);
03817     }
03818     if (d->trace) {
03819         fprintf(d->trace, "-- sqlite3_open: '%s'\n", d->dbname);
03820         fflush(d->trace);
03821     }
03822 #if defined(_WIN32) || defined(_WIN64)
03823     {
03824         char pname[MAX_PATH];
03825         HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
03826                                FALSE, GetCurrentProcessId());
03827 
03828         pname[0] = '\0';
03829         if (h) {
03830             HMODULE m = NULL, l = LoadLibrary("psapi.dll");
03831             DWORD need;
03832             typedef BOOL (WINAPI *epmfunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
03833             typedef BOOL (WINAPI *gmbfunc)(HANDLE, HMODULE, LPSTR, DWORD);
03834             epmfunc epm;
03835             gmbfunc gmb;
03836 
03837             if (l) {
03838                 epm = (epmfunc) GetProcAddress(l, "EnumProcessModules");
03839                 gmb = (gmbfunc) GetProcAddress(l, "GetModuleBaseNameA");
03840                 if (epm && gmb && epm(h, &m, sizeof (m), &need)) {
03841                     gmb(h, m, pname, sizeof (pname));
03842                 }
03843                 FreeLibrary(l);
03844             }
03845             CloseHandle(h);
03846         }
03847         d->xcelqrx = strncasecmp(pname, "EXCEL", 5) == 0 ||
03848                      strncasecmp(pname, "MSQRY", 5) == 0;
03849         if (d->trace && d->xcelqrx) {
03850             fprintf(d->trace, "-- enabled EXCEL quirks\n");
03851             fflush(d->trace);
03852         }
03853     }
03854 #endif
03855     sqlite3_create_function(d->sqlite, "blob_import", 1, SQLITE_UTF8,
03856                             d, blob_import, 0, 0);
03857     sqlite3_create_function(d->sqlite, "blob_export", 2, SQLITE_UTF8,
03858                             d, blob_export, 0, 0);
03859     return SQL_SUCCESS;
03860 }
03861 
03868 static void
03869 dbloadext(DBC *d, char *exts)
03870 {
03871 #if defined(HAVE_SQLITE3LOADEXTENSION) && (HAVE_SQLITE3LOADEXTENSION)
03872     char *p;
03873     char path[SQL_MAX_MESSAGE_LENGTH];
03874     int plen = 0;
03875 
03876     if (!d->sqlite) {
03877         return;
03878     }
03879     sqlite3_enable_load_extension(d->sqlite, 1);
03880 #if defined(_WIN32) || defined(_WIN64)
03881     GetModuleFileName(hModule, path, sizeof (path));
03882     p = strrchr(path, '\\');
03883     plen = p ? ((p + 1) - path) : 0;
03884 #endif
03885     do {
03886         p = strchr(exts, ',');
03887         if (p) {
03888             strncpy(path + plen, exts, p - exts);
03889             path[plen + (p - exts)] = '\0';
03890         } else {
03891             strcpy(path + plen, exts);
03892         }
03893         if (exts[0]) {
03894             char *errmsg = NULL;
03895             int rc;
03896 #if defined(_WIN32) || defined(_WIN64)
03897             char *q;
03898 
03899             q = path + plen;
03900             if (!(q[0] &&
03901                   ((q[1] == ':' && (q[2] == '\\' || q[2] == '/')) ||
03902                    q[0] == '\\' || q[0] == '/' || q[0] == '.'))) {
03903                 q = path;
03904             }
03905             rc = sqlite3_load_extension(d->sqlite, q, 0, &errmsg);
03906 #else
03907             rc = sqlite3_load_extension(d->sqlite, path, 0, &errmsg);
03908 #endif
03909             if (rc != SQLITE_OK) {
03910 #if defined(_WIN32) || defined(_WIN64)
03911                 char buf[512], msg[512];
03912 
03913                 LoadString(hModule, IDS_EXTERR, buf, sizeof (buf));
03914                 wsprintf(msg, buf, q, errmsg ?
03915                          errmsg : "no error info available");
03916                 LoadString(hModule, IDS_EXTTITLE, buf, sizeof (buf));
03917                 MessageBox(NULL, msg, buf,
03918                            MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
03919                            MB_SETFOREGROUND);
03920 #else
03921                 fprintf(stderr, "extension '%s' did not load%s%s\n",
03922                         path, errmsg ? ": " : "", errmsg ? errmsg : "");
03923 #endif
03924             }
03925         }
03926         if (p) {
03927             exts = p + 1;
03928         }
03929     } while (p);
03930 #endif /* HAVE_SQLITE3LOADEXTENSION */
03931 }
03932 
03942 static char *
03943 s3stmt_coltype(sqlite3_stmt *s3stmt, int col, DBC *d, int *guessed_types)
03944 {
03945     char *typename = (char *) sqlite3_column_decltype(s3stmt, col);
03946     char guess[64];
03947 
03948     guess[0] = '\0';
03949     if (!typename) {
03950         int coltype = sqlite3_column_type(s3stmt, col);
03951 
03952         if (guessed_types) {
03953             guessed_types[0]++;
03954         }
03955         if (d->trace) {
03956             sprintf(guess, " (guessed from %d)", coltype);
03957         }
03958         switch (coltype) {
03959         case SQLITE_INTEGER: typename = "integer"; break;
03960         case SQLITE_FLOAT:   typename = "double";  break;
03961         default:
03962         case SQLITE_TEXT:    typename = "varchar"; break;
03963         case SQLITE_BLOB:    typename = "blob";    break;
03964 #if 0
03965         case SQLITE_NULL:    typename = "null";    break;
03966 #endif
03967         }
03968     }
03969     if (d->trace) {
03970         fprintf(d->trace, "-- column %d type%s: '%s'\n", col + 1,
03971                 guess, typename);
03972         fflush(d->trace);
03973     }
03974     return typename;
03975 }
03976 
03977 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && (HAVE_SQLITE3TABLECOLUMNMETADATA)
03978 
03987 static void
03988 s3stmt_addmeta(sqlite3_stmt *s3stmt, int col, DBC *d, COL *ci)
03989 {
03990     int nn = 0, pk = 0, ai = 0;
03991     const char *dn, *tn, *cn, *dummy1, *dummy2;
03992 
03993     dn = sqlite3_column_database_name(s3stmt, col);
03994     tn = sqlite3_column_table_name(s3stmt, col);
03995     cn = sqlite3_column_origin_name(s3stmt, col);
03996     sqlite3_table_column_metadata(d->sqlite, dn, tn, cn,
03997                                   &dummy1, &dummy2,
03998                                   &nn, &pk, &ai);
03999     ci->autoinc = ai ? SQL_TRUE: SQL_FALSE;
04000     ci->notnull = nn ? SQL_NO_NULLS : SQL_NULLABLE;
04001     if (d->trace) {
04002         fprintf(d->trace, "-- column %d %s\n",
04003                 col + 1, nn ? "notnull" : "nullable");
04004         if (ai) {
04005             fprintf(d->trace, "-- column %d autoincrement\n", col + 1);
04006         }
04007         fflush(d->trace);
04008     }
04009 }
04010 
04011 #endif
04012 
04019 static int
04020 s3stmt_step(STMT *s)
04021 {
04022     DBC *d = (DBC *) s->dbc;
04023     char **rowd = NULL;
04024     const char *errp = NULL;
04025     int i, ncols, rc;
04026 
04027     if (s != d->cur_s3stmt || !s->s3stmt) {
04028         setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
04029         return SQL_ERROR;
04030     }
04031     rc = sqlite3_step(s->s3stmt);
04032     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
04033         ++s->s3stmt_rownum;
04034         ncols = sqlite3_column_count(s->s3stmt);
04035         if (d->s3stmt_needmeta && s->s3stmt_rownum == 0 && ncols > 0) {
04036             PTRDIFF_T size;
04037             char *p;
04038             COL *dyncols;
04039             const char *colname, *typename;
04040 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
04041             char *tblname;
04042 #endif
04043 
04044             for (i = size = 0; i < ncols; i++) {
04045                 colname = sqlite3_column_name(s->s3stmt, i);
04046                 size += 3 + 3 * strlen(colname);
04047             }
04048 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
04049             tblname = (char *) size;
04050             for (i = 0; i < ncols; i++) {
04051                 p = (char *) sqlite3_column_table_name(s->s3stmt, i);
04052                 size += 2 + (p ? strlen(p) : 0);
04053             }
04054 #endif
04055             dyncols = xmalloc(ncols * sizeof (COL) + size);
04056             if (!dyncols) {
04057                 freedyncols(s);
04058                 s->ncols = 0;
04059                 dbtraceapi(d, "sqlite3_finalize", 0);
04060                 sqlite3_finalize(s->s3stmt);
04061                 s->s3stmt = NULL;
04062                 d->cur_s3stmt = NULL;
04063                 return nomem(s);
04064             }
04065             p = (char *) (dyncols + ncols);
04066 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
04067             tblname = p + (PTRDIFF_T) tblname;    
04068 #endif
04069             for (i = 0; i < ncols; i++) {
04070                 char *q;
04071 
04072                 colname = sqlite3_column_name(s->s3stmt, i);
04073                 if (d->trace) {
04074                     fprintf(d->trace, "-- column %d name: '%s'\n",
04075                             i + 1, colname);
04076                     fflush(d->trace);
04077                 }
04078 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
04079                 q = (char *) sqlite3_column_table_name(s->s3stmt, i);
04080                 strcpy(tblname, q ? q : "");
04081                 if (d->trace) {
04082                     fprintf(d->trace, "-- table %d name: '%s'\n",
04083                             i + 1, tblname);
04084                     fflush(d->trace);
04085                 }
04086                 dyncols[i].table = tblname;
04087                 tblname += strlen(tblname) + 1;
04088 #endif
04089                 typename = s3stmt_coltype(s->s3stmt, i, d, 0);
04090                 dyncols[i].db = ((DBC *) (s->dbc))->dbname;
04091                 strcpy(p, colname);
04092                 dyncols[i].label = p;
04093                 p += strlen(p) + 1;
04094                 q = strchr(colname, '.');
04095                 if (q) {
04096                     char *q2 = strchr(q + 1, '.');
04097 
04098                     /* SQLite 3.3.4 produces view.table.column sometimes */
04099                     if (q2) {
04100                         q = q2;
04101                     }
04102                 }
04103                 if (q) {
04104 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
04105                     dyncols[i].table = p;
04106 #endif
04107                     strncpy(p, colname, q - colname);
04108                     p[q - colname] = '\0';
04109                     p += strlen(p) + 1;
04110                     strcpy(p, q + 1);
04111                     dyncols[i].column = p;
04112                     p += strlen(p) + 1;
04113                 } else {
04114 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
04115                     dyncols[i].table = "";
04116 #endif
04117                     strcpy(p, colname);
04118                     dyncols[i].column = p;
04119                     p += strlen(p) + 1;
04120                 }
04121                 if (s->longnames) {
04122                     dyncols[i].column = dyncols[i].label;
04123                 }
04124 #ifdef SQL_LONGVARCHAR
04125                 dyncols[i].type = SQL_LONGVARCHAR;
04126                 dyncols[i].size = 65535;
04127 #else
04128                 dyncols[i].type = SQL_VARCHAR;
04129                 dyncols[i].size = 255;
04130 #endif
04131                 dyncols[i].index = i;
04132                 dyncols[i].scale = 0;
04133                 dyncols[i].prec = 0;
04134                 dyncols[i].nosign = 1;
04135 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && (HAVE_SQLITE3TABLECOLUMNMETADATA)
04136                 s3stmt_addmeta(s->s3stmt, i, d, &dyncols[i]);
04137 #else
04138                 dyncols[i].autoinc = SQL_FALSE;
04139                 dyncols[i].notnull = SQL_NULLABLE;
04140 #endif
04141                 dyncols[i].typename = xstrdup(typename);
04142             }
04143             freedyncols(s);
04144             s->ncols = s->dcols = ncols;
04145             s->dyncols = s->cols = dyncols;
04146             fixupdyncols(s, d);
04147             mkbindcols(s, s->ncols);
04148             d->s3stmt_needmeta = 0;
04149         }
04150         if (ncols <= 0) {
04151             goto killstmt;
04152         }
04153         if (rc == SQLITE_DONE) {
04154             freeresult(s, 0);
04155             s->nrows = 0;
04156             dbtraceapi(d, "sqlite3_finalize", 0);
04157             sqlite3_finalize(s->s3stmt);
04158             s->s3stmt = NULL;
04159             d->cur_s3stmt = NULL;
04160             return SQL_SUCCESS;
04161         }
04162         rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
04163         if (rowd) {
04164             const unsigned char *value;
04165 
04166             rowd[0] = (char *) ((PTRDIFF_T) (ncols * 2));
04167             ++rowd;
04168             for (i = 0; i < ncols; i++) {
04169                 int coltype = sqlite3_column_type(s->s3stmt, i);
04170 
04171                 rowd[i] = rowd[i + ncols] = NULL;
04172                 if (coltype == SQLITE_BLOB) {
04173                     int k, nbytes = sqlite3_column_bytes(s->s3stmt, i);
04174                     char *qp;
04175                     unsigned const char *bp;
04176 
04177                     bp = sqlite3_column_blob(s->s3stmt, i);
04178                     qp = xmalloc(nbytes * 2 + 4);
04179                     if (qp) {
04180                         rowd[i + ncols] = qp;
04181                         *qp++ = 'X';
04182                         *qp++ = '\'';
04183                         for (k = 0; k < nbytes; k++) {
04184                             *qp++ = xdigits[(bp[k] >> 4)];
04185                             *qp++ = xdigits[(bp[k] & 0xF)];
04186                         }
04187                         *qp++ = '\'';
04188                         *qp = '\0';
04189                     }
04190 #ifdef _MSC_VER
04191                 } else if (coltype == SQLITE_FLOAT) {
04192                     static struct lconv *lc = 0;
04193                     double d = sqlite3_column_double(s->s3stmt, i);
04194                     char *p, buffer[128];
04195 
04196                     /*
04197                      * This avoids floating point rounding
04198                      * and formatting problems of some SQLite
04199                      * versions in conjunction with MSVC 2010.
04200                      */
04201                     snprintf(buffer, sizeof (buffer), "%.15g", d);
04202                     if (!lc) {
04203                         lc = localeconv();
04204                     }
04205                     if (lc && lc->decimal_point && lc->decimal_point[0] &&
04206                         lc->decimal_point[0] != '.') {
04207                         p = strchr(buffer, lc->decimal_point[0]);
04208                         if (p) {
04209                             *p = '.';
04210                         }
04211                     }
04212                     rowd[i + ncols] = xstrdup(buffer);
04213 #endif
04214                 } else if (coltype != SQLITE_NULL) {
04215                     value = sqlite3_column_text(s->s3stmt, i);
04216                     rowd[i + ncols] = xstrdup((char *) value);
04217                 }
04218             }
04219             for (i = 0; i < ncols; i++) {
04220                 int coltype = sqlite3_column_type(s->s3stmt, i);
04221 
04222                 value = NULL;
04223                 if (coltype == SQLITE_BLOB) {
04224                     value = sqlite3_column_blob(s->s3stmt, i);
04225                 } else if (coltype != SQLITE_NULL) {
04226                     value = sqlite3_column_text(s->s3stmt, i);
04227                 }
04228                 if (value && !rowd[i + ncols]) {
04229                     freerows(rowd);
04230                     rowd = 0;
04231                     break;
04232                 }
04233             }
04234         }
04235         if (rowd) {
04236             freeresult(s, 0);
04237             s->nrows = 1;
04238             s->rows = rowd;
04239             s->rowfree = freerows;
04240             if (rc == SQLITE_DONE) {
04241                 dbtraceapi(d, "sqlite3_finalize", 0);
04242                 sqlite3_finalize(s->s3stmt);
04243                 s->s3stmt = NULL;
04244                 d->cur_s3stmt = NULL;
04245             }
04246             return SQL_SUCCESS;
04247         }
04248     }
04249 killstmt:
04250     dbtraceapi(d, "sqlite3_reset", 0);
04251     rc = sqlite3_reset(s->s3stmt);
04252     s->s3stmt_noreset = 1;
04253     errp = sqlite3_errmsg(d->sqlite);
04254     if (d->cur_s3stmt == s) {
04255         d->cur_s3stmt = NULL;
04256     }
04257     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04258             errp ? errp : "unknown error", rc);
04259     return SQL_ERROR;   
04260 }
04261 
04267 static void
04268 s3stmt_end(STMT *s)
04269 {
04270     DBC *d;
04271 
04272     if (!s || !s->s3stmt) {
04273         return;
04274     }
04275     d = (DBC *) s->dbc;
04276     if (d) {
04277         d->busyint = 0;
04278     }
04279     if (!s->s3stmt_noreset) {
04280         dbtraceapi(d, "sqlite3_reset", 0);
04281         sqlite3_reset(s->s3stmt);
04282         s->s3stmt_noreset = 1;
04283         s->s3stmt_rownum = -1;
04284     }
04285     if (d->cur_s3stmt == s) {
04286         d->cur_s3stmt = NULL;
04287     }
04288 }
04289 
04295 static void
04296 s3stmt_end_if(STMT *s)
04297 {
04298     DBC *d = (DBC *) s->dbc;
04299 
04300     if (d) {
04301         d->busyint = 0;
04302     }
04303     if (d && d->cur_s3stmt == s) {
04304         s3stmt_end(s);
04305     }
04306 }
04307 
04313 static void
04314 s3stmt_drop(STMT *s)
04315 {
04316     if (s->s3stmt) {
04317         DBC *d = (DBC *) s->dbc;
04318 
04319         if (d) {
04320             dbtraceapi(d, "sqlite3_finalize", 0);
04321         }
04322         sqlite3_finalize(s->s3stmt);
04323         s->s3stmt = NULL;
04324         s->s3stmt_rownum = 0;
04325     }
04326 }
04327 
04334 static SQLRETURN
04335 s3stmt_start(STMT *s)
04336 {
04337     DBC *d = (DBC *) s->dbc;
04338     const char *endp;
04339     sqlite3_stmt *s3stmt = NULL;
04340     int rc, nretry = 0;
04341 
04342     d->s3stmt_needmeta = 0;
04343     if (!s->s3stmt) {
04344 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
04345         dbtraceapi(d, "sqlite3_prepare_v2", (char *) s->query);
04346 #else
04347         dbtraceapi(d, "sqlite3_prepare", (char *) s->query);
04348 #endif
04349         do {
04350             s3stmt = NULL;
04351 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
04352             rc = sqlite3_prepare_v2(d->sqlite, (char *) s->query, -1,
04353                                     &s3stmt, &endp);
04354 #else
04355             rc = sqlite3_prepare(d->sqlite, (char *) s->query, -1,
04356                                  &s3stmt, &endp);
04357 #endif
04358             if (rc != SQLITE_OK) {
04359                 if (s3stmt) {
04360                     sqlite3_finalize(s3stmt);
04361                     s3stmt = NULL;
04362                 }
04363             }
04364         } while (rc == SQLITE_SCHEMA && (++nretry) < 2);
04365         dbtracerc(d, rc, NULL);
04366         if (rc != SQLITE_OK) {
04367             if (s3stmt) {
04368                 dbtraceapi(d, "sqlite3_finalize", NULL);
04369                 sqlite3_finalize(s3stmt);
04370             }
04371             setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04372                     sqlite3_errmsg(d->sqlite), rc);
04373             return SQL_ERROR;
04374         }
04375         if (sqlite3_bind_parameter_count(s3stmt) != s->nparams) {
04376             dbtraceapi(d, "sqlite3_finalize", 0);
04377             sqlite3_finalize(s3stmt);
04378             setstat(s, SQLITE_ERROR, "parameter marker count incorrect",
04379                     (*s->ov3) ? "HY000" : "S1000");
04380             return SQL_ERROR;
04381         }
04382         s->s3stmt = s3stmt;
04383         s->s3stmt_noreset = 1;
04384         d->s3stmt_needmeta = 1;
04385     }
04386     d->cur_s3stmt = s;
04387     s->s3stmt_rownum = -1;
04388     s3bind(d, s->s3stmt, s->nparams, s->bindparms);
04389     return SQL_SUCCESS;
04390 }
04391 
04396 SQLRETURN SQL_API
04397 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
04398 {
04399     SQLRETURN ret;
04400 
04401     HSTMT_LOCK(stmt);
04402     ret = drvunimplstmt(stmt);
04403     HSTMT_UNLOCK(stmt);
04404     return ret;
04405 }
04406 
04407 #ifndef WINTERFACE
04408 
04412 SQLRETURN SQL_API
04413 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
04414                SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
04415                SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
04416 {
04417     if (env == SQL_NULL_HENV) {
04418         return SQL_INVALID_HANDLE;
04419     }
04420     return SQL_ERROR;
04421 }
04422 #endif
04423 
04424 #ifdef WINTERFACE
04425 
04429 SQLRETURN SQL_API
04430 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
04431                 SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
04432                 SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
04433 {
04434     if (env == SQL_NULL_HENV) {
04435         return SQL_INVALID_HANDLE;
04436     }
04437     return SQL_ERROR;
04438 }
04439 #endif
04440 
04441 #ifndef WINTERFACE
04442 
04446 SQLRETURN SQL_API
04447 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
04448            SQLSMALLINT descmax, SQLSMALLINT *desclenp,
04449            SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
04450 {
04451     if (env == SQL_NULL_HENV) {
04452         return SQL_INVALID_HANDLE;
04453     }
04454     return SQL_ERROR;
04455 }
04456 #endif
04457 
04458 #ifdef WINTERFACE
04459 
04463 SQLRETURN SQL_API
04464 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
04465             SQLSMALLINT descmax, SQLSMALLINT *desclenp,
04466             SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
04467 {
04468     if (env == SQL_NULL_HENV) {
04469         return SQL_INVALID_HANDLE;
04470     }
04471     return SQL_ERROR;
04472 }
04473 #endif
04474 
04475 #ifndef WINTERFACE
04476 
04480 SQLRETURN SQL_API
04481 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
04482                  SQLCHAR *connout, SQLSMALLINT connoutMax,
04483                  SQLSMALLINT *connoutLen)
04484 {
04485     SQLRETURN ret;
04486 
04487     HDBC_LOCK(dbc);
04488     ret = drvunimpldbc(dbc);
04489     HDBC_UNLOCK(dbc);
04490     return ret;
04491 }
04492 #endif
04493 
04494 #ifdef WINTERFACE
04495 
04499 SQLRETURN SQL_API
04500 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
04501                   SQLWCHAR *connout, SQLSMALLINT connoutMax,
04502                   SQLSMALLINT *connoutLen)
04503 {
04504     SQLRETURN ret;
04505 
04506     HDBC_LOCK(dbc);
04507     ret = drvunimpldbc(dbc);
04508     HDBC_UNLOCK(dbc);
04509     return ret;
04510 }
04511 #endif
04512 
04521 static SQLRETURN
04522 drvputdata(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
04523 {
04524     STMT *s;
04525     int i, dlen, done = 0;
04526     BINDPARM *p;
04527 
04528     if (stmt == SQL_NULL_HSTMT) {
04529         return SQL_INVALID_HANDLE;
04530     }
04531     s = (STMT *) stmt;
04532     if (!s->query || s->nparams <= 0) {
04533 seqerr:
04534         setstat(s, -1, "sequence error", "HY010");
04535         return SQL_ERROR;
04536     }
04537     for (i = (s->pdcount < 0) ? 0 : s->pdcount; i < s->nparams; i++) {
04538         p = &s->bindparms[i];
04539         if (p->need > 0) {
04540             int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
04541 
04542             if (len == SQL_NULL_DATA) {
04543                 freep(&p->parbuf);
04544                 p->param = NULL;
04545                 p->len = SQL_NULL_DATA;
04546                 p->need = -1;
04547             } else if (type != SQL_C_CHAR
04548 #ifdef WCHARSUPPORT
04549                        && type != SQL_C_WCHAR
04550 #endif
04551                        && type != SQL_C_BINARY) {
04552                 int size = 0;
04553 
04554                 switch (type) {
04555                 case SQL_C_TINYINT:
04556                 case SQL_C_UTINYINT:
04557                 case SQL_C_STINYINT:
04558 #ifdef SQL_BIT
04559                 case SQL_C_BIT:
04560 #endif
04561                     size = sizeof (SQLCHAR);
04562                     break;
04563                 case SQL_C_SHORT:
04564                 case SQL_C_USHORT:
04565                 case SQL_C_SSHORT:
04566                     size = sizeof (SQLSMALLINT);
04567                     break;
04568                 case SQL_C_LONG:
04569                 case SQL_C_ULONG:
04570                 case SQL_C_SLONG:
04571                     size = sizeof (SQLINTEGER);
04572                     break;
04573 #ifdef SQL_BIGINT
04574                 case SQL_C_UBIGINT:
04575                 case SQL_C_SBIGINT:
04576                     size = sizeof (SQLBIGINT);
04577                     break;
04578 #endif
04579                 case SQL_C_FLOAT:
04580                     size = sizeof (float);
04581                     break;
04582                 case SQL_C_DOUBLE:
04583                     size = sizeof (double);
04584                     break;
04585 #ifdef SQL_C_TYPE_DATE
04586                 case SQL_C_TYPE_DATE:
04587 #endif
04588                 case SQL_C_DATE:
04589                     size = sizeof (DATE_STRUCT);
04590                     break;
04591 #ifdef SQL_C_TYPE_DATE
04592                 case SQL_C_TYPE_TIME:
04593 #endif
04594                 case SQL_C_TIME:
04595                     size = sizeof (TIME_STRUCT);
04596                     break;
04597 #ifdef SQL_C_TYPE_DATE
04598                 case SQL_C_TYPE_TIMESTAMP:
04599 #endif
04600                 case SQL_C_TIMESTAMP:
04601                     size = sizeof (TIMESTAMP_STRUCT);
04602                     break;
04603                 }
04604                 freep(&p->parbuf);
04605                 p->parbuf = xmalloc(size);
04606                 if (!p->parbuf) {
04607                     return nomem(s);
04608                 }
04609                 p->param = p->parbuf;
04610                 memcpy(p->param, data, size);
04611                 p->len = size;
04612                 p->need = -1;
04613             } else if (len == SQL_NTS && (
04614                        type == SQL_C_CHAR
04615 #ifdef WCHARSUPPORT
04616                        || type == SQL_C_WCHAR
04617 #endif
04618                       )) {
04619                 char *dp = data;
04620 
04621 #ifdef WCHARSUPPORT
04622                 if (type == SQL_C_WCHAR) {
04623                     dp = uc_to_utf(data, len);
04624                     if (!dp) {
04625                         return nomem(s);
04626                     }
04627                 }
04628 #endif
04629 #if defined(_WIN32) || defined(_WIN64)
04630                 if (*s->oemcp) {
04631                     dp = wmb_to_utf(data, strlen (data));
04632                     if (!dp) {
04633                         return nomem(s);
04634                     }
04635                 }
04636 #endif
04637                 dlen = strlen(dp);
04638                 freep(&p->parbuf);
04639                 p->parbuf = xmalloc(dlen + 1);
04640                 if (!p->parbuf) {
04641                     if (dp != data) {
04642                         uc_free(dp);
04643                     }
04644                     return nomem(s);
04645                 }
04646                 p->param = p->parbuf;
04647                 strcpy(p->param, dp);
04648                 if (dp != data) {
04649                     uc_free(dp);
04650                 }
04651                 p->len = dlen;
04652                 p->need = -1;
04653             } else if (len < 0) {
04654                 setstat(s, -1, "invalid length", "HY090");
04655                 return SQL_ERROR;
04656             } else {
04657                 dlen = min(p->len - p->offs, len);
04658                 if (!p->param) {
04659                     setstat(s, -1, "no memory for parameter", "HY013");
04660                     return SQL_ERROR;
04661                 }
04662                 memcpy((char *) p->param + p->offs, data, dlen);
04663                 p->offs += dlen;
04664                 if (p->offs >= p->len) {
04665 #ifdef WCHARSUPPORT
04666                     if (type == SQL_C_WCHAR) {
04667                         char *dp = uc_to_utf(p->param, p->len);
04668                         char *np;
04669                         int nlen;
04670 
04671                         if (!dp) {
04672                             return nomem(s);
04673                         }
04674                         nlen = strlen(dp);
04675                         np = xmalloc(nlen + 1);
04676                         if (!np) {
04677                             uc_free(dp);
04678                             return nomem(s);
04679                         }
04680                         strcpy(np, dp);
04681                         uc_free(dp);
04682                         if (p->param == p->parbuf) {
04683                             freep(&p->parbuf);
04684                         }
04685                         p->parbuf = p->param = np;
04686                         p->len = nlen;
04687                     } else {
04688                         *((char *) p->param + p->len) = '\0';
04689                     }
04690                     p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR)
04691                             ? -1 : 0;
04692 #else
04693                     *((char *) p->param + p->len) = '\0';
04694                     p->need = (type == SQL_C_CHAR) ? -1 : 0;
04695 #endif
04696 #if defined(_WIN32) || defined(_WIN64)
04697                     if (type == SQL_C_CHAR && *s->oemcp &&
04698                         !(p->stype == SQL_BINARY ||
04699                           p->stype == SQL_VARBINARY ||
04700                           p->stype == SQL_LONGVARBINARY)) {
04701                         char *dp = wmb_to_utf(p->param, p->len);
04702 
04703                         if (!dp) {
04704                             return nomem(s);
04705                         }
04706                         if (p->param == p->parbuf) {
04707                             freep(&p->parbuf);
04708                         }
04709                         p->parbuf = p->param = dp;
04710                         p->len = strlen(dp);
04711                     }
04712                     if (p->type == SQL_C_WCHAR &&
04713                         (p->stype == SQL_VARCHAR ||
04714                          p->stype == SQL_LONGVARCHAR) &&
04715                          p->len == p->coldef * sizeof (SQLWCHAR)) {
04716                         /* fix for MS-Access */
04717                         p->len = p->coldef;
04718                     }
04719 #endif
04720                 }
04721             }
04722             done = 1;
04723             break;
04724         }
04725     }
04726     if (!done) {
04727         goto seqerr;
04728     }
04729     return SQL_SUCCESS;
04730 }
04731 
04740 SQLRETURN SQL_API
04741 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
04742 {
04743     SQLRETURN ret;
04744 
04745     HSTMT_LOCK(stmt);
04746     ret = drvputdata(stmt, data, len);
04747     HSTMT_UNLOCK(stmt);
04748     return ret;
04749 }
04750 
04756 static SQLRETURN
04757 freeparams(STMT *s)
04758 {
04759     if (s->bindparms) {
04760         int n;
04761 
04762         for (n = 0; n < s->nbindparms; n++) {
04763             freep(&s->bindparms[n].parbuf);
04764             memset(&s->bindparms[n], 0, sizeof (BINDPARM));
04765         }
04766     }
04767     return SQL_SUCCESS;
04768 }
04769 
04781 static SQLRETURN
04782 setupparam(STMT *s, char *sql, int pnum)
04783 {
04784     int type, len = 0, needalloc = 0;
04785     BINDPARM *p;
04786 
04787     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
04788         goto error;
04789     }
04790     p = &s->bindparms[pnum];
04791     type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
04792 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
04793     /* MS Access hack part 4 (map SQL_C_DEFAULT to SQL_C_CHAR) */
04794     if (type == SQL_C_WCHAR && p->type == SQL_C_DEFAULT) {
04795         type = SQL_C_CHAR;
04796     }
04797 #endif
04798     if (p->need > 0) {
04799         return setupparbuf(s, p);      
04800     }
04801     p->strbuf[0] = '\0';
04802     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
04803         p->s3type = SQLITE_NULL;
04804         p->s3size = 0;
04805         return SQL_SUCCESS;
04806     }
04807     if (type == SQL_C_CHAR &&
04808         (p->stype == SQL_BINARY ||
04809          p->stype == SQL_VARBINARY ||
04810          p->stype == SQL_LONGVARBINARY)) {
04811         type = SQL_C_BINARY;
04812     }
04813     switch (type) {
04814     case SQL_C_BINARY:
04815         p->s3type = SQLITE_BLOB;
04816         p->s3size = p->len;
04817         p->s3val = p->param;
04818         if (p->need < 0) {
04819             break;
04820         }
04821         if (!p->lenp) {
04822             len = p->len;
04823         } else if (*p->lenp == SQL_DATA_AT_EXEC) {
04824             len = p->len;
04825         } else {
04826             len = *p->lenp;
04827             if (len <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
04828                 len = SQL_LEN_DATA_AT_EXEC(len);
04829             }
04830         }
04831         if (len < 0) {
04832             setstat(s, -1, "invalid length", "HY009");
04833             return SQL_ERROR;
04834         }
04835         p->len = len;
04836         p->max = p->len;
04837         p->need = -1;
04838         p->s3size = len;
04839         break;
04840 #ifdef WCHARSUPPORT
04841     case SQL_C_WCHAR:
04842 #endif
04843     case SQL_C_CHAR:
04844         p->s3type = SQLITE_TEXT;
04845         p->s3size = -1;
04846         p->s3val = p->param;
04847         if (!p->parbuf && p->lenp) {
04848 #ifdef WCHARSUPPORT
04849             if (type == SQL_C_WCHAR) {
04850                 if (*p->lenp == SQL_NTS) {
04851                     p->max = uc_strlen(p->param) * sizeof (SQLWCHAR);
04852                 } else if (*p->lenp >= 0) {
04853                     p->max = *p->lenp;
04854                 }
04855             } else
04856 #endif
04857             if (type == SQL_C_CHAR) {
04858                 if (*p->lenp == SQL_NTS) {
04859                     p->len = p->max = strlen(p->param);
04860 #if defined(_WIN32) || defined(_WIN64)
04861                     needalloc = 1;
04862 #endif
04863                 } else if (*p->lenp >= 0) {
04864                     p->len = p->max = *p->lenp;
04865                     needalloc = 1;
04866                 }
04867             }
04868         }
04869         if (p->need < 0 && p->parbuf == p->param) {
04870             break;
04871         }
04872 #ifdef WCHARSUPPORT
04873         if (type == SQL_C_WCHAR) {
04874             char *dp = uc_to_utf(p->param, p->max);
04875 
04876             if (!dp) {
04877                 return nomem(s);
04878             }
04879             if (p->param == p->parbuf) {
04880                 freep(&p->parbuf);
04881             }
04882             p->parbuf = p->param = dp;
04883             p->need = -1;
04884             p->len = strlen(p->param);
04885             p->s3val = p->param;
04886             p->s3size = p->len;
04887         } else
04888 #endif
04889         if (type == SQL_C_CHAR) {
04890             p->s3val = p->param;
04891             if (needalloc) {
04892                 char *dp;
04893 
04894 #if defined(_WIN32) || defined(_WIN64)
04895                 if (*s->oemcp) {
04896                     dp = wmb_to_utf(p->param, p->len);
04897                 } else {
04898                     dp = xmalloc(p->len + 1);
04899                 }
04900 #else
04901                 dp = xmalloc(p->len + 1);
04902 #endif
04903                 if (!dp) {
04904                     return nomem(s);
04905                 }
04906 #if defined(_WIN32) || defined(_WIN64)
04907                 if (*s->oemcp) {
04908                     p->len = strlen(dp);
04909                 } else {
04910                     memcpy(dp, p->param, p->len);
04911                     dp[p->len] = '\0';
04912                 }
04913 #else
04914                 memcpy(dp, p->param, p->len);
04915                 dp[p->len] = '\0';
04916 #endif
04917                 if (p->param == p->parbuf) {
04918                     freep(&p->parbuf);
04919                 }
04920                 p->parbuf = p->param = dp;
04921                 p->need = -1;
04922                 p->s3val = p->param;
04923                 p->s3size = p->len;
04924             }
04925         }
04926         break;
04927     case SQL_C_UTINYINT:
04928         p->s3type = SQLITE_INTEGER;
04929         p->s3size = sizeof (int);
04930         p->s3ival = *((SQLCHAR *) p->param);
04931         break;
04932     case SQL_C_TINYINT:
04933     case SQL_C_STINYINT:
04934         p->s3type = SQLITE_INTEGER;
04935         p->s3size = sizeof (int);
04936         p->s3ival = *((SQLCHAR *) p->param);
04937         break;
04938     case SQL_C_USHORT:
04939         p->s3type = SQLITE_INTEGER;
04940         p->s3size = sizeof (int);
04941         p->s3ival = *((SQLUSMALLINT *) p->param);
04942         break;
04943     case SQL_C_SHORT:
04944     case SQL_C_SSHORT:
04945         p->s3type = SQLITE_INTEGER;
04946         p->s3size = sizeof (int);
04947         p->s3ival = *((SQLSMALLINT *) p->param);
04948         break;
04949     case SQL_C_ULONG:
04950         p->s3type = SQLITE_INTEGER;
04951         p->s3size = sizeof (int);
04952         p->s3ival = *((SQLUINTEGER *) p->param);
04953         break;
04954     case SQL_C_LONG:
04955     case SQL_C_SLONG:
04956         p->s3type = SQLITE_INTEGER;
04957         p->s3size = sizeof (int);
04958         p->s3ival = *((SQLINTEGER *) p->param);
04959         break;
04960 #ifdef SQL_BIT
04961     case SQL_C_BIT:
04962         p->s3type = SQLITE_INTEGER;
04963         p->s3size = sizeof (int);
04964         p->s3ival = (*((SQLCHAR *) p->param)) ? 1 : 0;
04965         break;
04966 #endif
04967 #ifdef SQL_BIGINT
04968     case SQL_C_SBIGINT:
04969         p->s3type = SQLITE_INTEGER;
04970         p->s3size = sizeof (sqlite_int64);
04971         p->s3lival = *((sqlite_int64 *) p->param);
04972         break;
04973     case SQL_C_UBIGINT:
04974         p->s3type = SQLITE_INTEGER;
04975         p->s3size = sizeof (sqlite_int64);
04976         p->s3lival = *((sqlite_uint64 *) p->param);
04977         break;
04978 #endif
04979     case SQL_C_FLOAT:
04980         p->s3type = SQLITE_FLOAT;
04981         p->s3size = sizeof (double);
04982         p->s3dval = *((float *) p->param);
04983         break;
04984     case SQL_C_DOUBLE:
04985         p->s3type = SQLITE_FLOAT;
04986         p->s3size = sizeof (double);
04987         p->s3dval = *((double *) p->param);
04988         break;
04989 #ifdef SQL_C_TYPE_DATE
04990     case SQL_C_TYPE_DATE:
04991 #endif
04992     case SQL_C_DATE:
04993         if (*s->jdconv) {
04994             int a, b, x1, x2, y, m, d;
04995 
04996             p->s3type = SQLITE_FLOAT;
04997             p->s3size = sizeof (double);
04998             y = ((DATE_STRUCT *) p->param)->year;
04999             m = ((DATE_STRUCT *) p->param)->month;
05000             d = ((DATE_STRUCT *) p->param)->day;
05001             if (m <= 2) {
05002                 y--;
05003                 m += 12;
05004             }
05005             a = y / 100;
05006             b = 2 - a + (a / 4);
05007             x1 = 36525 * (y + 4716) / 100;
05008             x2 = 306001 * (m + 1) / 10000;
05009             p->s3dval = x1 + x2 + d + b - 1524.5;
05010             break;
05011         }
05012         sprintf(p->strbuf, "%04d-%02d-%02d",
05013                 ((DATE_STRUCT *) p->param)->year,
05014                 ((DATE_STRUCT *) p->param)->month,
05015                 ((DATE_STRUCT *) p->param)->day);
05016         p->s3type = SQLITE_TEXT;
05017         p->s3size = -1;
05018         p->s3val = p->strbuf;
05019         break;
05020 #ifdef SQL_C_TYPE_TIME
05021     case SQL_C_TYPE_TIME:
05022 #endif
05023     case SQL_C_TIME:
05024         if (*s->jdconv) {
05025             p->s3type = SQLITE_FLOAT;
05026             p->s3size = sizeof (double);
05027             p->s3dval = 2451544.5 + 
05028                (((TIME_STRUCT *) p->param)->hour * 3600000.0 +
05029                 ((TIME_STRUCT *) p->param)->minute * 60000.0 +
05030                 ((TIME_STRUCT *) p->param)->second * 1000.0) / 86400000.0;
05031             break;
05032         }
05033         sprintf(p->strbuf, "%02d:%02d:%02d",
05034                 ((TIME_STRUCT *) p->param)->hour,
05035                 ((TIME_STRUCT *) p->param)->minute,
05036                 ((TIME_STRUCT *) p->param)->second);
05037         p->s3type = SQLITE_TEXT;
05038         p->s3size = -1;
05039         p->s3val = p->strbuf;
05040         break;
05041 #ifdef SQL_C_TYPE_TIMESTAMP
05042     case SQL_C_TYPE_TIMESTAMP:
05043 #endif
05044     case SQL_C_TIMESTAMP:
05045         if (*s->jdconv) {
05046             int a, b, x1, x2, y, m, d;
05047 
05048             p->s3type = SQLITE_FLOAT;
05049             p->s3size = sizeof (double);
05050             y = ((TIMESTAMP_STRUCT *) p->param)->year;
05051             m = ((TIMESTAMP_STRUCT *) p->param)->month;
05052             d = ((TIMESTAMP_STRUCT *) p->param)->day;
05053             if (m <= 2) {
05054                 y--;
05055                 m += 12;
05056             }
05057             a = y / 100;
05058             b = 2 - a + (a / 4);
05059             x1 = 36525 * (y + 4716) / 100;
05060             x2 = 306001 * (m + 1) / 10000;
05061             p->s3dval = x1 + x2 + d + b - 1524.5 +
05062                (((TIMESTAMP_STRUCT *) p->param)->hour * 3600000.0 +
05063                 ((TIMESTAMP_STRUCT *) p->param)->minute * 60000.0 +
05064                 ((TIMESTAMP_STRUCT *) p->param)->second * 1000.0 +
05065                 ((TIMESTAMP_STRUCT *) p->param)->fraction / 1.0E6)
05066                / 86400000.0;
05067             break;
05068         }
05069         len = (int) ((TIMESTAMP_STRUCT *) p->param)->fraction;
05070         len /= 1000000;
05071         len = len % 1000;
05072         if (len < 0) {
05073             len = 0;
05074         }
05075         if (p->coldef && p->coldef <= 16) {
05076             sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
05077                     ((TIMESTAMP_STRUCT *) p->param)->year,
05078                     ((TIMESTAMP_STRUCT *) p->param)->month,
05079                     ((TIMESTAMP_STRUCT *) p->param)->day,
05080                     ((TIMESTAMP_STRUCT *) p->param)->hour,
05081                     ((TIMESTAMP_STRUCT *) p->param)->minute);
05082         } else if (p->coldef && p->coldef <= 19) {
05083             sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
05084                     ((TIMESTAMP_STRUCT *) p->param)->year,
05085                     ((TIMESTAMP_STRUCT *) p->param)->month,
05086                     ((TIMESTAMP_STRUCT *) p->param)->day,
05087                     ((TIMESTAMP_STRUCT *) p->param)->hour,
05088                     ((TIMESTAMP_STRUCT *) p->param)->minute,
05089                     ((TIMESTAMP_STRUCT *) p->param)->second);
05090         } else {
05091             sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
05092                     ((TIMESTAMP_STRUCT *) p->param)->year,
05093                     ((TIMESTAMP_STRUCT *) p->param)->month,
05094                     ((TIMESTAMP_STRUCT *) p->param)->day,
05095                     ((TIMESTAMP_STRUCT *) p->param)->hour,
05096                     ((TIMESTAMP_STRUCT *) p->param)->minute,
05097                     ((TIMESTAMP_STRUCT *) p->param)->second,
05098                     len);
05099         }
05100         p->s3type = SQLITE_TEXT;
05101         p->s3size = -1;
05102         p->s3val = p->strbuf;
05103         break;
05104     default:
05105     error:
05106         setstat(s, -1, "unsupported parameter type",
05107                 (*s->ov3) ? "07009" : "S1093");
05108         return SQL_ERROR;
05109     }
05110     return SQL_SUCCESS;
05111 }
05112 
05128 static SQLRETURN
05129 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
05130              SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
05131              SQLSMALLINT scale,
05132              SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
05133 {
05134     STMT *s;
05135     BINDPARM *p;
05136 
05137     if (stmt == SQL_NULL_HSTMT) {
05138         return SQL_INVALID_HANDLE;
05139     }
05140     s = (STMT *) stmt;
05141     if (pnum == 0) {
05142         setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
05143         return SQL_ERROR;
05144     }
05145     if (!data && !len) {
05146         setstat(s, -1, "invalid buffer", "HY003");
05147         return SQL_ERROR;
05148     }
05149     --pnum;
05150     if (s->bindparms) {
05151         if (pnum >= s->nbindparms) {
05152             BINDPARM *newparms;
05153             
05154             newparms = xrealloc(s->bindparms,
05155                                 (pnum + 1) * sizeof (BINDPARM));
05156             if (!newparms) {
05157 outofmem:
05158                 return nomem(s);
05159             }
05160             s->bindparms = newparms;
05161             memset(&s->bindparms[s->nbindparms], 0,
05162                    (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
05163             s->nbindparms = pnum + 1;
05164         }
05165     } else {
05166         int npar = max(10, pnum + 1);
05167 
05168         s->bindparms = xmalloc(npar * sizeof (BINDPARM));
05169         if (!s->bindparms) {
05170             goto outofmem;
05171         }
05172         memset(s->bindparms, 0, npar * sizeof (BINDPARM));
05173         s->nbindparms = npar;
05174     }
05175     switch (buftype) {
05176     case SQL_C_STINYINT:
05177     case SQL_C_UTINYINT:
05178     case SQL_C_TINYINT:
05179 #ifdef SQL_C_BIT
05180     case SQL_C_BIT:
05181 #endif
05182         buflen = sizeof (SQLCHAR);
05183         break;
05184     case SQL_C_SHORT:
05185     case SQL_C_USHORT:
05186     case SQL_C_SSHORT:
05187         buflen = sizeof (SQLSMALLINT);
05188         break;
05189     case SQL_C_SLONG:
05190     case SQL_C_ULONG:
05191     case SQL_C_LONG:
05192         buflen = sizeof (SQLINTEGER);
05193         break;
05194     case SQL_C_FLOAT:
05195         buflen = sizeof (float);
05196         break;
05197     case SQL_C_DOUBLE:
05198         buflen = sizeof (double);
05199         break;
05200     case SQL_C_TIMESTAMP:
05201 #ifdef SQL_C_TYPE_TIMESTAMP
05202     case SQL_C_TYPE_TIMESTAMP:
05203 #endif
05204         buflen = sizeof (TIMESTAMP_STRUCT);
05205         break;
05206     case SQL_C_TIME:
05207 #ifdef SQL_C_TYPE_TIME
05208     case SQL_C_TYPE_TIME:
05209 #endif
05210         buflen = sizeof (TIME_STRUCT);
05211         break;
05212     case SQL_C_DATE:
05213 #ifdef SQL_C_TYPE_DATE
05214     case SQL_C_TYPE_DATE:
05215 #endif
05216         buflen = sizeof (DATE_STRUCT);
05217         break;
05218 #ifdef SQL_C_UBIGINT
05219     case SQL_C_UBIGINT:
05220         buflen = sizeof (SQLBIGINT);
05221         break;
05222 #endif
05223 #ifdef SQL_C_SBIGINT
05224     case SQL_C_SBIGINT:
05225         buflen = sizeof (SQLBIGINT);
05226         break;
05227 #endif
05228 #ifdef SQL_C_BIGINT
05229     case SQL_C_BIGINT:
05230         buflen = sizeof (SQLBIGINT);
05231         break;
05232 #endif
05233     }
05234     p = &s->bindparms[pnum];
05235     p->type = buftype;
05236     p->stype = ptype;
05237     p->coldef = coldef;
05238     p->scale = scale;
05239     p->max = buflen;
05240     p->inc = buflen;
05241     p->lenp = p->lenp0 = len;
05242     p->offs = 0;
05243     p->len = 0;
05244     p->param0 = data;
05245     freep(&p->parbuf);
05246     p->param = p->param0;
05247     p->bound = 1;
05248     p->need = 0;
05249     return SQL_SUCCESS;
05250 }
05251 
05267 SQLRETURN SQL_API
05268 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
05269                  SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
05270                  SQLSMALLINT scale,
05271                  SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
05272 {
05273     SQLRETURN ret;
05274 
05275     HSTMT_LOCK(stmt);
05276     ret = drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
05277                        scale, data, buflen, len);
05278     HSTMT_UNLOCK(stmt);
05279     return ret;
05280 }
05281 
05282 #ifndef HAVE_IODBC
05283 
05296 SQLRETURN SQL_API
05297 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
05298              SQLSMALLINT ptype, SQLULEN lenprec,
05299              SQLSMALLINT scale, SQLPOINTER val,
05300              SQLLEN *lenp)
05301 {
05302     SQLRETURN ret;
05303 
05304     HSTMT_LOCK(stmt);
05305     ret = drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
05306                        lenprec, scale, val, 0, lenp);
05307     HSTMT_UNLOCK(stmt);
05308     return ret;
05309 }
05310 #endif
05311 
05319 SQLRETURN SQL_API
05320 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
05321 {
05322     STMT *s;
05323     SQLSMALLINT dummy;
05324 
05325     HSTMT_LOCK(stmt);
05326     if (stmt == SQL_NULL_HSTMT) {
05327         return SQL_INVALID_HANDLE;
05328     }
05329     s = (STMT *) stmt;
05330     if (!nparam) {
05331         nparam = &dummy;
05332     }
05333     *nparam = s->nparams;
05334     HSTMT_UNLOCK(stmt);
05335     return SQL_SUCCESS;
05336 }
05337 
05345 static SQLRETURN
05346 setupparbuf(STMT *s, BINDPARM *p)
05347 {
05348     if (!p->parbuf) {
05349         if (*p->lenp == SQL_DATA_AT_EXEC) {
05350             p->len = p->max;
05351         } else {
05352             p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
05353         }
05354         if (p->len < 0 && p->len != SQL_NTS &&
05355             p->len != SQL_NULL_DATA) {
05356             setstat(s, -1, "invalid length", "HY009");
05357             return SQL_ERROR;
05358         }
05359         if (p->len >= 0) {
05360             p->parbuf = xmalloc(p->len + 2);
05361             if (!p->parbuf) {
05362                 return nomem(s);
05363             }
05364             p->param = p->parbuf;
05365         } else {
05366             p->param = NULL;
05367         }
05368     }
05369     return SQL_NEED_DATA;
05370 }
05371 
05379 SQLRETURN SQL_API
05380 SQLParamData(SQLHSTMT stmt, SQLPOINTER *pind)
05381 {
05382     STMT *s;
05383     int i;
05384     SQLPOINTER dummy;
05385     SQLRETURN ret;
05386     BINDPARM *p;
05387 
05388     HSTMT_LOCK(stmt);
05389     if (stmt == SQL_NULL_HSTMT) {
05390         return SQL_INVALID_HANDLE;
05391     }
05392     s = (STMT *) stmt;
05393     if (!pind) {
05394         pind = &dummy;
05395     }
05396     if (s->pdcount < s->nparams) {
05397         s->pdcount++;
05398     }
05399     for (i = 0; i < s->pdcount; i++) {
05400         p = &s->bindparms[i];
05401         if (p->need > 0) {
05402             int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
05403 
05404             p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR) ? -1 : 0;
05405         }
05406     }
05407     for (; i < s->nparams; i++) {
05408         p = &s->bindparms[i];
05409         if (p->need > 0) {
05410             *pind = (SQLPOINTER) p->param0;
05411             ret = setupparbuf(s, p);
05412             s->pdcount = i;
05413             goto done;
05414         }
05415     }
05416     ret = drvexecute(stmt, 0);
05417 done:
05418     HSTMT_UNLOCK(stmt);
05419     return ret;
05420 }
05421 
05433 SQLRETURN SQL_API
05434 SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT *dtype,
05435                  SQLULEN *size, SQLSMALLINT *decdigits, SQLSMALLINT *nullable)
05436 {
05437     STMT *s;
05438     SQLRETURN ret = SQL_ERROR;
05439 
05440     HSTMT_LOCK(stmt);
05441     if (stmt == SQL_NULL_HSTMT) {
05442         return SQL_INVALID_HANDLE;
05443     }
05444     s = (STMT *) stmt;
05445     --pnum;
05446     if (pnum >= s->nparams) {
05447         setstat(s, -1, "invalid parameter index",
05448                 (*s->ov3) ? "HY000" : "S1000");
05449         goto done;
05450     }
05451     if (dtype) {
05452 #ifdef SQL_LONGVARCHAR
05453 #ifdef WINTERFACE
05454         *dtype = s->nowchar[0] ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
05455 #else   
05456         *dtype = SQL_LONGVARCHAR;
05457 #endif
05458 #else
05459 #ifdef WINTERFACE
05460         *dtype = s->nowchar[0] ? SQL_VARCHAR : SQL_WVARCHAR;
05461 #else
05462         *dtype = SQL_VARCHAR;
05463 #endif
05464 #endif
05465     }
05466     if (size) {
05467 #ifdef SQL_LONGVARCHAR
05468         *size = 65536;
05469 #else
05470         *size = 255;
05471 #endif
05472     }
05473     if (decdigits) {
05474         *decdigits = 0;
05475     }
05476     if (nullable) {
05477         *nullable = SQL_NULLABLE;
05478     }
05479     ret = SQL_SUCCESS;
05480 done:
05481     HSTMT_UNLOCK(stmt);
05482     return ret;
05483 }
05484 
05498 SQLRETURN SQL_API
05499 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
05500             SQLSMALLINT sqltype, SQLULEN coldef,
05501             SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
05502 {
05503     SQLRETURN ret;
05504 
05505     HSTMT_LOCK(stmt);
05506     ret = drvbindparam(stmt, par, SQL_PARAM_INPUT,
05507                        type, sqltype, coldef, scale, val,
05508                        SQL_SETPARAM_VALUE_MAX, nval);
05509     HSTMT_UNLOCK(stmt);
05510     return ret;
05511 }
05512 
05517 SQLRETURN SQL_API
05518 SQLParamOptions(SQLHSTMT stmt, SQLULEN rows, SQLULEN *rowp)
05519 {
05520     SQLRETURN ret;
05521 
05522     HSTMT_LOCK(stmt);
05523     ret = drvunimplstmt(stmt);
05524     HSTMT_UNLOCK(stmt);
05525     return ret;
05526 }
05527 
05528 #ifndef WINTERFACE
05529 
05533 SQLRETURN SQL_API
05534 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
05535                 SQLSMALLINT fieldid, SQLPOINTER value,
05536                 SQLINTEGER buflen, SQLINTEGER *strlen)
05537 {
05538     return SQL_ERROR;
05539 }
05540 #endif
05541 
05542 #ifdef WINTERFACE
05543 
05547 SQLRETURN SQL_API
05548 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
05549                  SQLSMALLINT fieldid, SQLPOINTER value,
05550                  SQLINTEGER buflen, SQLINTEGER *strlen)
05551 {
05552     return SQL_ERROR;
05553 }
05554 #endif
05555 
05556 #ifndef WINTERFACE
05557 
05561 SQLRETURN SQL_API
05562 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
05563                 SQLSMALLINT fieldid, SQLPOINTER value,
05564                 SQLINTEGER buflen)
05565 {
05566     return SQL_ERROR;
05567 }
05568 #endif
05569 
05570 #ifdef WINTERFACE
05571 
05575 SQLRETURN SQL_API
05576 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
05577                  SQLSMALLINT fieldid, SQLPOINTER value,
05578                  SQLINTEGER buflen)
05579 {
05580     return SQL_ERROR;
05581 }
05582 #endif
05583 
05584 #ifndef WINTERFACE
05585 
05589 SQLRETURN SQL_API
05590 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
05591               SQLCHAR *name, SQLSMALLINT buflen,
05592               SQLSMALLINT *strlen, SQLSMALLINT *type,
05593               SQLSMALLINT *subtype, SQLLEN *len,
05594               SQLSMALLINT *prec, SQLSMALLINT *scale,
05595               SQLSMALLINT *nullable)
05596 {
05597     return SQL_ERROR;
05598 }
05599 #endif
05600 
05601 #ifdef WINTERFACE
05602 
05606 SQLRETURN SQL_API
05607 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
05608                SQLWCHAR *name, SQLSMALLINT buflen,
05609                SQLSMALLINT *strlen, SQLSMALLINT *type,
05610                SQLSMALLINT *subtype, SQLLEN *len,
05611                SQLSMALLINT *prec, SQLSMALLINT *scale,
05612                SQLSMALLINT *nullable)
05613 {
05614     return SQL_ERROR;
05615 }
05616 #endif
05617 
05622 SQLRETURN SQL_API
05623 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
05624               SQLSMALLINT type, SQLSMALLINT subtype,
05625               SQLLEN len, SQLSMALLINT prec,
05626               SQLSMALLINT scale, SQLPOINTER data,
05627               SQLLEN *strlen, SQLLEN *indicator)
05628 {
05629     return SQL_ERROR;
05630 }
05631 
05643 static SQLRETURN
05644 mkresultset(HSTMT stmt, COL *colspec, int ncols, COL *colspec3,
05645             int ncols3, int *nret)
05646 {
05647     STMT *s;
05648     DBC *d;
05649 
05650     if (stmt == SQL_NULL_HSTMT) {
05651         return SQL_INVALID_HANDLE;
05652     }
05653     s = (STMT *) stmt;
05654     if (s->dbc == SQL_NULL_HDBC) {
05655 noconn:
05656         return noconn(s);
05657     }
05658     d = (DBC *) s->dbc;
05659     if (!d->sqlite) {
05660         goto noconn;
05661     }
05662     s3stmt_end_if(s);
05663     freeresult(s, 0);
05664     if (colspec3 && *s->ov3) {
05665         s->ncols = ncols3;
05666         s->cols = colspec3;
05667     } else {
05668         s->ncols = ncols;
05669         s->cols = colspec;
05670     }
05671     mkbindcols(s, s->ncols);
05672     s->nowchar[1] = 1;
05673     s->nrows = 0;
05674     s->rowp = -1;
05675     s->isselect = -1;
05676     if (nret) {
05677         *nret = s->ncols;
05678     }
05679     return SQL_SUCCESS;
05680 }
05681 
05686 static COL tablePrivSpec2[] = {
05687     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
05688     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
05689     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
05690     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
05691     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
05692     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
05693     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
05694 };
05695 
05696 static COL tablePrivSpec3[] = {
05697     { "SYSTEM", "TABLEPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
05698     { "SYSTEM", "TABLEPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
05699     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
05700     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
05701     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
05702     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
05703     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
05704 };
05705 
05718 static SQLRETURN
05719 drvtableprivileges(SQLHSTMT stmt,
05720                    SQLCHAR *cat, SQLSMALLINT catLen,
05721                    SQLCHAR *schema, SQLSMALLINT schemaLen,
05722                    SQLCHAR *table, SQLSMALLINT tableLen)
05723 {
05724     SQLRETURN ret;
05725     STMT *s;
05726     DBC *d;
05727     int ncols, rc, size, npatt;
05728     char *errp = NULL, *sql, tname[512];
05729 
05730     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
05731                       tablePrivSpec3, array_size(tablePrivSpec3), NULL);
05732     if (ret != SQL_SUCCESS) {
05733         return ret;
05734     }
05735     s = (STMT *) stmt;
05736     d = (DBC *) s->dbc;
05737     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
05738         table = NULL;
05739         goto doit;
05740     }
05741     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
05742         schema[0] == '%') {
05743         if ((!cat || catLen == 0 || !cat[0]) &&
05744             (!table || tableLen == 0 || !table[0])) {
05745             table = NULL;
05746             goto doit;
05747         }
05748     }
05749 doit:
05750     if (!table) {
05751         size = 1;
05752         tname[0] = '%';
05753     } else {
05754         if (tableLen == SQL_NTS) {
05755             size = sizeof (tname) - 1;
05756         } else {
05757             size = min(sizeof (tname) - 1, tableLen);
05758         }
05759         strncpy(tname, (char *) table, size);
05760     }
05761     tname[size] = '\0';
05762     npatt = unescpat(tname);
05763 #if defined(_WIN32) || defined(_WIN64)
05764     sql = sqlite3_mprintf("select %s as 'TABLE_QUALIFIER', "
05765                           "%s as 'TABLE_OWNER', "
05766                           "tbl_name as 'TABLE_NAME', "
05767                           "'' as 'GRANTOR', "
05768                           "'' as 'GRANTEE', "
05769                           "'SELECT' AS 'PRIVILEGE', "
05770                           "NULL as 'IS_GRANTABLE' "
05771                           "from sqlite_master where "
05772                           "(type = 'table' or type = 'view') "
05773                           "and tbl_name %s %Q "
05774                           "UNION "
05775                           "select %s as 'TABLE_QUALIFIER', "
05776                           "%s as 'TABLE_OWNER', "
05777                           "tbl_name as 'TABLE_NAME', "
05778                           "'' as 'GRANTOR', "
05779                           "'' as 'GRANTEE', "
05780                           "'UPDATE' AS 'PRIVILEGE', "
05781                           "NULL as 'IS_GRANTABLE' "
05782                           "from sqlite_master where "
05783                           "(type = 'table' or type = 'view') "
05784                           "and tbl_name %s %Q "
05785                           "UNION "
05786                           "select %s as 'TABLE_QUALIFIER', "
05787                           "%s as 'TABLE_OWNER', "
05788                           "tbl_name as 'TABLE_NAME', "
05789                           "'' as 'GRANTOR', "
05790                           "'' as 'GRANTEE', "
05791                           "'DELETE' AS 'PRIVILEGE', "
05792                           "NULL as 'IS_GRANTABLE' "
05793                           "from sqlite_master where "
05794                           "(type = 'table' or type = 'view') "
05795                           "and tbl_name %s %Q "
05796                           "UNION "
05797                           "select %s as 'TABLE_QUALIFIER', "
05798                           "%s as 'TABLE_OWNER', "
05799                           "tbl_name as 'TABLE_NAME', "
05800                           "'' as 'GRANTOR', "
05801                           "'' as 'GRANTEE', "
05802                           "'INSERT' AS 'PRIVILEGE', "
05803                           "NULL as 'IS_GRANTABLE' "
05804                           "from sqlite_master where "
05805                           "(type = 'table' or type = 'view') "
05806                           "and tbl_name %s %Q "
05807                           "UNION "
05808                           "select %s as 'TABLE_QUALIFIER', "
05809                           "%s as 'TABLE_OWNER', "
05810                           "tbl_name as 'TABLE_NAME', "
05811                           "'' as 'GRANTOR', "
05812                           "'' as 'GRANTEE', "
05813                           "'REFERENCES' AS 'PRIVILEGE', "
05814                           "NULL as 'IS_GRANTABLE' "
05815                           "from sqlite_master where "
05816                           "(type = 'table' or type = 'view') "
05817                           "and tbl_name %s %Q",
05818                           d->xcelqrx ? "''" : "NULL",
05819                           d->xcelqrx ? "'main'" : "NULL",
05820                           npatt ? "like" : "=", tname,
05821                           d->xcelqrx ? "''" : "NULL",
05822                           d->xcelqrx ? "'main'" : "NULL",
05823                           npatt ? "like" : "=", tname,
05824                           d->xcelqrx ? "''" : "NULL",
05825                           d->xcelqrx ? "'main'" : "NULL",
05826                           npatt ? "like" : "=", tname,
05827                           d->xcelqrx ? "''" : "NULL",
05828                           d->xcelqrx ? "'main'" : "NULL",
05829                           npatt ? "like" : "=", tname,
05830                           d->xcelqrx ? "''" : "NULL",
05831                           d->xcelqrx ? "'main'" : "NULL",
05832                           npatt ? "like" : "=", tname);
05833 #else
05834     sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
05835                           "NULL as 'TABLE_OWNER', "
05836                           "tbl_name as 'TABLE_NAME', "
05837                           "'' as 'GRANTOR', "
05838                           "'' as 'GRANTEE', "
05839                           "'SELECT' AS 'PRIVILEGE', "
05840                           "NULL as 'IS_GRANTABLE' "
05841                           "from sqlite_master where "
05842                           "(type = 'table' or type = 'view') "
05843                           "and tbl_name %s %Q "
05844                           "UNION "
05845                           "select NULL as 'TABLE_QUALIFIER', "
05846                           "NULL as 'TABLE_OWNER', "
05847                           "tbl_name as 'TABLE_NAME', "
05848                           "'' as 'GRANTOR', "
05849                           "'' as 'GRANTEE', "
05850                           "'UPDATE' AS 'PRIVILEGE', "
05851                           "NULL as 'IS_GRANTABLE' "
05852                           "from sqlite_master where "
05853                           "(type = 'table' or type = 'view') "
05854                           "and tbl_name %s %Q "
05855                           "UNION "
05856                           "select NULL as 'TABLE_QUALIFIER', "
05857                           "NULL as 'TABLE_OWNER', "
05858                           "tbl_name as 'TABLE_NAME', "
05859                           "'' as 'GRANTOR', "
05860                           "'' as 'GRANTEE', "
05861                           "'DELETE' AS 'PRIVILEGE', "
05862                           "NULL as 'IS_GRANTABLE' "
05863                           "from sqlite_master where "
05864                           "(type = 'table' or type = 'view') "
05865                           "and tbl_name %s %Q "
05866                           "UNION "
05867                           "select NULL as 'TABLE_QUALIFIER', "
05868                           "NULL as 'TABLE_OWNER', "
05869                           "tbl_name as 'TABLE_NAME', "
05870                           "'' as 'GRANTOR', "
05871                           "'' as 'GRANTEE', "
05872                           "'INSERT' AS 'PRIVILEGE', "
05873                           "NULL as 'IS_GRANTABLE' "
05874                           "from sqlite_master where "
05875                           "(type = 'table' or type = 'view') "
05876                           "and tbl_name %s %Q "
05877                           "UNION "
05878                           "select NULL as 'TABLE_QUALIFIER', "
05879                           "NULL as 'TABLE_OWNER', "
05880                           "tbl_name as 'TABLE_NAME', "
05881                           "'' as 'GRANTOR', "
05882                           "'' as 'GRANTEE', "
05883                           "'REFERENCES' AS 'PRIVILEGE', "
05884                           "NULL as 'IS_GRANTABLE' "
05885                           "from sqlite_master where "
05886                           "(type = 'table' or type = 'view') "
05887                           "and tbl_name %s %Q",
05888                           npatt ? "like" : "=", tname,
05889                           npatt ? "like" : "=", tname,
05890                           npatt ? "like" : "=", tname,
05891                           npatt ? "like" : "=", tname,
05892                           npatt ? "like" : "=", tname);
05893 #endif
05894     if (!sql) {
05895         return nomem(s);
05896     }
05897     ret = starttran(s);
05898     if (ret != SQL_SUCCESS) {
05899         sqlite3_free(sql);
05900         return ret;
05901     }
05902     dbtraceapi(d, "sqlite3_get_table", sql);
05903     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
05904     sqlite3_free(sql);
05905     if (rc == SQLITE_OK) {
05906         if (ncols != s->ncols) {
05907             freeresult(s, 0);
05908             s->nrows = 0;
05909         } else {
05910             s->rowfree = sqlite3_free_table;
05911         }
05912     } else {
05913         s->nrows = 0;
05914         s->rows = NULL;
05915         s->rowfree = NULL;
05916     }
05917     if (errp) {
05918         sqlite3_free(errp);
05919         errp = NULL;
05920     }
05921     s->rowp = -1;
05922     return SQL_SUCCESS;
05923 }
05924 
05925 
05926 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
05927 
05939 SQLRETURN SQL_API
05940 SQLTablePrivileges(SQLHSTMT stmt,
05941                    SQLCHAR *catalog, SQLSMALLINT catalogLen,
05942                    SQLCHAR *schema, SQLSMALLINT schemaLen,
05943                    SQLCHAR *table, SQLSMALLINT tableLen)
05944 {
05945 #if defined(_WIN32) || defined(_WIN64)
05946     char *c = NULL, *s = NULL, *t = NULL;
05947 #endif
05948     SQLRETURN ret;
05949 
05950     HSTMT_LOCK(stmt);
05951 #if defined(_WIN32) || defined(_WIN64)
05952     if (!((STMT *) stmt)->oemcp[0]) {
05953         ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
05954                                  table, tableLen);
05955         goto done2;
05956     }
05957     if (catalog) {
05958         c = wmb_to_utf_c((char *) catalog, catalogLen);
05959         if (!c) {
05960             ret = nomem((STMT *) stmt);
05961             goto done;
05962         }
05963     }
05964     if (schema) {
05965         s = wmb_to_utf_c((char *) schema, schemaLen);
05966         if (!s) {
05967             ret = nomem((STMT *) stmt);
05968             goto done;
05969         }
05970     }
05971     if (table) {
05972         t = wmb_to_utf_c((char *) table, tableLen);
05973         if (!t) {
05974             ret = nomem((STMT *) stmt);
05975             goto done;
05976         }
05977     }
05978     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
05979                              (SQLCHAR *) s, SQL_NTS,
05980                              (SQLCHAR *) t, SQL_NTS);
05981 #else
05982     ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
05983                              table, tableLen);
05984 #endif
05985 #if defined(_WIN32) || defined(_WIN64)
05986 done:
05987     uc_free(t);
05988     uc_free(s);
05989     uc_free(c);
05990 done2:
05991     ;
05992 #endif
05993     HSTMT_UNLOCK(stmt);
05994     return ret;
05995 }
05996 #endif
05997 
05998 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
05999 #ifdef WINTERFACE
06000 
06012 SQLRETURN SQL_API
06013 SQLTablePrivilegesW(SQLHSTMT stmt,
06014                     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
06015                     SQLWCHAR *schema, SQLSMALLINT schemaLen,
06016                     SQLWCHAR *table, SQLSMALLINT tableLen)
06017 {
06018     char *c = NULL, *s = NULL, *t = NULL;
06019     SQLRETURN ret;
06020 
06021     HSTMT_LOCK(stmt);
06022     if (catalog) {
06023         c = uc_to_utf_c(catalog, catalogLen);
06024         if (!c) {
06025             ret = nomem((STMT *) stmt);
06026             goto done;
06027         }
06028     }
06029     if (schema) {
06030         s = uc_to_utf_c(schema, schemaLen);
06031         if (!s) {
06032             ret = nomem((STMT *) stmt);
06033             goto done;
06034         }
06035     }
06036     if (table) {
06037         t = uc_to_utf_c(table, tableLen);
06038         if (!t) {
06039             ret = nomem((STMT *) stmt);
06040             goto done;
06041         }
06042     }
06043     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
06044                              (SQLCHAR *) s, SQL_NTS,
06045                              (SQLCHAR *) t, SQL_NTS);
06046 done:
06047     uc_free(t);
06048     uc_free(s);
06049     uc_free(c);
06050     HSTMT_UNLOCK(stmt);
06051     return ret;
06052 }
06053 #endif
06054 #endif
06055 
06060 static COL colPrivSpec2[] = {
06061     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
06062     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
06063     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
06064     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06065     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
06066     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
06067     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
06068 };
06069 
06070 static COL colPrivSpec3[] = {
06071     { "SYSTEM", "COLPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
06072     { "SYSTEM", "COLPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
06073     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
06074     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06075     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
06076     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
06077     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
06078 };
06079 
06080 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
06081 
06095 SQLRETURN SQL_API
06096 SQLColumnPrivileges(SQLHSTMT stmt,
06097                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
06098                     SQLCHAR *schema, SQLSMALLINT schemaLen,
06099                     SQLCHAR *table, SQLSMALLINT tableLen,
06100                     SQLCHAR *column, SQLSMALLINT columnLen)
06101 {
06102     SQLRETURN ret;
06103 
06104     HSTMT_LOCK(stmt);
06105     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
06106                       colPrivSpec3, array_size(colPrivSpec3), NULL);
06107     HSTMT_UNLOCK(stmt);
06108     return ret;
06109 }
06110 #endif
06111 
06112 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
06113 #ifdef WINTERFACE
06114 
06128 SQLRETURN SQL_API
06129 SQLColumnPrivilegesW(SQLHSTMT stmt,
06130                      SQLWCHAR *catalog, SQLSMALLINT catalogLen,
06131                      SQLWCHAR *schema, SQLSMALLINT schemaLen,
06132                      SQLWCHAR *table, SQLSMALLINT tableLen,
06133                      SQLWCHAR *column, SQLSMALLINT columnLen)
06134 {
06135     SQLRETURN ret;
06136 
06137     HSTMT_LOCK(stmt);
06138     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
06139                       colPrivSpec3, array_size(colPrivSpec3), NULL);
06140     HSTMT_UNLOCK(stmt);
06141     return ret;
06142 }
06143 #endif
06144 #endif
06145 
06150 static COL pkeySpec2[] = {
06151     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
06152     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
06153     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
06154     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06155     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
06156     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
06157 };
06158 
06159 static COL pkeySpec3[] = {
06160     { "SYSTEM", "PRIMARYKEY", "TABLE_CAT", SCOL_VARCHAR, 50 },
06161     { "SYSTEM", "PRIMARYKEY", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
06162     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
06163     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06164     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
06165     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
06166 };
06167 
06180 static SQLRETURN
06181 drvprimarykeys(SQLHSTMT stmt,
06182                SQLCHAR *cat, SQLSMALLINT catLen,
06183                SQLCHAR *schema, SQLSMALLINT schemaLen,
06184                SQLCHAR *table, SQLSMALLINT tableLen)
06185 {
06186     STMT *s;
06187     DBC *d;
06188     SQLRETURN sret;
06189     int i, asize, ret, nrows, ncols, nrows2 = 0, ncols2 = 0;
06190     int namec = -1, uniquec = -1, namec2 = -1, uniquec2 = -1, offs, seq = 1;
06191     PTRDIFF_T size;
06192     char **rowp = NULL, **rowp2 = NULL, *errp = NULL, *sql, tname[512];
06193 
06194     sret = mkresultset(stmt, pkeySpec2, array_size(pkeySpec2),
06195                        pkeySpec3, array_size(pkeySpec3), &asize);
06196     if (sret != SQL_SUCCESS) {
06197         return sret;
06198     }
06199     s = (STMT *) stmt;
06200     d = (DBC *) s->dbc;
06201     if (!table || table[0] == '\0' || table[0] == '%') {
06202         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
06203         return SQL_ERROR;
06204     }
06205     if (tableLen == SQL_NTS) {
06206         size = sizeof (tname) - 1;
06207     } else {
06208         size = min(sizeof (tname) - 1, tableLen);
06209     }
06210     strncpy(tname, (char *) table, size);
06211     tname[size] = '\0';
06212     unescpat(tname);
06213     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
06214     if (!sql) {
06215         return nomem(s);
06216     }
06217     sret = starttran(s);
06218     if (sret != SQL_SUCCESS) {
06219         sqlite3_free(sql);
06220         return sret;
06221     }
06222     dbtraceapi(d, "sqlite3_get_table", sql);
06223     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
06224     sqlite3_free(sql);
06225     if (ret != SQLITE_OK) {
06226         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
06227                 errp ? errp : "unknown error", ret);
06228         if (errp) {
06229             sqlite3_free(errp);
06230             errp = NULL;
06231         }
06232         return SQL_ERROR;
06233     }
06234     if (errp) {
06235         sqlite3_free(errp);
06236         errp = NULL;
06237     }
06238     size = 0;
06239     if (ncols * nrows > 0) {
06240         int typec;
06241 
06242         namec = findcol(rowp, ncols, "name");
06243         uniquec = findcol(rowp, ncols, "pk");
06244         typec = findcol(rowp, ncols, "type");
06245         if (namec >= 0 && uniquec >= 0 && typec >= 0) {
06246             for (i = 1; i <= nrows; i++) {
06247                 if (*rowp[i * ncols + uniquec] != '0') {
06248                     size++;
06249                 }
06250             }
06251         }
06252     }
06253     if (size == 0) {
06254         sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
06255         if (!sql) {
06256             sqlite3_free_table(rowp);
06257             return nomem(s);
06258         }
06259         dbtraceapi(d, "sqlite3_get_table", sql);
06260         ret = sqlite3_get_table(d->sqlite, sql, &rowp2, &nrows2, &ncols2,
06261                                 &errp);
06262         sqlite3_free(sql);
06263         if (ret != SQLITE_OK) {
06264             sqlite3_free_table(rowp);
06265             sqlite3_free_table(rowp2);
06266             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
06267                     errp ? errp : "unknown error", ret);
06268             if (errp) {
06269                 sqlite3_free(errp);
06270                 errp = NULL;
06271             }
06272             return SQL_ERROR;
06273         }
06274         if (errp) {
06275             sqlite3_free(errp);
06276             errp = NULL;
06277         }
06278     }
06279     if (ncols2 * nrows2 > 0) {
06280         namec2 = findcol(rowp2, ncols2, "name");
06281         uniquec2 = findcol(rowp2, ncols2, "unique");
06282         if (namec2 >= 0 && uniquec2 >=  0) {
06283             for (i = 1; i <= nrows2; i++) {
06284                 int nnrows, nncols, nlen = 0;
06285                 char **rowpp;
06286 
06287                 if (rowp2[i * ncols2 + namec2]) {
06288                     nlen = strlen(rowp2[i * ncols2 + namec2]);
06289                 }
06290                 if (nlen < 17 ||
06291                     strncmp(rowp2[i * ncols2 + namec2],
06292                             "sqlite_autoindex_", 17)) {
06293                     continue;
06294                 }
06295                 if (*rowp2[i * ncols2 + uniquec2] != '0') {
06296                     ret = SQLITE_ERROR;
06297                     sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
06298                                           rowp2[i * ncols2 + namec2]);
06299                     if (sql) {
06300                         dbtraceapi(d, "sqlite3_get_table", sql);
06301                         ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
06302                                                 &nnrows, &nncols, NULL);
06303                         sqlite3_free(sql);
06304                     }
06305                     if (ret == SQLITE_OK) {
06306                         size += nnrows;
06307                         sqlite3_free_table(rowpp);
06308                     }
06309                 }
06310             }
06311         }
06312     }
06313     if (size == 0) {
06314         sqlite3_free_table(rowp);
06315         sqlite3_free_table(rowp2);
06316         return SQL_SUCCESS;
06317     }
06318     s->nrows = size;
06319     size = (size + 1) * asize;
06320     s->rows = xmalloc((size + 1) * sizeof (char *));
06321     if (!s->rows) {
06322         s->nrows = 0;
06323         sqlite3_free_table(rowp);
06324         sqlite3_free_table(rowp2);
06325         return nomem(s);
06326     }
06327     s->rows[0] = (char *) size;
06328     s->rows += 1;
06329     memset(s->rows, 0, sizeof (char *) * size);
06330     s->rowfree = freerows;
06331     offs = s->ncols;
06332     if (rowp) {
06333         for (i = 1; i <= nrows; i++) {
06334             if (*rowp[i * ncols + uniquec] != '0') {
06335                 char buf[32];
06336 
06337                 s->rows[offs + 0] = xstrdup("");
06338 #if defined(_WIN32) || defined(_WIN64)
06339                 s->rows[offs + 1] = xstrdup(d->xcelqrx ? "main" : "");
06340 #else
06341                 s->rows[offs + 1] = xstrdup("");
06342 #endif
06343                 s->rows[offs + 2] = xstrdup(tname);
06344                 s->rows[offs + 3] = xstrdup(rowp[i * ncols + namec]);
06345                 sprintf(buf, "%d", seq++);
06346                 s->rows[offs + 4] = xstrdup(buf);
06347                 offs += s->ncols;
06348             }
06349         }
06350     }
06351     if (rowp2) {
06352         for (i = 1; i <= nrows2; i++) {
06353             int nnrows, nncols, nlen = 0;
06354             char **rowpp;
06355 
06356             if (rowp2[i * ncols2 + namec2]) {
06357                 nlen = strlen(rowp2[i * ncols2 + namec2]);
06358             }
06359             if (nlen < 17 ||
06360                 strncmp(rowp2[i * ncols2 + namec2], "sqlite_autoindex_", 17)) {
06361                 continue;
06362             }
06363             if (*rowp2[i * ncols2 + uniquec2] != '0') {
06364                 int k;
06365 
06366                 ret = SQLITE_ERROR;
06367                 sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
06368                                       rowp2[i * ncols2 + namec2]);
06369                 if (sql) {
06370                     dbtraceapi(d, "sqlite3_get_table", sql);
06371                     ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
06372                                             &nnrows, &nncols, NULL);
06373                     sqlite3_free(sql);
06374                 }
06375                 if (ret != SQLITE_OK) {
06376                     continue;
06377                 }
06378                 for (k = 0; nnrows && k < nncols; k++) {
06379                     if (strcmp(rowpp[k], "name") == 0) {
06380                         int m;
06381 
06382                         for (m = 1; m <= nnrows; m++) {
06383                             int roffs = offs + (m - 1) * s->ncols;
06384 
06385                             s->rows[roffs + 0] = xstrdup("");
06386 #if defined(_WIN32) || defined(_WIN64)
06387                             s->rows[roffs + 1] = 
06388                                 xstrdup(d->xcelqrx ? "main" : "");
06389 #else
06390                             s->rows[roffs + 1] = xstrdup("");
06391 #endif
06392                             s->rows[roffs + 2] = xstrdup(tname);
06393                             s->rows[roffs + 3] =
06394                                 xstrdup(rowpp[m * nncols + k]);
06395                             s->rows[roffs + 5] =
06396                                 xstrdup(rowp2[i * ncols2 + namec2]);
06397                         }
06398                     } else if (strcmp(rowpp[k], "seqno") == 0) {
06399                         int m;
06400 
06401                         for (m = 1; m <= nnrows; m++) {
06402                             int roffs = offs + (m - 1) * s->ncols;
06403                             int pos = m - 1;
06404                             char buf[32];
06405 
06406                             sscanf(rowpp[m * nncols + k], "%d", &pos);
06407                             sprintf(buf, "%d", pos + 1);
06408                             s->rows[roffs + 4] = xstrdup(buf);
06409                         }
06410                     }
06411                 }
06412                 offs += nnrows * s->ncols;
06413                 sqlite3_free_table(rowpp);
06414             }
06415         }
06416     }
06417     sqlite3_free_table(rowp);
06418     sqlite3_free_table(rowp2);
06419     return SQL_SUCCESS;
06420 }
06421 
06422 #ifndef WINTERFACE
06423 
06435 SQLRETURN SQL_API
06436 SQLPrimaryKeys(SQLHSTMT stmt,
06437                SQLCHAR *cat, SQLSMALLINT catLen,
06438                SQLCHAR *schema, SQLSMALLINT schemaLen,
06439                SQLCHAR *table, SQLSMALLINT tableLen)
06440 {
06441 #if defined(_WIN32) || defined(_WIN64)
06442     char *c = NULL, *s = NULL, *t = NULL;
06443 #endif
06444     SQLRETURN ret;
06445 
06446     HSTMT_LOCK(stmt);
06447 #if defined(_WIN32) || defined(_WIN64)
06448     if (!((STMT *) stmt)->oemcp[0]) {
06449         ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
06450                              table, tableLen);
06451         goto done2;
06452     }
06453     if (cat) {
06454         c = wmb_to_utf_c((char *) cat, catLen);
06455         if (!c) {
06456             ret = nomem((STMT *) stmt);
06457             goto done;
06458         }
06459     }
06460     if (schema) {
06461         s = wmb_to_utf_c((char *) schema, schemaLen);
06462         if (!s) {
06463             ret = nomem((STMT *) stmt);
06464             goto done;
06465         }
06466     }
06467     if (table) {
06468         t = wmb_to_utf_c((char *) table, tableLen);
06469         if (!t) {
06470             ret = nomem((STMT *) stmt);
06471             goto done;
06472         }
06473     }
06474     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
06475                          (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
06476 #else
06477     ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
06478                          table, tableLen);
06479 #endif
06480 #if defined(_WIN32) || defined(_WIN64)
06481 done:
06482     uc_free(t);
06483     uc_free(s);
06484     uc_free(c);
06485 done2:
06486     ;
06487 #endif
06488     HSTMT_UNLOCK(stmt);
06489     return ret;
06490 }
06491 #endif
06492 
06493 #ifdef WINTERFACE
06494 
06506 SQLRETURN SQL_API
06507 SQLPrimaryKeysW(SQLHSTMT stmt,
06508                 SQLWCHAR *cat, SQLSMALLINT catLen,
06509                 SQLWCHAR *schema, SQLSMALLINT schemaLen,
06510                 SQLWCHAR *table, SQLSMALLINT tableLen)
06511 {
06512     char *c = NULL, *s = NULL, *t = NULL;
06513     SQLRETURN ret;
06514 
06515     HSTMT_LOCK(stmt);
06516     if (cat) {
06517         c = uc_to_utf_c(cat, catLen);
06518         if (!c) {
06519             ret = nomem((STMT *) stmt);
06520             goto done;
06521         }
06522     }
06523     if (schema) {
06524         s = uc_to_utf_c(schema, schemaLen);
06525         if (!s) {
06526             ret = nomem((STMT *) stmt);
06527             goto done;
06528         }
06529     }
06530     if (table) {
06531         t = uc_to_utf_c(table, tableLen);
06532         if (!t) {
06533             ret = nomem((STMT *) stmt);
06534             goto done;
06535         }
06536     }
06537     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
06538                          (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
06539 done:
06540     uc_free(t);
06541     uc_free(s);
06542     uc_free(c);
06543     HSTMT_UNLOCK(stmt);
06544     return ret;
06545 }
06546 #endif
06547 
06552 static COL scolSpec2[] = {
06553     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
06554     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06555     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
06556     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
06557     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
06558     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
06559     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
06560     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
06561     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
06562 };
06563 
06564 static COL scolSpec3[] = {
06565     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
06566     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06567     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
06568     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
06569     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
06570     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
06571     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
06572     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
06573     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
06574 };
06575 
06591 static SQLRETURN
06592 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
06593                   SQLCHAR *cat, SQLSMALLINT catLen,
06594                   SQLCHAR *schema, SQLSMALLINT schemaLen,
06595                   SQLCHAR *table, SQLSMALLINT tableLen,
06596                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
06597 {
06598     STMT *s;
06599     DBC *d;
06600     SQLRETURN sret;
06601     int i, asize, ret, nrows, ncols, nnnrows, nnncols, offs;
06602     PTRDIFF_T size;
06603     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
06604     int notnullcc = -1, mkrowid = 0;
06605     char *errp = NULL, *sql, tname[512];
06606     char **rowp = NULL, **rowppp = NULL;
06607 
06608     sret = mkresultset(stmt, scolSpec2, array_size(scolSpec2),
06609                        scolSpec3, array_size(scolSpec3), &asize);
06610     if (sret != SQL_SUCCESS) {
06611         return sret;
06612     }
06613     s = (STMT *) stmt;
06614     d = (DBC *) s->dbc;
06615     if (!table || table[0] == '\0' || table[0] == '%') {
06616         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
06617         return SQL_ERROR;
06618     }
06619     if (tableLen == SQL_NTS) {
06620         size = sizeof (tname) - 1;
06621     } else {
06622         size = min(sizeof (tname) - 1, tableLen);
06623     }
06624     strncpy(tname, (char *) table, size);
06625     tname[size] = '\0';
06626     unescpat(tname);
06627     if (id != SQL_BEST_ROWID) {
06628         return SQL_SUCCESS;
06629     }
06630     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
06631     if (!sql) {
06632         return nomem(s);
06633     }
06634     sret = starttran(s);
06635     if (sret != SQL_SUCCESS) {
06636         sqlite3_free(sql);
06637         return sret;
06638     }
06639     dbtraceapi(d, "sqlite3_get_table", sql);
06640     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
06641     sqlite3_free(sql);
06642     if (ret != SQLITE_OK) {
06643 doerr:
06644         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
06645                 errp ? errp : "unknown error", ret);
06646         if (errp) {
06647             sqlite3_free(errp);
06648             errp = NULL;
06649         }
06650         return SQL_ERROR;       
06651     }
06652     if (errp) {
06653         sqlite3_free(errp);
06654         errp = NULL;
06655     }
06656     size = 0; /* number result rows */
06657     if (ncols * nrows <= 0) {
06658         goto nodata_but_rowid;
06659     }
06660     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
06661     if (!sql) {
06662         return nomem(s);
06663     }
06664     dbtraceapi(d, "sqlite3_get_table", sql);
06665     ret = sqlite3_get_table(d->sqlite, sql, &rowppp, &nnnrows, &nnncols,
06666                             &errp);
06667     sqlite3_free(sql);
06668     if (ret != SQLITE_OK) {
06669         sqlite3_free_table(rowp);
06670         goto doerr;
06671     }
06672     if (errp) {
06673         sqlite3_free(errp);
06674         errp = NULL;
06675     }
06676     namec = findcol(rowp, ncols, "name");
06677     uniquec = findcol(rowp, ncols, "unique");
06678     if (namec < 0 || uniquec < 0) {
06679         goto nodata_but_rowid;
06680     }
06681     namecc = findcol(rowppp, nnncols, "name");
06682     typecc = findcol(rowppp, nnncols, "type");
06683     notnullcc = findcol(rowppp, nnncols, "notnull");
06684     for (i = 1; i <= nrows; i++) {
06685         int nnrows, nncols;
06686         char **rowpp = NULL;
06687 
06688         if (*rowp[i * ncols + uniquec] != '0') {
06689             ret = SQLITE_ERROR;
06690             sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
06691                                   rowp[i * ncols + namec]);
06692             if (sql) {
06693                 dbtraceapi(d, "sqlite3_get_table", sql);
06694                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
06695                                         &nnrows, &nncols, NULL);
06696                 sqlite3_free(sql);
06697             }
06698             if (ret == SQLITE_OK) {
06699                 size += nnrows;
06700                 sqlite3_free_table(rowpp);
06701             }
06702         }
06703     }
06704 nodata_but_rowid:
06705     if (size == 0) {
06706         size = 1;
06707         mkrowid = 1;
06708     }
06709     s->nrows = size;
06710     size = (size + 1) * asize;
06711     s->rows = xmalloc((size + 1) * sizeof (char *));
06712     if (!s->rows) {
06713         s->nrows = 0;
06714         sqlite3_free_table(rowp);
06715         sqlite3_free_table(rowppp);
06716         return nomem(s);
06717     }
06718     s->rows[0] = (char *) size;
06719     s->rows += 1;
06720     memset(s->rows, 0, sizeof (char *) * size);
06721     s->rowfree = freerows;
06722     if (mkrowid) {
06723         s->nrows = 0;
06724         goto mkrowid;
06725     }
06726     offs = 0;
06727     for (i = 1; i <= nrows; i++) {
06728         int nnrows, nncols;
06729         char **rowpp = NULL;
06730 
06731         if (*rowp[i * ncols + uniquec] != '0') {
06732             int k;
06733 
06734             ret = SQLITE_ERROR;
06735             sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
06736                                   rowp[i * ncols + namec]);
06737             if (sql) {
06738                 dbtraceapi(d, "sqlite3_get_table", sql);
06739                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
06740                                         &nnrows, &nncols, NULL);
06741                 sqlite3_free(sql);
06742             }
06743             if (ret != SQLITE_OK) {
06744                 continue;
06745             }
06746             for (k = 0; nnrows && k < nncols; k++) {
06747                 if (strcmp(rowpp[k], "name") == 0) {
06748                     int m;
06749 
06750                     for (m = 1; m <= nnrows; m++) {
06751                         int roffs = (offs + m) * s->ncols;
06752 
06753                         s->rows[roffs + 0] =
06754                             xstrdup(stringify(SQL_SCOPE_SESSION));
06755                         s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
06756                         s->rows[roffs + 4] = xstrdup("0");
06757                         s->rows[roffs + 7] =
06758                             xstrdup(stringify(SQL_PC_NOT_PSEUDO));
06759                         if (namecc >= 0 && typecc >= 0) {
06760                             int ii;
06761 
06762                             for (ii = 1; ii <= nnnrows; ii++) {
06763                                 if (strcmp(rowppp[ii * nnncols + namecc],
06764                                            rowpp[m * nncols + k]) == 0) {
06765                                     char *typen = rowppp[ii * nnncols + typecc];
06766                                     int sqltype, mm, dd, isnullable = 0;
06767                                     char buf[32];
06768                                         
06769                                     s->rows[roffs + 3] = xstrdup(typen);
06770                                     sqltype = mapsqltype(typen, NULL, *s->ov3,
06771                                                          s->nowchar[0],
06772                                                          s->dobigint);
06773                                     getmd(typen, sqltype, &mm, &dd);
06774 #ifdef SQL_LONGVARCHAR
06775                                     if (sqltype == SQL_VARCHAR && mm > 255) {
06776                                         sqltype = SQL_LONGVARCHAR;
06777                                     }
06778 #endif
06779 #ifdef WINTERFACE
06780 #ifdef SQL_WLONGVARCHAR
06781                                     if (sqltype == SQL_WVARCHAR && mm > 255) {
06782                                         sqltype = SQL_WLONGVARCHAR;
06783                                     }
06784 #endif
06785 #endif
06786                                     if (sqltype == SQL_VARBINARY && mm > 255) {
06787                                         sqltype = SQL_LONGVARBINARY;
06788                                     }
06789                                     sprintf(buf, "%d", sqltype);
06790                                     s->rows[roffs + 2] = xstrdup(buf);
06791                                     sprintf(buf, "%d", mm);
06792                                     s->rows[roffs + 5] = xstrdup(buf);
06793                                     sprintf(buf, "%d", dd);
06794                                     s->rows[roffs + 6] = xstrdup(buf);
06795                                     if (notnullcc >= 0) {
06796                                         char *inp =
06797                                            rowppp[ii * nnncols + notnullcc];
06798 
06799                                         isnullable = inp[0] != '0';
06800                                     }
06801                                     sprintf(buf, "%d", isnullable);
06802                                     s->rows[roffs + 8] = xstrdup(buf);
06803                                 }
06804                             }
06805                         }
06806                     }
06807                 }
06808             }
06809             offs += nnrows;
06810             sqlite3_free_table(rowpp);
06811         }
06812     }
06813     if (nullable == SQL_NO_NULLS) {
06814         for (i = 1; i < s->nrows; i++) {
06815             if (s->rows[i * s->ncols + 8][0] == '0') {
06816                 int m, i1 = i + 1;
06817 
06818                 for (m = 0; m < s->ncols; m++) {
06819                     freep(&s->rows[i * s->ncols + m]);
06820                 }
06821                 size = s->ncols * sizeof (char *) * (s->nrows - i1);
06822                 if (size > 0) {
06823                     memmove(s->rows + i * s->ncols,
06824                             s->rows + i1 * s->ncols,
06825                             size);
06826                     memset(s->rows + s->nrows * s->ncols, 0,
06827                            s->ncols * sizeof (char *));
06828                 }
06829                 s->nrows--;
06830                 --i;
06831             }
06832         }
06833     }
06834 mkrowid:
06835     sqlite3_free_table(rowp);
06836     sqlite3_free_table(rowppp);
06837     if (s->nrows == 0) {
06838         s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
06839         s->rows[s->ncols + 1] = xstrdup("_ROWID_");
06840         s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
06841         s->rows[s->ncols + 3] = xstrdup("integer");
06842         s->rows[s->ncols + 4] = xstrdup("0");
06843         s->rows[s->ncols + 5] = xstrdup("10");
06844         s->rows[s->ncols + 6] = xstrdup("9");
06845         s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
06846         s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
06847         s->nrows = 1;
06848     }
06849     return SQL_SUCCESS;
06850 }
06851 
06852 #ifndef WINTERFACE
06853 
06868 SQLRETURN SQL_API
06869 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
06870                   SQLCHAR *cat, SQLSMALLINT catLen,
06871                   SQLCHAR *schema, SQLSMALLINT schemaLen,
06872                   SQLCHAR *table, SQLSMALLINT tableLen,
06873                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
06874 {
06875 #if defined(_WIN32) || defined(_WIN64)
06876     char *c = NULL, *s = NULL, *t = NULL;
06877 #endif
06878     SQLRETURN ret;
06879 
06880     HSTMT_LOCK(stmt);
06881 #if defined(_WIN32) || defined(_WIN64)
06882     if (!((STMT *) stmt)->oemcp[0]) {
06883         ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
06884                                 table, tableLen, scope, nullable);
06885         goto done2;
06886     }
06887     if (cat) {
06888         c = wmb_to_utf_c((char *) cat, catLen);
06889         if (!c) {
06890             ret = nomem((STMT *) stmt);
06891             goto done;
06892         }
06893     }
06894     if (schema) {
06895         s = wmb_to_utf_c((char *) schema, schemaLen);
06896         if (!s) {
06897             ret = nomem((STMT *) stmt);
06898             goto done;
06899         }
06900     }
06901     if (table) {
06902         t = wmb_to_utf_c((char *) table, tableLen);
06903         if (!t) {
06904             ret = nomem((STMT *) stmt);
06905             goto done;
06906         }
06907     }
06908     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
06909                             (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
06910                             scope, nullable);
06911 #else
06912     ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
06913                             table, tableLen, scope, nullable);
06914 #endif
06915 #if defined(_WIN32) || defined(_WIN64)
06916 done:
06917     uc_free(t);
06918     uc_free(s);
06919     uc_free(c);
06920 done2:
06921     ;
06922 #endif
06923     HSTMT_UNLOCK(stmt);
06924     return ret;
06925 }
06926 #endif
06927 
06928 #ifdef WINTERFACE
06929 
06944 SQLRETURN SQL_API
06945 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
06946                    SQLWCHAR *cat, SQLSMALLINT catLen,
06947                    SQLWCHAR *schema, SQLSMALLINT schemaLen,
06948                    SQLWCHAR *table, SQLSMALLINT tableLen,
06949                    SQLUSMALLINT scope, SQLUSMALLINT nullable)
06950 {
06951     char *c = NULL, *s = NULL, *t = NULL;
06952     SQLRETURN ret;
06953 
06954     HSTMT_LOCK(stmt);
06955     if (cat) {
06956         c = uc_to_utf_c(cat, catLen);
06957         if (!c) {
06958             ret = nomem((STMT *) stmt);
06959             goto done;
06960         }
06961     }
06962     if (schema) {
06963         s = uc_to_utf_c(schema, schemaLen);
06964         if (!s) {
06965             ret = nomem((STMT *) stmt);
06966             goto done;
06967         }
06968     }
06969     if (table) {
06970         t = uc_to_utf_c(table, tableLen);
06971         if (!t) {
06972             ret = nomem((STMT *) stmt);
06973             goto done;
06974         }
06975     }
06976     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
06977                             (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
06978                             scope, nullable);
06979 done:
06980     uc_free(t);
06981     uc_free(s);
06982     uc_free(c);
06983     HSTMT_UNLOCK(stmt);
06984     return ret;
06985 }
06986 #endif
06987 
06992 static COL fkeySpec2[] = {
06993     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
06994     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
06995     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
06996     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
06997     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
06998     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
06999     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
07000     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
07001     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
07002     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
07003     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
07004     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
07005     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
07006     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
07007 };
07008 
07009 static COL fkeySpec3[] = {
07010     { "SYSTEM", "FOREIGNKEY", "PKTABLE_CAT", SCOL_VARCHAR, 50 },
07011     { "SYSTEM", "FOREIGNKEY", "PKTABLE_SCHEM", SCOL_VARCHAR, 50 },
07012     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
07013     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
07014     { "SYSTEM", "FOREIGNKEY", "FKTABLE_CAT", SCOL_VARCHAR, 50 },
07015     { "SYSTEM", "FOREIGNKEY", "FKTABLE_SCHEM", SCOL_VARCHAR, 50 },
07016     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
07017     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
07018     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
07019     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
07020     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
07021     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
07022     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
07023     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
07024 };
07025 
07044 static SQLRETURN SQL_API
07045 drvforeignkeys(SQLHSTMT stmt,
07046                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
07047                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
07048                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
07049                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
07050                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
07051                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
07052 {
07053     STMT *s;
07054     DBC *d;
07055     SQLRETURN sret;
07056     int i, asize, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
07057     int onu, ond;
07058     PTRDIFF_T size;
07059     char **rowp, *errp = NULL, *sql, pname[512], fname[512];
07060 
07061     sret = mkresultset(stmt, fkeySpec2, array_size(fkeySpec2),
07062                        fkeySpec3, array_size(fkeySpec3), &asize);
07063     if (sret != SQL_SUCCESS) {
07064         return sret;
07065     }
07066     s = (STMT *) stmt;
07067     sret = starttran(s);
07068     if (sret != SQL_SUCCESS) {
07069         return sret;
07070     }
07071     d = (DBC *) s->dbc;
07072     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
07073         (!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
07074         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
07075         return SQL_ERROR;
07076     }
07077     size = 0;
07078     if (PKtable) {
07079         if (PKtableLen == SQL_NTS) {
07080             size = sizeof (pname) - 1;
07081         } else {
07082             size = min(sizeof (pname) - 1, PKtableLen);
07083         }
07084         strncpy(pname, (char *) PKtable, size);
07085     }
07086     pname[size] = '\0';
07087     size = 0;
07088     if (FKtable) {
07089 
07090         if (FKtableLen == SQL_NTS) {
07091             size = sizeof (fname) - 1;
07092         } else {
07093             size = min(sizeof (fname) - 1, FKtableLen);
07094         }
07095         strncpy(fname, (char *) FKtable, size);
07096     }
07097     fname[size] = '\0';
07098     if (fname[0] != '\0') {
07099         int plen;
07100 
07101         ret = SQLITE_ERROR;
07102         sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", fname);
07103         if (sql) {
07104             dbtraceapi(d, "sqlite3_get_table", sql);
07105             ret = sqlite3_get_table(d->sqlite, sql, &rowp,
07106                                     &nrows, &ncols, &errp);
07107             sqlite3_free(sql);
07108         }
07109         if (ret != SQLITE_OK) {
07110             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
07111                     errp ? errp : "unknown error", ret);
07112             if (errp) {
07113                 sqlite3_free(errp);
07114                 errp = NULL;
07115             }
07116             return SQL_ERROR;
07117         }
07118         if (errp) {
07119             sqlite3_free(errp);
07120             errp = NULL;
07121         }
07122         if (ncols * nrows <= 0) {
07123 nodata:
07124             sqlite3_free_table(rowp);
07125             return SQL_SUCCESS;
07126         }
07127         size = 0;
07128         namec = findcol(rowp, ncols, "table");
07129         seqc = findcol(rowp, ncols, "seq");
07130         fromc = findcol(rowp, ncols, "from");
07131         toc = findcol(rowp, ncols, "to");
07132         onu = findcol(rowp, ncols, "on_update");
07133         ond = findcol(rowp, ncols, "on_delete");
07134         if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
07135             goto nodata;
07136         }
07137         plen = strlen(pname);
07138         for (i = 1; i <= nrows; i++) {
07139             char *ptab = unquote(rowp[i * ncols + namec]);
07140 
07141             if (plen && ptab) {
07142                 int len = strlen(ptab);
07143 
07144                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
07145                     continue;
07146                 }
07147             }
07148             size++;
07149         }
07150         if (size == 0) {
07151             goto nodata;
07152         }
07153         s->nrows = size;
07154         size = (size + 1) * asize;
07155         s->rows = xmalloc((size + 1) * sizeof (char *));
07156         if (!s->rows) {
07157             s->nrows = 0;
07158             return nomem(s);
07159         }
07160         s->rows[0] = (char *) size;
07161         s->rows += 1;
07162         memset(s->rows, 0, sizeof (char *) * size);
07163         s->rowfree = freerows;
07164         offs = 0;
07165         for (i = 1; i <= nrows; i++) {
07166             int pos = 0, roffs = (offs + 1) * s->ncols;
07167             char *ptab = rowp[i * ncols + namec];
07168             char buf[32];
07169 
07170             if (plen && ptab) {
07171                 int len = strlen(ptab);
07172 
07173                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
07174                     continue;
07175                 }
07176             }
07177             s->rows[roffs + 0] = xstrdup("");
07178 #if defined(_WIN32) || defined(_WIN64)
07179             s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
07180 #else
07181             s->rows[roffs + 1] = xstrdup("");
07182 #endif
07183             s->rows[roffs + 2] = xstrdup(ptab);
07184             s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
07185             s->rows[roffs + 4] = xstrdup("");
07186             s->rows[roffs + 5] = xstrdup("");
07187             s->rows[roffs + 6] = xstrdup(fname);
07188             s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
07189             sscanf(rowp[i * ncols + seqc], "%d", &pos);
07190             sprintf(buf, "%d", pos + 1);
07191             s->rows[roffs + 8] = xstrdup(buf);
07192             if (onu < 0) {
07193                 s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
07194             } else {
07195                 if (strcmp(rowp[i * ncols + onu], "SET NULL") == 0) {
07196                     s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
07197                 } else if (strcmp(rowp[i * ncols + onu], "SET DEFAULT") == 0) {
07198                     s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_DEFAULT));
07199                 } else if (strcmp(rowp[i * ncols + onu], "CASCADE") == 0) {
07200                     s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
07201                 } else if (strcmp(rowp[i * ncols + onu], "RESTRICT") == 0) {
07202                     s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
07203                 } else {
07204                     s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
07205                 }
07206             }
07207             if (ond < 0) {
07208                 s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
07209             } else {
07210                 if (strcmp(rowp[i * ncols + ond], "SET NULL") == 0) {
07211                     s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
07212                 } else if (strcmp(rowp[i * ncols + ond], "SET DEFAULT") == 0) {
07213                     s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_DEFAULT));
07214                 } else if (strcmp(rowp[i * ncols + ond], "CASCADE") == 0) {
07215                     s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
07216                 } else if (strcmp(rowp[i * ncols + ond], "RESTRICT") == 0) {
07217                     s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
07218                 } else {
07219                     s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
07220                 }
07221             }
07222             s->rows[roffs + 11] = NULL;
07223             s->rows[roffs + 12] = NULL;
07224             s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
07225             offs++;
07226         }
07227         sqlite3_free_table(rowp);
07228     } else {
07229         int nnrows, nncols, plen = strlen(pname);
07230         char **rowpp;
07231 
07232         sql = "select name from sqlite_master where type='table'";
07233         dbtraceapi(d, "sqlite3_get_table", sql);
07234         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
07235         if (ret != SQLITE_OK) {
07236             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
07237                     errp ? errp : "unknown error", ret);
07238             if (errp) {
07239                 sqlite3_free(errp);
07240                 errp = NULL;
07241             }
07242             return SQL_ERROR;
07243         }
07244         if (errp) {
07245             sqlite3_free(errp);
07246             errp = NULL;
07247         }
07248         if (ncols * nrows <= 0) {
07249             goto nodata;
07250         }
07251         size = 0;
07252         for (i = 1; i <= nrows; i++) {
07253             int k;
07254 
07255             if (!rowp[i]) {
07256                 continue;
07257             }
07258             rowpp = NULL;
07259             ret = SQLITE_ERROR;
07260             sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
07261             if (sql) {
07262                 dbtraceapi(d, "sqlite3_get_table", sql);
07263                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
07264                                       &nnrows, &nncols, NULL);
07265                 sqlite3_free(sql);
07266             }
07267             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
07268                 sqlite3_free_table(rowpp);
07269                 continue;
07270             }
07271             namec = findcol(rowpp, nncols, "table");
07272             seqc = findcol(rowpp, nncols, "seq");
07273             fromc = findcol(rowpp, nncols, "from");
07274             toc = findcol(rowpp, nncols, "to");
07275             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
07276                 sqlite3_free_table(rowpp);
07277                 continue;
07278             }
07279             for (k = 1; k <= nnrows; k++) {
07280                 char *ptab = unquote(rowpp[k * nncols + namec]);
07281 
07282                 if (plen && ptab) {
07283                     int len = strlen(ptab);
07284 
07285                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
07286                         continue;
07287                     }
07288                 }
07289                 size++;
07290             }
07291             sqlite3_free_table(rowpp);
07292         }
07293         if (size == 0) {
07294             goto nodata;
07295         }
07296         s->nrows = size;
07297         size = (size + 1) * asize;
07298         s->rows = xmalloc((size + 1) * sizeof (char *));
07299         if (!s->rows) {
07300             s->nrows = 0;
07301             return nomem(s);
07302         }
07303         s->rows[0] = (char *) size;
07304         s->rows += 1;
07305         memset(s->rows, 0, sizeof (char *) * size);
07306         s->rowfree = freerows;
07307         offs = 0;
07308         for (i = 1; i <= nrows; i++) {
07309             int k;
07310 
07311             if (!rowp[i]) {
07312                 continue;
07313             }
07314             rowpp = NULL;
07315             ret = SQLITE_ERROR;
07316             sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
07317             if (sql) {
07318                 dbtraceapi(d, "sqlite3_get_table", sql);
07319                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
07320                                         &nnrows, &nncols, NULL);
07321                 sqlite3_free(sql);
07322             }
07323             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
07324                 sqlite3_free_table(rowpp);
07325                 continue;
07326             }
07327             namec = findcol(rowpp, nncols, "table");
07328             seqc = findcol(rowpp, nncols, "seq");
07329             fromc = findcol(rowpp, nncols, "from");
07330             toc = findcol(rowpp, nncols, "to");
07331             onu = findcol(rowpp, nncols, "on_update");
07332             ond = findcol(rowpp, nncols, "on_delete");
07333             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
07334                 sqlite3_free_table(rowpp);
07335                 continue;
07336             }
07337             for (k = 1; k <= nnrows; k++) {
07338                 int pos = 0, roffs = (offs + 1) * s->ncols;
07339                 char *ptab = unquote(rowpp[k * nncols + namec]);
07340                 char buf[32];
07341 
07342                 if (plen && ptab) {
07343                     int len = strlen(ptab);
07344 
07345                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
07346                         continue;
07347                     }
07348                 }
07349                 s->rows[roffs + 0] = xstrdup("");
07350 #if defined(_WIN32) || defined(_WIN64)
07351                 s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
07352 #else
07353                 s->rows[roffs + 1] = xstrdup("");
07354 #endif
07355                 s->rows[roffs + 2] = xstrdup(ptab);
07356                 s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
07357                 s->rows[roffs + 4] = xstrdup("");
07358                 s->rows[roffs + 5] = xstrdup("");
07359                 s->rows[roffs + 6] = xstrdup(rowp[i]);
07360                 s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
07361                 sscanf(rowpp[k * nncols + seqc], "%d", &pos);
07362                 sprintf(buf, "%d", pos + 1);
07363                 s->rows[roffs + 8] = xstrdup(buf);
07364                 if (onu < 0) {
07365                     s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
07366                 } else {
07367                     if (strcmp(rowpp[k * nncols + onu], "SET NULL") == 0) {
07368                         s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
07369                     } else if (strcmp(rowpp[k * nncols + onu], "SET DEFAULT")
07370                                == 0) {
07371                         s->rows[roffs + 9] =
07372                             xstrdup(stringify(SQL_SET_DEFAULT));
07373                     } else if (strcmp(rowpp[k * nncols + onu], "CASCADE")
07374                                == 0) {
07375                         s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
07376                     } else if (strcmp(rowpp[k * nncols + onu], "RESTRICT")
07377                                == 0) {
07378                         s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
07379                     } else {
07380                         s->rows[roffs + 9] =
07381                             xstrdup(stringify(SQL_NO_ACTION));
07382                     }
07383                 }
07384                 if (ond < 0) {
07385                     s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
07386                 } else {
07387                     if (strcmp(rowpp[k * nncols + ond], "SET NULL") == 0) {
07388                         s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
07389                     } else if (strcmp(rowpp[k * nncols + ond], "SET DEFAULT")
07390                                == 0) {
07391                         s->rows[roffs + 10] =
07392                             xstrdup(stringify(SQL_SET_DEFAULT));
07393                     } else if (strcmp(rowpp[k * nncols + ond], "CASCADE")
07394                                == 0) {
07395                         s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
07396                     } else if (strcmp(rowpp[k * nncols + ond], "RESTRICT")
07397                                == 0) {
07398                         s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
07399                     } else {
07400                         s->rows[roffs + 10] =
07401                             xstrdup(stringify(SQL_NO_ACTION));
07402                     }
07403                 }
07404                 s->rows[roffs + 11] = NULL;
07405                 s->rows[roffs + 12] = NULL;
07406                 s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
07407                 offs++;
07408             }
07409             sqlite3_free_table(rowpp);
07410         }
07411         sqlite3_free_table(rowp);
07412     }
07413     return SQL_SUCCESS;
07414 }
07415 
07416 #ifndef WINTERFACE
07417 
07435 SQLRETURN SQL_API
07436 SQLForeignKeys(SQLHSTMT stmt,
07437                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
07438                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
07439                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
07440                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
07441                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
07442                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
07443 {
07444 #if defined(_WIN32) || defined(_WIN64)
07445     char *pc = NULL, *ps = NULL, *pt = NULL;
07446     char *fc = NULL, *fs = NULL, *ft = NULL;
07447 #endif
07448     SQLRETURN ret;
07449 
07450     HSTMT_LOCK(stmt);
07451 #if defined(_WIN32) || defined(_WIN64)
07452     if (!((STMT *) stmt)->oemcp[0]) {
07453         ret = drvforeignkeys(stmt,
07454                              PKcatalog, PKcatalogLen,
07455                              PKschema, PKschemaLen, PKtable, PKtableLen,
07456                              FKcatalog, FKcatalogLen,
07457                              FKschema, FKschemaLen,
07458                              FKtable, FKtableLen);
07459         goto done2;
07460     }
07461     if (PKcatalog) {
07462         pc = wmb_to_utf_c((char *) PKcatalog, PKcatalogLen);
07463         if (!pc) {
07464             ret = nomem((STMT *) stmt);
07465             goto done;
07466         }
07467     }
07468     if (PKschema) {
07469         ps = wmb_to_utf_c((char *) PKschema, PKschemaLen);
07470         if (!ps) {
07471             ret = nomem((STMT *) stmt);
07472             goto done;
07473         }
07474     }
07475     if (PKtable) {
07476         pt = wmb_to_utf_c((char *) PKtable, PKtableLen);
07477         if (!pt) {
07478             ret = nomem((STMT *) stmt);
07479             goto done;
07480         }
07481     }
07482     if (FKcatalog) {
07483         fc = wmb_to_utf_c((char *) FKcatalog, FKcatalogLen);
07484         if (!fc) {
07485             ret = nomem((STMT *) stmt);
07486             goto done;
07487         }
07488     }
07489     if (FKschema) {
07490         fs = wmb_to_utf_c((char *) FKschema, FKschemaLen);
07491         if (!fs) {
07492             ret = nomem((STMT *) stmt);
07493             goto done;
07494         }
07495     }
07496     if (FKtable) {
07497         ft = wmb_to_utf_c((char *) FKtable, FKtableLen);
07498         if (!ft) {
07499             ret = nomem((STMT *) stmt);
07500             goto done;
07501         }
07502     }
07503     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
07504                          (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
07505                          (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
07506                          (SQLCHAR *) ft, SQL_NTS);
07507 #else
07508     ret = drvforeignkeys(stmt,
07509                          PKcatalog, PKcatalogLen,
07510                          PKschema, PKschemaLen, PKtable, PKtableLen,
07511                          FKcatalog, FKcatalogLen,
07512                          FKschema, FKschemaLen,
07513                          FKtable, FKtableLen);
07514 #endif
07515 #if defined(_WIN32) || defined(_WIN64)
07516 done:
07517     uc_free(ft);
07518     uc_free(fs);
07519     uc_free(fc);
07520     uc_free(pt);
07521     uc_free(ps);
07522     uc_free(pc);
07523 done2:
07524     ;
07525 #endif
07526     HSTMT_UNLOCK(stmt);
07527     return ret;
07528 }
07529 #endif
07530 
07531 #ifdef WINTERFACE
07532 
07550 SQLRETURN SQL_API
07551 SQLForeignKeysW(SQLHSTMT stmt,
07552                 SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
07553                 SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
07554                 SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
07555                 SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
07556                 SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
07557                 SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
07558 {
07559     char *pc = NULL, *ps = NULL, *pt = NULL;
07560     char *fc = NULL, *fs = NULL, *ft = NULL;
07561     SQLRETURN ret;
07562 
07563     HSTMT_LOCK(stmt);
07564     if (PKcatalog) {
07565         pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
07566         if (!pc) {
07567             ret = nomem((STMT *) stmt);
07568             goto done;
07569         }
07570     }
07571     if (PKschema) {
07572         ps = uc_to_utf_c(PKschema, PKschemaLen);
07573         if (!ps) {
07574             ret = nomem((STMT *) stmt);
07575             goto done;
07576         }
07577     }
07578     if (PKtable) {
07579         pt = uc_to_utf_c(PKtable, PKtableLen);
07580         if (!pt) {
07581             ret = nomem((STMT *) stmt);
07582             goto done;
07583         }
07584     }
07585     if (FKcatalog) {
07586         fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
07587         if (!fc) {
07588             ret = nomem((STMT *) stmt);
07589             goto done;
07590         }
07591     }
07592     if (FKschema) {
07593         fs = uc_to_utf_c(FKschema, FKschemaLen);
07594         if (!fs) {
07595             ret = nomem((STMT *) stmt);
07596             goto done;
07597         }
07598     }
07599     if (FKtable) {
07600         ft = uc_to_utf_c(FKtable, FKtableLen);
07601         if (!ft) {
07602             ret = nomem((STMT *) stmt);
07603             goto done;
07604         }
07605     }
07606     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
07607                          (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
07608                          (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
07609                          (SQLCHAR *) ft, SQL_NTS);
07610 done:
07611     uc_free(ft);
07612     uc_free(fs);
07613     uc_free(fc);
07614     uc_free(pt);
07615     uc_free(ps);
07616     uc_free(pc);
07617     HSTMT_UNLOCK(stmt);
07618     return ret;
07619 }
07620 #endif
07621 
07628 static SQLRETURN
07629 starttran(STMT *s)
07630 {
07631     int ret = SQL_SUCCESS, rc, busy_count = 0;
07632     char *errp = NULL;
07633     DBC *d = (DBC *) s->dbc;
07634 
07635     if (!d->autocommit && !d->intrans && !d->trans_disable) {
07636 begin_again:
07637         rc = sqlite3_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL, &errp);
07638         if (rc == SQLITE_BUSY) {
07639             if (busy_handler((void *) d, ++busy_count)) {
07640                 if (errp) {
07641                     sqlite3_free(errp);
07642                     errp = NULL;
07643                 }
07644                 goto begin_again;
07645             }
07646         }
07647         dbtracerc(d, rc, errp);
07648         if (rc != SQLITE_OK) {
07649             setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
07650                     errp ? errp : "unknown error", rc);
07651             ret = SQL_ERROR;
07652         } else {
07653             d->intrans = 1;
07654         }
07655         if (errp) {
07656             sqlite3_free(errp);
07657             errp = NULL;
07658         }
07659     }
07660     return ret;
07661 }
07662 
07671 static SQLRETURN
07672 endtran(DBC *d, SQLSMALLINT comptype, int force)
07673 {
07674     int ret, busy_count = 0;
07675     char *sql, *errp = NULL;
07676 
07677     if (!d->sqlite) {
07678         setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
07679         return SQL_ERROR;
07680     }
07681     if ((!force && d->autocommit) || !d->intrans) {
07682         return SQL_SUCCESS;
07683     }
07684     switch (comptype) {
07685     case SQL_COMMIT:
07686         sql = "COMMIT TRANSACTION";
07687         goto doit;
07688     case SQL_ROLLBACK:
07689         sql = "ROLLBACK TRANSACTION";
07690     doit:
07691         ret = sqlite3_exec(d->sqlite, sql, NULL, NULL, &errp);
07692         dbtracerc(d, ret, errp);
07693         if (ret == SQLITE_BUSY && busy_count < 10) {
07694             if (busy_handler((void *) d, ++busy_count)) {
07695                 if (errp) {
07696                     sqlite3_free(errp);
07697                     errp = NULL;
07698                 }
07699                 goto doit;
07700             }
07701         }
07702         d->intrans = 0;
07703         if (ret != SQLITE_OK) {
07704             setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
07705                      errp ? errp : "transaction failed");
07706             if (errp) {
07707                 sqlite3_free(errp);
07708                 errp = NULL;
07709             }
07710             return SQL_ERROR;
07711         }
07712         if (errp) {
07713             sqlite3_free(errp);
07714             errp = NULL;
07715         }
07716         return SQL_SUCCESS;
07717     }
07718     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
07719     return SQL_ERROR;
07720 }
07721 
07730 static SQLRETURN
07731 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
07732 {
07733     DBC *d;
07734     int fail = 0;
07735     SQLRETURN ret;
07736 #if defined(_WIN32) || defined(_WIN64)
07737     ENV *e;
07738 #endif
07739 
07740     switch (type) {
07741     case SQL_HANDLE_DBC:
07742         HDBC_LOCK((SQLHDBC) handle);
07743         if (handle == SQL_NULL_HDBC) {
07744             return SQL_INVALID_HANDLE;
07745         }
07746         d = (DBC *) handle;
07747         ret = endtran(d, comptype, 0);
07748         HDBC_UNLOCK((SQLHDBC) handle);
07749         return ret;
07750     case SQL_HANDLE_ENV:
07751         if (handle == SQL_NULL_HENV) {
07752             return SQL_INVALID_HANDLE;
07753         }
07754 #if defined(_WIN32) || defined(_WIN64)
07755         e = (ENV *) handle;
07756         if (e->magic != ENV_MAGIC) {
07757             return SQL_INVALID_HANDLE;
07758         }
07759         EnterCriticalSection(&e->cs);
07760         e->owner = GetCurrentThreadId();
07761 #endif
07762         d = ((ENV *) handle)->dbcs;
07763         while (d) {
07764             ret = endtran(d, comptype, 0);
07765             if (ret != SQL_SUCCESS) {
07766                 fail++;
07767             }
07768             d = d->next;
07769         }
07770 #if defined(_WIN32) || defined(_WIN64)
07771         e->owner = 0;
07772         LeaveCriticalSection(&e->cs);
07773 #endif
07774         return fail ? SQL_ERROR : SQL_SUCCESS;
07775     }
07776     return SQL_INVALID_HANDLE;
07777 }
07778 
07787 SQLRETURN SQL_API
07788 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
07789 {
07790     return drvendtran(type, handle, comptype);
07791 }
07792 
07801 SQLRETURN SQL_API
07802 SQLTransact(SQLHENV env, SQLHDBC dbc, SQLUSMALLINT type)
07803 {
07804     if (env != SQL_NULL_HENV) {
07805         return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
07806     }
07807     return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
07808 }
07809 
07814 SQLRETURN SQL_API
07815 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
07816 {
07817     return SQL_ERROR;
07818 }
07819 
07820 #ifndef WINTERFACE
07821 
07832 SQLRETURN SQL_API
07833 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
07834              SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
07835 {
07836     int outLen = 0;
07837     SQLRETURN ret = SQL_SUCCESS;
07838 
07839     HSTMT_LOCK(stmt);
07840     if (sqlinLen == SQL_NTS) {
07841         sqlinLen = strlen((char *) sqlin);
07842     }
07843     if (sql) {
07844         if (sqlMax > 0) {
07845             strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
07846             sqlin[sqlMax - 1] = '\0';
07847             outLen = min(sqlMax - 1, sqlinLen);
07848         }
07849     } else {
07850         outLen = sqlinLen;
07851     }
07852     if (sqlLen) {
07853         *sqlLen = outLen;
07854     }
07855     if (sql && outLen < sqlinLen) {
07856         setstat((STMT *) stmt, -1, "data right truncated", "01004");
07857         ret = SQL_SUCCESS_WITH_INFO;
07858     }
07859     HSTMT_UNLOCK(stmt);
07860     return ret;
07861 }
07862 #endif
07863 
07864 #ifdef WINTERFACE
07865 
07876 SQLRETURN SQL_API
07877 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
07878               SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
07879 {
07880     int outLen = 0;
07881     SQLRETURN ret = SQL_SUCCESS;
07882 
07883     HSTMT_LOCK(stmt);
07884     if (sqlinLen == SQL_NTS) {
07885         sqlinLen = uc_strlen(sqlin);
07886     }
07887     if (sql) {
07888         if (sqlMax > 0) {
07889             uc_strncpy(sql, sqlin, sqlMax - 1);
07890             sqlin[sqlMax - 1] = 0;
07891             outLen = min(sqlMax  - 1, sqlinLen);
07892         }
07893     } else {
07894         outLen = sqlinLen;
07895     }
07896     if (sqlLen) {
07897         *sqlLen = outLen;
07898     }
07899     if (sql && outLen < sqlinLen) {
07900         setstat((STMT *) stmt, -1, "data right truncated", "01004");
07901         ret = SQL_SUCCESS_WITH_INFO;
07902     }
07903     HSTMT_UNLOCK(stmt);
07904     return ret;
07905 }
07906 #endif
07907 
07912 static COL procSpec2[] = {
07913     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
07914     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
07915     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
07916     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
07917     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
07918     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
07919     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
07920     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
07921 };
07922 
07923 static COL procSpec3[] = {
07924     { "SYSTEM", "PROCEDURE", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
07925     { "SYSTEM", "PROCEDURE", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
07926     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
07927     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
07928     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
07929     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
07930     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
07931     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
07932 };
07933 
07934 #ifndef WINTERFACE
07935 
07947 SQLRETURN SQL_API
07948 SQLProcedures(SQLHSTMT stmt,
07949               SQLCHAR *catalog, SQLSMALLINT catalogLen,
07950               SQLCHAR *schema, SQLSMALLINT schemaLen,
07951               SQLCHAR *proc, SQLSMALLINT procLen)
07952 {
07953     SQLRETURN ret;
07954 
07955     HSTMT_LOCK(stmt);
07956     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
07957                       procSpec3, array_size(procSpec3), NULL);
07958     HSTMT_UNLOCK(stmt);
07959     return ret;
07960 }
07961 #endif
07962 
07963 #ifdef WINTERFACE
07964 
07976 SQLRETURN SQL_API
07977 SQLProceduresW(SQLHSTMT stmt,
07978                SQLWCHAR *catalog, SQLSMALLINT catalogLen,
07979                SQLWCHAR *schema, SQLSMALLINT schemaLen,
07980                SQLWCHAR *proc, SQLSMALLINT procLen)
07981 {
07982     SQLRETURN ret;
07983 
07984     HSTMT_LOCK(stmt);
07985     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
07986                       procSpec3, array_size(procSpec3), NULL);
07987     HSTMT_UNLOCK(stmt);
07988     return ret;
07989 }
07990 #endif
07991 
07996 static COL procColSpec2[] = {
07997     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
07998     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
07999     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
08000     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
08001     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
08002     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
08003     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
08004     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
08005     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
08006     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
08007     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
08008     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
08009     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
08010     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
08011     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
08012     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
08013     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
08014     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
08015     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
08016 };
08017 
08018 static COL procColSpec3[] = {
08019     { "SYSTEM", "PROCCOL", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
08020     { "SYSTEM", "PROCCOL", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
08021     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
08022     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
08023     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
08024     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
08025     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
08026     { "SYSTEM", "PROCCOL", "COLUMN_SIZE", SQL_INTEGER, 10 },
08027     { "SYSTEM", "PROCCOL", "BUFFER_LENGTH", SQL_INTEGER, 10 },
08028     { "SYSTEM", "PROCCOL", "DECIMAL_DIGITS", SQL_SMALLINT, 5 },
08029     { "SYSTEM", "PROCCOL", "NUM_PREC_RADIX", SQL_SMALLINT, 5 },
08030     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
08031     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
08032     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
08033     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
08034     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
08035     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
08036     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
08037     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
08038 };
08039 
08040 #ifndef WINTERFACE
08041 
08055 SQLRETURN SQL_API
08056 SQLProcedureColumns(SQLHSTMT stmt,
08057                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
08058                     SQLCHAR *schema, SQLSMALLINT schemaLen,
08059                     SQLCHAR *proc, SQLSMALLINT procLen,
08060                     SQLCHAR *column, SQLSMALLINT columnLen)
08061 {
08062     SQLRETURN ret;
08063 
08064     HSTMT_LOCK(stmt);
08065     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
08066                       procColSpec3, array_size(procColSpec3), NULL);
08067     HSTMT_UNLOCK(stmt);
08068     return ret;
08069 }
08070 #endif
08071 
08072 #ifdef WINTERFACE
08073 
08088 SQLRETURN SQL_API
08089 SQLProcedureColumnsW(SQLHSTMT stmt,
08090                      SQLWCHAR *catalog, SQLSMALLINT catalogLen,
08091                      SQLWCHAR *schema, SQLSMALLINT schemaLen,
08092                      SQLWCHAR *proc, SQLSMALLINT procLen,
08093                      SQLWCHAR *column, SQLSMALLINT columnLen)
08094 {
08095     SQLRETURN ret;
08096 
08097     HSTMT_LOCK(stmt);
08098     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
08099                       procColSpec3, array_size(procColSpec3), NULL);
08100     HSTMT_UNLOCK(stmt);
08101     return ret;
08102 }
08103 #endif
08104 
08115 SQLRETURN SQL_API
08116 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
08117               SQLINTEGER len, SQLINTEGER *lenp)
08118 {
08119     ENV *e;
08120     SQLRETURN ret = SQL_ERROR;
08121 
08122     if (env == SQL_NULL_HENV) {
08123         return SQL_INVALID_HANDLE;
08124     }
08125     e = (ENV *) env;
08126     if (!e || e->magic != ENV_MAGIC) {
08127         return SQL_INVALID_HANDLE;
08128     }
08129 #if defined(_WIN32) || defined(_WIN64)
08130     EnterCriticalSection(&e->cs);
08131     e->owner = GetCurrentThreadId();
08132 #endif
08133     switch (attr) {
08134     case SQL_ATTR_CONNECTION_POOLING:
08135         ret = SQL_ERROR;
08136         break;
08137     case SQL_ATTR_CP_MATCH:
08138         ret = SQL_NO_DATA;
08139         break;
08140     case SQL_ATTR_OUTPUT_NTS:
08141         if (val) {
08142             *((SQLINTEGER *) val) = SQL_TRUE;
08143         }
08144         if (lenp) {
08145             *lenp = sizeof (SQLINTEGER);
08146         }
08147         ret = SQL_SUCCESS;
08148         break;
08149     case SQL_ATTR_ODBC_VERSION:
08150         if (val) {
08151             *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
08152         }
08153         if (lenp) {
08154             *lenp = sizeof (SQLINTEGER);
08155         }
08156         ret = SQL_SUCCESS;
08157         break;
08158     }
08159 #if defined(_WIN32) || defined(_WIN64)
08160     e->owner = 0;
08161     LeaveCriticalSection(&e->cs);
08162 #endif
08163     return ret;
08164 }
08165 
08175 SQLRETURN SQL_API
08176 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
08177 {
08178     ENV *e;
08179     SQLRETURN ret = SQL_ERROR;
08180 
08181     if (env == SQL_NULL_HENV) {
08182         return SQL_INVALID_HANDLE;
08183     }
08184     e = (ENV *) env;
08185     if (!e || e->magic != ENV_MAGIC) {
08186         return SQL_INVALID_HANDLE;
08187     }
08188 #if defined(_WIN32) || defined(_WIN64)
08189     EnterCriticalSection(&e->cs);
08190     e->owner = GetCurrentThreadId();
08191 #endif
08192     switch (attr) {
08193     case SQL_ATTR_CONNECTION_POOLING:
08194         ret = SQL_SUCCESS;
08195         break;
08196     case SQL_ATTR_CP_MATCH:
08197         ret = SQL_NO_DATA;
08198         break;
08199     case SQL_ATTR_OUTPUT_NTS:
08200         if (val == (SQLPOINTER) SQL_TRUE) {
08201             ret = SQL_SUCCESS;
08202         }
08203         break;
08204     case SQL_ATTR_ODBC_VERSION:
08205         if (!val) {
08206             break;
08207         }
08208         if (val == (SQLPOINTER) SQL_OV_ODBC2) {
08209             e->ov3 = 0;
08210             ret = SQL_SUCCESS;
08211         }
08212         if (val == (SQLPOINTER) SQL_OV_ODBC3) {
08213             e->ov3 = 1;
08214             ret = SQL_SUCCESS;
08215         }
08216         break;
08217     }
08218 #if defined(_WIN32) || defined(_WIN64)
08219     e->owner = 0;
08220     LeaveCriticalSection(&e->cs);
08221 #endif
08222     return ret;
08223 }
08224 
08238 static SQLRETURN
08239 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
08240               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
08241               SQLSMALLINT buflen, SQLSMALLINT *msglen)
08242 {
08243     DBC *d = NULL;
08244     STMT *s = NULL;
08245     int len, naterr;
08246     char *logmsg, *sqlst;
08247     SQLRETURN ret = SQL_ERROR;
08248 
08249     if (handle == SQL_NULL_HANDLE) {
08250         return SQL_INVALID_HANDLE;
08251     }
08252     if (sqlstate) {
08253         sqlstate[0] = '\0';
08254     }
08255     if (msg && buflen > 0) {
08256         msg[0] = '\0';
08257     }
08258     if (msglen) {
08259         *msglen = 0;
08260     }
08261     if (nativeerr) {
08262         *nativeerr = 0;
08263     }
08264     switch (htype) {
08265     case SQL_HANDLE_ENV:
08266     case SQL_HANDLE_DESC:
08267         return SQL_NO_DATA;
08268     case SQL_HANDLE_DBC:
08269         HDBC_LOCK((SQLHDBC) handle);
08270         d = (DBC *) handle;
08271         logmsg = (char *) d->logmsg;
08272         sqlst = d->sqlstate;
08273         naterr = d->naterr;
08274         break;
08275     case SQL_HANDLE_STMT:
08276         HSTMT_LOCK((SQLHSTMT) handle);
08277         s = (STMT *) handle;
08278         logmsg = (char *) s->logmsg;
08279         sqlst = s->sqlstate;
08280         naterr = s->naterr;
08281         break;
08282     default:
08283         return SQL_INVALID_HANDLE;
08284     }
08285     if (buflen < 0) {
08286         goto done;
08287     }
08288     if (recno > 1) {
08289         ret = SQL_NO_DATA;
08290         goto done;
08291     }
08292     len = strlen(logmsg);
08293     if (len == 0) {
08294         ret = SQL_NO_DATA;
08295         goto done;
08296     }
08297     if (nativeerr) {
08298         *nativeerr = naterr;
08299     }
08300     if (sqlstate) {
08301         strcpy((char *) sqlstate, sqlst);
08302     }
08303     if (msglen) {
08304         *msglen = len;
08305     }
08306     if (len >= buflen) {
08307         if (msg && buflen > 0) {
08308             strncpy((char *) msg, logmsg, buflen);
08309             msg[buflen - 1] = '\0';
08310             logmsg[0] = '\0';
08311         }
08312     } else if (msg) {
08313         strcpy((char *) msg, logmsg);
08314         logmsg[0] = '\0';
08315     }
08316     ret = SQL_SUCCESS;
08317 done:
08318     switch (htype) {
08319     case SQL_HANDLE_DBC:
08320         HDBC_UNLOCK((SQLHDBC) handle);
08321         break;
08322     case SQL_HANDLE_STMT:
08323         HSTMT_UNLOCK((SQLHSTMT) handle);
08324         break;
08325     }
08326     return ret;
08327 }
08328 
08329 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
08330 
08343 SQLRETURN SQL_API
08344 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
08345               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
08346               SQLSMALLINT buflen, SQLSMALLINT *msglen)
08347 {
08348     return drvgetdiagrec(htype, handle, recno, sqlstate,
08349                          nativeerr, msg, buflen, msglen);
08350 }
08351 #endif
08352 
08353 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
08354 #ifdef WINTERFACE
08355 
08369 SQLRETURN SQL_API
08370 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
08371               SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
08372               SQLSMALLINT buflen, SQLSMALLINT *msglen)
08373 {
08374     char state[16];
08375     SQLSMALLINT len;
08376     SQLRETURN ret;
08377     
08378     ret = drvgetdiagrec(htype, handle, recno, (SQLCHAR *) state,
08379                         nativeerr, (SQLCHAR *) msg, buflen, &len);
08380     if (ret == SQL_SUCCESS) {
08381         if (sqlstate) {
08382             uc_from_utf_buf((SQLCHAR *) state, -1, sqlstate,
08383                             6 * sizeof (SQLWCHAR));
08384         }
08385         if (msg) {
08386             if (len > 0) {
08387                 SQLWCHAR *m = NULL;
08388 
08389                 m = uc_from_utf((unsigned char *) msg, len);
08390                 if (m) {
08391                     if (buflen) {
08392                         buflen /= sizeof (SQLWCHAR);
08393                         uc_strncpy(msg, m, buflen);
08394                         m[len] = 0;
08395                         len = min(buflen, uc_strlen(m));
08396                     } else {
08397                         len = uc_strlen(m);
08398                     }
08399                     uc_free(m);
08400                 } else {
08401                     len = 0;
08402                 }
08403             }
08404             if (len <= 0) {
08405                 len = 0;
08406                 if (buflen > 0) {
08407                     msg[0] = 0;
08408                 }
08409             }
08410         } else {
08411             /* estimated length !!! */
08412             len *= sizeof (SQLWCHAR);
08413         }
08414         if (msglen) {
08415             *msglen = len;
08416         }
08417     } else if (ret == SQL_NO_DATA) {
08418         if (sqlstate) {
08419             sqlstate[0] = 0;
08420         }
08421         if (msg) {
08422             if (buflen > 0) {
08423                 msg[0] = 0;
08424             }
08425         }
08426         if (msglen) {
08427             *msglen = 0;
08428         }
08429     }
08430     return ret;
08431 }
08432 #endif
08433 #endif
08434 
08447 static SQLRETURN
08448 drvgetdiagfield(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
08449                 SQLSMALLINT id, SQLPOINTER info, 
08450                 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
08451 {
08452     DBC *d = NULL;
08453     STMT *s = NULL;
08454     int len, naterr, strbuf = 1;
08455     char *logmsg, *sqlst, *clrmsg = NULL;
08456     SQLRETURN ret = SQL_ERROR;
08457 
08458     if (handle == SQL_NULL_HANDLE) {
08459         return SQL_INVALID_HANDLE;
08460     }
08461     if (stringlen) {
08462         *stringlen = 0;
08463     }
08464     switch (htype) {
08465     case SQL_HANDLE_ENV:
08466     case SQL_HANDLE_DESC:
08467         return SQL_NO_DATA;
08468     case SQL_HANDLE_DBC:
08469         HDBC_LOCK((SQLHDBC) handle);
08470         d = (DBC *) handle;
08471         logmsg = (char *) d->logmsg;
08472         sqlst = d->sqlstate;
08473         naterr = d->naterr;
08474         break;
08475     case SQL_HANDLE_STMT:
08476         HSTMT_LOCK((SQLHSTMT) handle);
08477         s = (STMT *) handle;
08478         d = (DBC *) s->dbc;
08479         logmsg = (char *) s->logmsg;
08480         sqlst = s->sqlstate;
08481         naterr = s->naterr;
08482         break;
08483     default:
08484         return SQL_INVALID_HANDLE;
08485     }
08486     if (buflen < 0) {
08487         switch (buflen) {
08488         case SQL_IS_POINTER:
08489         case SQL_IS_UINTEGER:
08490         case SQL_IS_INTEGER:
08491         case SQL_IS_USMALLINT:
08492         case SQL_IS_SMALLINT:
08493             strbuf = 0;
08494             break;
08495         default:
08496             ret = SQL_ERROR;
08497             goto done;
08498         }
08499     }
08500     if (recno > 1) {
08501         ret = SQL_NO_DATA;
08502         goto done;
08503     }
08504     switch (id) {
08505     case SQL_DIAG_CLASS_ORIGIN:
08506         logmsg = "ISO 9075";
08507         if (sqlst[0] == 'I' && sqlst[1] == 'M') {
08508             logmsg = "ODBC 3.0";
08509         }
08510         break;
08511     case SQL_DIAG_SUBCLASS_ORIGIN:
08512         logmsg = "ISO 9075";
08513         if (sqlst[0] == 'I' && sqlst[1] == 'M') {
08514             logmsg = "ODBC 3.0";
08515         } else if (sqlst[0] == 'H' && sqlst[1] == 'Y') {
08516             logmsg = "ODBC 3.0";
08517         } else if (sqlst[0] == '2' || sqlst[0] == '0' || sqlst[0] == '4') {
08518             logmsg = "ODBC 3.0";
08519         }
08520         break;
08521     case SQL_DIAG_CONNECTION_NAME:
08522     case SQL_DIAG_SERVER_NAME:
08523         logmsg = d->dsn ? d->dsn : "No DSN";
08524         break;
08525     case SQL_DIAG_SQLSTATE:
08526         logmsg = sqlst;
08527         break;
08528     case SQL_DIAG_MESSAGE_TEXT:
08529         if (info) {
08530             clrmsg = logmsg;
08531         }
08532         break;
08533     case SQL_DIAG_NUMBER:
08534         naterr = 1;
08535         /* fall through */
08536     case SQL_DIAG_NATIVE:
08537         len = strlen(logmsg);
08538         if (len == 0) {
08539             ret = SQL_NO_DATA;
08540             goto done;
08541         }
08542         if (info) {
08543             *((SQLINTEGER *) info) = naterr;
08544         }
08545         ret = SQL_SUCCESS;
08546         goto done;
08547     case SQL_DIAG_DYNAMIC_FUNCTION:
08548         logmsg = "";
08549         break;
08550     case SQL_DIAG_CURSOR_ROW_COUNT:
08551         if (htype == SQL_HANDLE_STMT) {
08552             SQLULEN count;
08553 
08554             count = (s->isselect == 1 || s->isselect == -1) ? s->nrows : 0;
08555             *((SQLULEN *) info) = count;
08556             ret = SQL_SUCCESS;
08557         }
08558         goto done;
08559     case SQL_DIAG_ROW_COUNT:
08560         if (htype == SQL_HANDLE_STMT) {
08561             SQLULEN count;
08562 
08563             count = s->isselect ? 0 : s->nrows;
08564             *((SQLULEN *) info) = count;
08565             ret = SQL_SUCCESS;
08566         }
08567         goto done;
08568     default:
08569         goto done;
08570     }
08571     if (info && buflen > 0) {
08572         ((char *) info)[0] = '\0';
08573     }
08574     len = strlen(logmsg);
08575     if (len == 0) {
08576         ret = SQL_NO_DATA;
08577         goto done;
08578     }
08579     if (stringlen) {
08580         *stringlen = len;
08581     }
08582     if (strbuf) {
08583         if (len >= buflen) {
08584             if (info && buflen > 0) {
08585                 if (stringlen) {
08586                     *stringlen = buflen - 1;
08587                 }
08588                 strncpy((char *) info, logmsg, buflen);
08589                 ((char *) info)[buflen - 1] = '\0';
08590             }
08591         } else if (info) {
08592             strcpy((char *) info, logmsg);
08593         }
08594     }
08595     if (clrmsg) {
08596         *clrmsg = '\0';
08597     }
08598     ret = SQL_SUCCESS;
08599 done:
08600     switch (htype) {
08601     case SQL_HANDLE_DBC:
08602         HDBC_UNLOCK((SQLHDBC) handle);
08603         break;
08604     case SQL_HANDLE_STMT:
08605         HSTMT_UNLOCK((SQLHSTMT) handle);
08606         break;
08607     }
08608     return ret;
08609 }
08610 
08611 #ifndef WINTERFACE
08612 
08624 SQLRETURN SQL_API
08625 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
08626                 SQLSMALLINT id, SQLPOINTER info, 
08627                 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
08628 {
08629     return drvgetdiagfield(htype, handle, recno, id, info, buflen, stringlen);
08630 }
08631 #endif
08632 
08633 #ifdef WINTERFACE
08634 
08646 SQLRETURN SQL_API
08647 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
08648                  SQLSMALLINT id, SQLPOINTER info, 
08649                  SQLSMALLINT buflen, SQLSMALLINT *stringlen)
08650 {
08651     SQLSMALLINT len;
08652     SQLRETURN ret;
08653     
08654     ret = drvgetdiagfield(htype, handle, recno, id, info, buflen, &len);
08655     if (ret == SQL_SUCCESS) {
08656         if (info) {
08657             switch (id) {
08658             case SQL_DIAG_CLASS_ORIGIN:
08659             case SQL_DIAG_SUBCLASS_ORIGIN:
08660             case SQL_DIAG_CONNECTION_NAME:
08661             case SQL_DIAG_SERVER_NAME:
08662             case SQL_DIAG_SQLSTATE:
08663             case SQL_DIAG_MESSAGE_TEXT:
08664             case SQL_DIAG_DYNAMIC_FUNCTION:
08665                 if (len > 0) {
08666                     SQLWCHAR *m = NULL;
08667 
08668                     m = uc_from_utf((unsigned char *) info, len);
08669                     if (m) {
08670                         if (buflen) {
08671                             buflen /= sizeof (SQLWCHAR);
08672                             uc_strncpy(info, m, buflen);
08673                             m[len] = 0;
08674                             len = min(buflen, uc_strlen(m));
08675                         } else {
08676                             len = uc_strlen(m);
08677                         }
08678                         uc_free(m);
08679                         len *= sizeof (SQLWCHAR);
08680                     } else {
08681                         len = 0;
08682                     }
08683                 }
08684                 if (len <= 0) {
08685                     len = 0;
08686                     if (buflen > 0) {
08687                         ((SQLWCHAR *) info)[0] = 0;
08688                     }
08689                 }
08690             }
08691         } else {
08692             switch (id) {
08693             case SQL_DIAG_CLASS_ORIGIN:
08694             case SQL_DIAG_SUBCLASS_ORIGIN:
08695             case SQL_DIAG_CONNECTION_NAME:
08696             case SQL_DIAG_SERVER_NAME:
08697             case SQL_DIAG_SQLSTATE:
08698             case SQL_DIAG_MESSAGE_TEXT:
08699             case SQL_DIAG_DYNAMIC_FUNCTION:
08700                 len *= sizeof (SQLWCHAR);
08701                 break;
08702             }
08703         }
08704         if (stringlen) {
08705             *stringlen = len;
08706         }
08707     }
08708     return ret;
08709 }
08710 #endif
08711 
08722 static SQLRETURN
08723 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
08724                SQLINTEGER bufmax, SQLINTEGER *buflen)
08725 {
08726     STMT *s = (STMT *) stmt;
08727     SQLULEN *uval = (SQLULEN *) val;
08728 
08729     switch (attr) {
08730     case SQL_QUERY_TIMEOUT:
08731         *uval = 0;
08732         return SQL_SUCCESS;
08733     case SQL_ATTR_CURSOR_TYPE:
08734         *uval = s->curtype;
08735         return SQL_SUCCESS;
08736     case SQL_ATTR_CURSOR_SCROLLABLE:
08737         *uval = (s->curtype != SQL_CURSOR_FORWARD_ONLY) ?
08738             SQL_SCROLLABLE : SQL_NONSCROLLABLE;
08739         return SQL_SUCCESS;
08740 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
08741     case SQL_ATTR_CURSOR_SENSITIVITY:
08742         *uval = SQL_UNSPECIFIED;
08743         return SQL_SUCCESS;
08744 #endif
08745     case SQL_ATTR_ROW_NUMBER:
08746         if (s->s3stmt) {
08747             *uval = (s->s3stmt_rownum < 0) ?
08748                     SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
08749         } else {
08750             *uval = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
08751         }
08752         return SQL_SUCCESS;
08753     case SQL_ATTR_ASYNC_ENABLE:
08754         *uval = SQL_ASYNC_ENABLE_OFF;
08755         return SQL_SUCCESS;
08756     case SQL_CONCURRENCY:
08757         *uval = SQL_CONCUR_LOCK;
08758         return SQL_SUCCESS;
08759     case SQL_ATTR_RETRIEVE_DATA:
08760         *uval = s->retr_data;
08761         return SQL_SUCCESS;
08762     case SQL_ROWSET_SIZE:
08763     case SQL_ATTR_ROW_ARRAY_SIZE:
08764         *uval = s->rowset_size;
08765         return SQL_SUCCESS;
08766     /* Needed for some driver managers, but dummies for now */
08767     case SQL_ATTR_IMP_ROW_DESC:
08768     case SQL_ATTR_APP_ROW_DESC:
08769     case SQL_ATTR_IMP_PARAM_DESC:
08770     case SQL_ATTR_APP_PARAM_DESC:
08771         *((SQLHDESC *) val) = (SQLHDESC) DEAD_MAGIC;
08772         return SQL_SUCCESS;
08773     case SQL_ATTR_ROW_STATUS_PTR:
08774         *((SQLUSMALLINT **) val) = s->row_status;
08775         return SQL_SUCCESS;
08776     case SQL_ATTR_ROWS_FETCHED_PTR:
08777         *((SQLULEN **) val) = s->row_count;
08778         return SQL_SUCCESS;
08779     case SQL_ATTR_USE_BOOKMARKS: {
08780         STMT *s = (STMT *) stmt;
08781 
08782         *(SQLUINTEGER *) val = s->bkmrk ? SQL_UB_ON : SQL_UB_OFF;
08783         return SQL_SUCCESS;
08784     }
08785     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
08786         *((SQLULEN **) val) = s->parm_bind_offs;
08787         return SQL_SUCCESS;
08788     case SQL_ATTR_PARAM_BIND_TYPE:
08789         *((SQLULEN *) val) = s->parm_bind_type;
08790         return SQL_SUCCESS;
08791     case SQL_ATTR_PARAM_OPERATION_PTR:
08792         *((SQLUSMALLINT **) val) = s->parm_oper;
08793         return SQL_SUCCESS;
08794     case SQL_ATTR_PARAM_STATUS_PTR:
08795         *((SQLUSMALLINT **) val) = s->parm_status;
08796         return SQL_SUCCESS;
08797     case SQL_ATTR_PARAMS_PROCESSED_PTR:
08798         *((SQLULEN **) val) = s->parm_proc;
08799         return SQL_SUCCESS;
08800     case SQL_ATTR_PARAMSET_SIZE:
08801         *((SQLULEN *) val) = s->paramset_size;
08802         return SQL_SUCCESS;
08803     case SQL_ATTR_ROW_BIND_TYPE:
08804         *(SQLULEN *) val = s->bind_type;
08805         return SQL_SUCCESS;
08806     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
08807         *((SQLULEN **) val) = s->bind_offs;
08808         return SQL_SUCCESS;
08809     case SQL_ATTR_MAX_ROWS:
08810         *((SQLULEN *) val) = s->max_rows;
08811     case SQL_ATTR_MAX_LENGTH:
08812         *((SQLINTEGER *) val) = 1000000000;
08813         return SQL_SUCCESS;
08814 #ifdef SQL_ATTR_METADATA_ID
08815     case SQL_ATTR_METADATA_ID:
08816         *((SQLULEN *) val) = SQL_FALSE;
08817         return SQL_SUCCESS;
08818 #endif
08819     }
08820     return drvunimplstmt(stmt);
08821 }
08822 
08823 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
08824 
08834 SQLRETURN SQL_API
08835 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
08836                SQLINTEGER bufmax, SQLINTEGER *buflen)
08837 {
08838     SQLRETURN ret;
08839 
08840     HSTMT_LOCK(stmt);
08841     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
08842     HSTMT_UNLOCK(stmt);
08843     return ret;
08844 }
08845 #endif
08846 
08847 #ifdef WINTERFACE
08848 
08858 SQLRETURN SQL_API
08859 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
08860                 SQLINTEGER bufmax, SQLINTEGER *buflen)
08861 {
08862     SQLRETURN ret;
08863 
08864     HSTMT_LOCK(stmt);
08865     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
08866     HSTMT_UNLOCK(stmt);
08867     return ret;
08868 }
08869 #endif
08870 
08880 static SQLRETURN
08881 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
08882                SQLINTEGER buflen)
08883 {
08884     STMT *s = (STMT *) stmt;
08885 #if defined(SQL_BIGINT) && defined(__WORDSIZE) && (__WORDSIZE == 64)
08886     SQLBIGINT uval;
08887 
08888     uval = (SQLBIGINT) val;
08889 #else
08890     SQLULEN uval;
08891 
08892     uval = (SQLULEN) val;
08893 #endif
08894     switch (attr) {
08895     case SQL_ATTR_CURSOR_TYPE:
08896         if (val == (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY) {
08897             s->curtype = SQL_CURSOR_FORWARD_ONLY;
08898         } else {
08899             s->curtype = SQL_CURSOR_STATIC;
08900         }
08901         if (val != (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY &&
08902             val != (SQLPOINTER) SQL_CURSOR_STATIC) {
08903             goto e01s02;
08904         }
08905         return SQL_SUCCESS;
08906     case SQL_ATTR_CURSOR_SCROLLABLE:
08907         if (val == (SQLPOINTER) SQL_NONSCROLLABLE) {
08908             s->curtype = SQL_CURSOR_FORWARD_ONLY;
08909         } else {
08910             s->curtype = SQL_CURSOR_STATIC;
08911         }
08912         return SQL_SUCCESS;
08913     case SQL_ATTR_ASYNC_ENABLE:
08914         if (val != (SQLPOINTER) SQL_ASYNC_ENABLE_OFF) {
08915     e01s02:
08916             setstat(s, -1, "option value changed", "01S02");
08917             return SQL_SUCCESS_WITH_INFO;
08918         }
08919         return SQL_SUCCESS;
08920     case SQL_CONCURRENCY:
08921         if (val != (SQLPOINTER) SQL_CONCUR_LOCK) {
08922             goto e01s02;
08923         }
08924         return SQL_SUCCESS;
08925 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
08926     case SQL_ATTR_CURSOR_SENSITIVITY:
08927         if (val != (SQLPOINTER) SQL_UNSPECIFIED) {
08928             goto e01s02;
08929         }
08930         return SQL_SUCCESS;
08931 #endif
08932     case SQL_ATTR_QUERY_TIMEOUT:
08933         return SQL_SUCCESS;
08934     case SQL_ATTR_RETRIEVE_DATA:
08935         if (val != (SQLPOINTER) SQL_RD_ON &&
08936             val != (SQLPOINTER) SQL_RD_OFF) {
08937             goto e01s02;
08938         }
08939         s->retr_data = uval;
08940         return SQL_SUCCESS;
08941     case SQL_ROWSET_SIZE:
08942     case SQL_ATTR_ROW_ARRAY_SIZE:
08943         if (uval < 1) {
08944             setstat(s, -1, "invalid rowset size", "HY000");
08945             return SQL_ERROR;
08946         } else {
08947             SQLUSMALLINT *rst = &s->row_status1;
08948 
08949             if (uval > 1) {
08950                 rst = xmalloc(sizeof (SQLUSMALLINT) * uval);
08951                 if (!rst) {
08952                     return nomem(s);
08953                 }
08954             }
08955             if (s->row_status0 != &s->row_status1) {
08956                 freep(&s->row_status0);
08957             }
08958             s->row_status0 = rst;
08959             s->rowset_size = uval;
08960         }
08961         return SQL_SUCCESS;
08962     case SQL_ATTR_ROW_STATUS_PTR:
08963         s->row_status = (SQLUSMALLINT *) val;
08964         return SQL_SUCCESS;
08965     case SQL_ATTR_ROWS_FETCHED_PTR:
08966         s->row_count = (SQLULEN *) val;
08967         return SQL_SUCCESS;
08968     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
08969         s->parm_bind_offs = (SQLULEN *) val;
08970         return SQL_SUCCESS;
08971     case SQL_ATTR_PARAM_BIND_TYPE:
08972         s->parm_bind_type = uval;
08973         return SQL_SUCCESS;
08974     case SQL_ATTR_PARAM_OPERATION_PTR:
08975         s->parm_oper = (SQLUSMALLINT *) val;
08976         return SQL_SUCCESS;
08977     case SQL_ATTR_PARAM_STATUS_PTR:
08978         s->parm_status = (SQLUSMALLINT *) val;
08979         return SQL_SUCCESS;
08980     case SQL_ATTR_PARAMS_PROCESSED_PTR:
08981         s->parm_proc = (SQLULEN *) val;
08982         return SQL_SUCCESS;
08983     case SQL_ATTR_PARAMSET_SIZE:
08984         if (uval < 1) {
08985             goto e01s02;
08986         }
08987         s->paramset_size = uval;
08988         s->paramset_count = 0;
08989         return SQL_SUCCESS;
08990     case SQL_ATTR_ROW_BIND_TYPE:
08991         s->bind_type = uval;
08992         return SQL_SUCCESS;
08993     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
08994         s->bind_offs = (SQLULEN *) val;
08995         return SQL_SUCCESS;
08996     case SQL_ATTR_USE_BOOKMARKS:
08997         if (val != (SQLPOINTER) SQL_UB_OFF &&
08998             val != (SQLPOINTER) SQL_UB_ON) {
08999             goto e01s02;
09000         }
09001         s->bkmrk = val == (SQLPOINTER) SQL_UB_ON;
09002         return SQL_SUCCESS;
09003     case SQL_ATTR_MAX_ROWS:
09004         s->max_rows = uval;
09005         return SQL_SUCCESS;
09006     case SQL_ATTR_MAX_LENGTH:
09007         if (val != (SQLPOINTER) 1000000000) {
09008             goto e01s02;
09009         }
09010         return SQL_SUCCESS;
09011 #ifdef SQL_ATTR_METADATA_ID
09012     case SQL_ATTR_METADATA_ID:
09013         if (val != (SQLPOINTER) SQL_FALSE) {
09014             goto e01s02;
09015         }
09016         return SQL_SUCCESS;
09017 #endif
09018     }
09019     return drvunimplstmt(stmt);
09020 }
09021 
09022 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
09023 
09032 SQLRETURN SQL_API
09033 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
09034                SQLINTEGER buflen)
09035 {
09036     SQLRETURN ret;
09037 
09038     HSTMT_LOCK(stmt);
09039     ret = drvsetstmtattr(stmt, attr, val, buflen);
09040     HSTMT_UNLOCK(stmt);
09041     return ret;
09042 }
09043 #endif
09044 
09045 #ifdef WINTERFACE
09046 
09055 SQLRETURN SQL_API
09056 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
09057                 SQLINTEGER buflen)
09058 {
09059     SQLRETURN ret;
09060 
09061     HSTMT_LOCK(stmt);
09062     ret = drvsetstmtattr(stmt, attr, val, buflen);
09063     HSTMT_UNLOCK(stmt);
09064     return ret;
09065 }
09066 #endif
09067 
09076 static SQLRETURN
09077 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
09078 {
09079     STMT *s = (STMT *) stmt;
09080     SQLUINTEGER *ret = (SQLUINTEGER *) param;
09081 
09082     switch (opt) {
09083     case SQL_QUERY_TIMEOUT:
09084         *ret = 0;
09085         return SQL_SUCCESS;
09086     case SQL_CURSOR_TYPE:
09087         *ret = s->curtype;
09088         return SQL_SUCCESS;
09089     case SQL_ROW_NUMBER:
09090         if (s->s3stmt) {
09091             *ret = (s->s3stmt_rownum < 0) ?
09092                    SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
09093         } else {
09094             *ret = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
09095         }
09096         return SQL_SUCCESS;
09097     case SQL_ASYNC_ENABLE:
09098         *ret = SQL_ASYNC_ENABLE_OFF;
09099         return SQL_SUCCESS;
09100     case SQL_CONCURRENCY:
09101         *ret = SQL_CONCUR_LOCK;
09102         return SQL_SUCCESS;
09103     case SQL_ATTR_RETRIEVE_DATA:
09104         *ret = s->retr_data;
09105         return SQL_SUCCESS;
09106     case SQL_ROWSET_SIZE:
09107     case SQL_ATTR_ROW_ARRAY_SIZE:
09108         *ret = s->rowset_size;
09109         return SQL_SUCCESS;
09110     case SQL_ATTR_MAX_ROWS:
09111         *ret = s->max_rows;
09112         return SQL_SUCCESS;
09113     case SQL_ATTR_MAX_LENGTH:
09114         *ret = 1000000000;
09115         return SQL_SUCCESS;
09116     }
09117     return drvunimplstmt(stmt);
09118 }
09119 
09128 SQLRETURN SQL_API
09129 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
09130 {
09131     SQLRETURN ret;
09132 
09133     HSTMT_LOCK(stmt);
09134     ret = drvgetstmtoption(stmt, opt, param);
09135     HSTMT_UNLOCK(stmt);
09136     return ret;
09137 }
09138 
09139 #ifdef WINTERFACE
09140 
09148 SQLRETURN SQL_API
09149 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
09150 {
09151     SQLRETURN ret;
09152 
09153     HSTMT_LOCK(stmt);
09154     ret = drvgetstmtoption(stmt, opt, param);
09155     HSTMT_UNLOCK(stmt);
09156     return ret;
09157 }
09158 #endif
09159 
09168 static SQLRETURN
09169 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
09170 {
09171     STMT *s = (STMT *) stmt;
09172 
09173     switch (opt) {
09174     case SQL_CURSOR_TYPE:
09175         if (param == SQL_CURSOR_FORWARD_ONLY) {
09176             s->curtype = param;
09177         } else {
09178             s->curtype = SQL_CURSOR_STATIC;
09179         }
09180         if (param != SQL_CURSOR_FORWARD_ONLY &&
09181             param != SQL_CURSOR_STATIC) {
09182             goto e01s02;
09183         }
09184         return SQL_SUCCESS;
09185     case SQL_ASYNC_ENABLE:
09186         if (param != SQL_ASYNC_ENABLE_OFF) {
09187             goto e01s02;
09188         }
09189         return SQL_SUCCESS;
09190     case SQL_CONCURRENCY:
09191         if (param != SQL_CONCUR_LOCK) {
09192             goto e01s02;
09193         }
09194         return SQL_SUCCESS;
09195     case SQL_QUERY_TIMEOUT:
09196         return SQL_SUCCESS;
09197     case SQL_RETRIEVE_DATA:
09198         if (param != SQL_RD_ON && param != SQL_RD_OFF) {
09199     e01s02:
09200             setstat(s, -1, "option value changed", "01S02");
09201             return SQL_SUCCESS_WITH_INFO;
09202         }
09203         s->retr_data = (int) param;
09204         return SQL_SUCCESS;
09205     case SQL_ROWSET_SIZE:
09206     case SQL_ATTR_ROW_ARRAY_SIZE:
09207         if (param < 1) {
09208             setstat(s, -1, "invalid rowset size", "HY000");
09209             return SQL_ERROR;
09210         } else {
09211             SQLUSMALLINT *rst = &s->row_status1;
09212 
09213             if (param > 1) {
09214                 rst = xmalloc(sizeof (SQLUSMALLINT) * param);
09215                 if (!rst) {
09216                     return nomem(s);
09217                 }
09218             }
09219             if (s->row_status0 != &s->row_status1) {
09220                 freep(&s->row_status0);
09221             }
09222             s->row_status0 = rst;
09223             s->rowset_size = param;
09224         }
09225         return SQL_SUCCESS;
09226     case SQL_ATTR_MAX_ROWS:
09227         s->max_rows = param;
09228         return SQL_SUCCESS;
09229     case SQL_ATTR_MAX_LENGTH:
09230         if (param != 1000000000) {
09231             goto e01s02;
09232         }
09233         return SQL_SUCCESS;
09234     }
09235     return drvunimplstmt(stmt);
09236 }
09237 
09246 SQLRETURN SQL_API
09247 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt,
09248                  SETSTMTOPTION_LAST_ARG_TYPE param)
09249 {
09250     SQLRETURN ret;
09251 
09252     HSTMT_LOCK(stmt);
09253     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
09254     HSTMT_UNLOCK(stmt);
09255     return ret;
09256 }
09257 
09258 #ifdef WINTERFACE
09259 
09267 SQLRETURN SQL_API
09268 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt,
09269                   SETSTMTOPTION_LAST_ARG_TYPE param)
09270 {
09271     SQLRETURN ret;
09272 
09273     HSTMT_LOCK(stmt);
09274     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
09275     HSTMT_UNLOCK(stmt);
09276     return ret;
09277 }
09278 #endif
09279 
09289 static SQLRETURN
09290 drvsetpos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
09291 {
09292     STMT *s = (STMT *) stmt;
09293     int rowp;
09294 
09295     if (op != SQL_POSITION) {
09296         return drvunimplstmt(stmt);
09297     }
09298     rowp = s->rowp + row - 1;
09299     if (!s->rows || row <= 0 || rowp < -1 || rowp >= s->nrows) {
09300         setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
09301         return SQL_ERROR;
09302     }
09303     s->rowp = rowp;
09304     return SQL_SUCCESS;
09305 }
09306 
09316 SQLRETURN SQL_API
09317 SQLSetPos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
09318 {
09319     SQLRETURN ret;
09320 
09321     HSTMT_LOCK(stmt);
09322     ret = drvsetpos(stmt, row, op, lock);
09323     HSTMT_UNLOCK(stmt);
09324     return ret;
09325 }
09326 
09331 SQLRETURN SQL_API
09332 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
09333                     SQLUSMALLINT rowset)
09334 {
09335     SQLRETURN ret;
09336 
09337     HSTMT_LOCK(stmt);
09338     ret = drvunimplstmt(stmt);
09339     HSTMT_UNLOCK(stmt);
09340     return ret;
09341 }
09342 
09343 #define strmak(dst, src, max, lenp) { \
09344     int len = strlen(src); \
09345     int cnt = min(len + 1, max); \
09346     strncpy(dst, src, cnt); \
09347     *lenp = (cnt > len) ? len : cnt; \
09348 }
09349 
09360 static SQLRETURN
09361 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
09362            SQLSMALLINT *valLen)
09363 {
09364     DBC *d;
09365     char dummyc[16];
09366     SQLSMALLINT dummy;
09367 #if defined(_WIN32) || defined(_WIN64)
09368     char pathbuf[301], *drvname;
09369 #else
09370     static char drvname[] = "sqlite3odbc.so";
09371 #endif
09372 
09373     if (dbc == SQL_NULL_HDBC) {
09374         return SQL_INVALID_HANDLE;
09375     }
09376     d = (DBC *) dbc;
09377     if (valMax) {
09378         valMax--;
09379     }
09380     if (!valLen) {
09381         valLen = &dummy;
09382     }
09383     if (!val) {
09384         val = dummyc;
09385         valMax = sizeof (dummyc) - 1;
09386     }
09387     switch (type) {
09388     case SQL_MAX_USER_NAME_LEN:
09389         *((SQLSMALLINT *) val) = 16;
09390         *valLen = sizeof (SQLSMALLINT);
09391         break;
09392     case SQL_USER_NAME:
09393         strmak(val, "", valMax, valLen);
09394         break;
09395     case SQL_DRIVER_ODBC_VER:
09396 #if 0
09397         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
09398 #else
09399         strmak(val, "03.00", valMax, valLen);
09400 #endif
09401         break;
09402     case SQL_ACTIVE_CONNECTIONS:
09403     case SQL_ACTIVE_STATEMENTS:
09404         *((SQLSMALLINT *) val) = 0;
09405         *valLen = sizeof (SQLSMALLINT);
09406         break;
09407 #ifdef SQL_ASYNC_MODE
09408     case SQL_ASYNC_MODE:
09409         *((SQLUINTEGER *) val) = SQL_AM_NONE;
09410         *valLen = sizeof (SQLUINTEGER);
09411         break;
09412 #endif
09413 #ifdef SQL_CREATE_TABLE
09414     case SQL_CREATE_TABLE:
09415         *((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
09416                                  SQL_CT_COLUMN_DEFAULT |
09417                                  SQL_CT_COLUMN_CONSTRAINT |
09418                                  SQL_CT_CONSTRAINT_NON_DEFERRABLE;
09419         *valLen = sizeof (SQLUINTEGER);
09420         break;
09421 #endif
09422 #ifdef SQL_CREATE_VIEW
09423     case SQL_CREATE_VIEW:
09424         *((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
09425         *valLen = sizeof (SQLUINTEGER);
09426         break;
09427 #endif
09428 #ifdef SQL_DDL_INDEX
09429     case SQL_DDL_INDEX:
09430         *((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
09431         *valLen = sizeof (SQLUINTEGER);
09432         break;
09433 #endif
09434 #ifdef SQL_DROP_TABLE
09435     case SQL_DROP_TABLE:
09436         *((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
09437         *valLen = sizeof (SQLUINTEGER);
09438         break;
09439 #endif
09440 #ifdef SQL_DROP_VIEW
09441     case SQL_DROP_VIEW:
09442         *((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
09443         *valLen = sizeof (SQLUINTEGER);
09444         break;
09445 #endif
09446 #ifdef SQL_INDEX_KEYWORDS
09447     case SQL_INDEX_KEYWORDS:
09448         *((SQLUINTEGER *) val) = SQL_IK_ALL;
09449         *valLen = sizeof (SQLUINTEGER);
09450         break;
09451 #endif
09452     case SQL_DATA_SOURCE_NAME:
09453         strmak(val, d->dsn ? d->dsn : "", valMax, valLen);
09454         break;
09455     case SQL_DRIVER_NAME:
09456 #if defined(_WIN32) || defined(_WIN64)
09457         GetModuleFileName(hModule, pathbuf, sizeof (pathbuf));
09458         drvname = strrchr(pathbuf, '\\');
09459         if (drvname == NULL) {
09460             drvname = strrchr(pathbuf, '/');
09461         }
09462         if (drvname == NULL) {
09463             drvname = pathbuf;
09464         } else {
09465             drvname++;
09466         }
09467 #endif
09468         strmak(val, drvname, valMax, valLen);
09469         break;
09470     case SQL_DRIVER_VER:
09471         strmak(val, DRIVER_VER_INFO, valMax, valLen);
09472         break;
09473     case SQL_FETCH_DIRECTION:
09474         *((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
09475             SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
09476         *valLen = sizeof (SQLUINTEGER);
09477         break;
09478     case SQL_ODBC_VER:
09479         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
09480         break;
09481     case SQL_ODBC_SAG_CLI_CONFORMANCE:
09482         *((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
09483         *valLen = sizeof (SQLSMALLINT);
09484         break;
09485     case SQL_STANDARD_CLI_CONFORMANCE:
09486         *((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
09487         *valLen = sizeof (SQLUINTEGER);
09488         break;
09489     case SQL_SERVER_NAME:
09490     case SQL_DATABASE_NAME:
09491         strmak(val, d->dbname ? d->dbname : "", valMax, valLen);
09492         break;
09493     case SQL_SEARCH_PATTERN_ESCAPE:
09494         strmak(val, "\\", valMax, valLen);
09495         break;
09496     case SQL_ODBC_SQL_CONFORMANCE:
09497         *((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
09498         *valLen = sizeof (SQLSMALLINT);
09499         break;
09500     case SQL_ODBC_API_CONFORMANCE:
09501         *((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
09502         *valLen = sizeof (SQLSMALLINT);
09503         break;
09504     case SQL_DBMS_NAME:
09505         strmak(val, "SQLite", valMax, valLen);
09506         break;
09507     case SQL_DBMS_VER:
09508         strmak(val, SQLITE_VERSION, valMax, valLen);
09509         break;
09510     case SQL_COLUMN_ALIAS:
09511     case SQL_NEED_LONG_DATA_LEN:
09512         strmak(val, "Y", valMax, valLen);
09513         break;
09514     case SQL_ROW_UPDATES:
09515     case SQL_ACCESSIBLE_PROCEDURES:
09516     case SQL_PROCEDURES:
09517     case SQL_EXPRESSIONS_IN_ORDERBY:
09518     case SQL_ODBC_SQL_OPT_IEF:
09519     case SQL_LIKE_ESCAPE_CLAUSE:
09520     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
09521     case SQL_OUTER_JOINS:
09522     case SQL_ACCESSIBLE_TABLES:
09523     case SQL_MULT_RESULT_SETS:
09524     case SQL_MULTIPLE_ACTIVE_TXN:
09525     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
09526         strmak(val, "N", valMax, valLen);
09527         break;
09528 #ifdef SQL_CATALOG_NAME
09529     case SQL_CATALOG_NAME:
09530 #if defined(_WIN32) || defined(_WIN64)
09531         strmak(val, d->xcelqrx ? "Y" : "N", valMax, valLen);
09532 #else
09533         strmak(val, "N", valMax, valLen);
09534 #endif
09535         break;
09536 #endif
09537     case SQL_DATA_SOURCE_READ_ONLY:
09538         strmak(val, "N", valMax, valLen);
09539         break;
09540 #ifdef SQL_OJ_CAPABILITIES
09541     case SQL_OJ_CAPABILITIES:
09542         *((SQLUINTEGER *) val) = 0;
09543         *valLen = sizeof (SQLUINTEGER);
09544         break;
09545 #endif
09546 #ifdef SQL_MAX_IDENTIFIER_LEN
09547     case SQL_MAX_IDENTIFIER_LEN:
09548         *((SQLUSMALLINT *) val) = 255;
09549         *valLen = sizeof (SQLUSMALLINT);
09550         break;
09551 #endif
09552     case SQL_CONCAT_NULL_BEHAVIOR:
09553         *((SQLSMALLINT *) val) = SQL_CB_NULL;
09554         *valLen = sizeof (SQLSMALLINT);
09555         break;
09556     case SQL_CURSOR_COMMIT_BEHAVIOR:
09557     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
09558         *((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
09559         *valLen = sizeof (SQLSMALLINT);
09560         break;
09561 #ifdef SQL_CURSOR_SENSITIVITY
09562     case SQL_CURSOR_SENSITIVITY:
09563         *((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
09564         *valLen = sizeof (SQLUINTEGER);
09565         break;
09566 #endif
09567     case SQL_DEFAULT_TXN_ISOLATION:
09568         *((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
09569         *valLen = sizeof (SQLUINTEGER);
09570         break;
09571 #ifdef SQL_DESCRIBE_PARAMETER
09572     case SQL_DESCRIBE_PARAMETER:
09573         strmak(val, "Y", valMax, valLen);
09574         break;
09575 #endif
09576     case SQL_TXN_ISOLATION_OPTION:
09577         *((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
09578         *valLen = sizeof (SQLUINTEGER);
09579         break;
09580     case SQL_IDENTIFIER_CASE:
09581         *((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
09582         *valLen = sizeof (SQLSMALLINT);
09583         break;
09584     case SQL_IDENTIFIER_QUOTE_CHAR:
09585         strmak(val, "\"", valMax, valLen);
09586         break;
09587     case SQL_MAX_TABLE_NAME_LEN:
09588     case SQL_MAX_COLUMN_NAME_LEN:
09589         *((SQLSMALLINT *) val) = 255;
09590         *valLen = sizeof (SQLSMALLINT);
09591         break;
09592     case SQL_MAX_CURSOR_NAME_LEN:
09593         *((SQLSMALLINT *) val) = 255;
09594         *valLen = sizeof (SQLSMALLINT);
09595         break;
09596     case SQL_MAX_PROCEDURE_NAME_LEN:
09597         *((SQLSMALLINT *) val) = 0;
09598         break;
09599     case SQL_MAX_QUALIFIER_NAME_LEN:
09600     case SQL_MAX_OWNER_NAME_LEN:
09601         *((SQLSMALLINT *) val) = 255;
09602         break;
09603     case SQL_OWNER_TERM:
09604         strmak(val, "", valMax, valLen);
09605         break;
09606     case SQL_PROCEDURE_TERM:
09607         strmak(val, "PROCEDURE", valMax, valLen);
09608         break;
09609     case SQL_QUALIFIER_NAME_SEPARATOR:
09610         strmak(val, ".", valMax, valLen);
09611         break;
09612     case SQL_QUALIFIER_TERM:
09613 #if defined(_WIN32) || defined(_WIN64)
09614         strmak(val, d->xcelqrx ? "catalog" : "", valMax, valLen);
09615 #else
09616         strmak(val, "", valMax, valLen);
09617 #endif
09618         break;
09619     case SQL_QUALIFIER_USAGE:
09620 #if defined(_WIN32) || defined(_WIN64)
09621         *((SQLUINTEGER *) val) = d->xcelqrx ?
09622             (SQL_CU_DML_STATEMENTS | SQL_CU_INDEX_DEFINITION |
09623              SQL_CU_TABLE_DEFINITION) : 0;
09624 #else
09625         *((SQLUINTEGER *) val) = 0;
09626 #endif
09627         *valLen = sizeof (SQLUINTEGER);
09628         break;
09629     case SQL_SCROLL_CONCURRENCY:
09630         *((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
09631         *valLen = sizeof (SQLUINTEGER);
09632         break;
09633     case SQL_SCROLL_OPTIONS:
09634         *((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
09635         *valLen = sizeof (SQLUINTEGER);
09636         break;
09637     case SQL_TABLE_TERM:
09638         strmak(val, "TABLE", valMax, valLen);
09639         break;
09640     case SQL_TXN_CAPABLE:
09641         *((SQLSMALLINT *) val) = SQL_TC_ALL;
09642         *valLen = sizeof (SQLSMALLINT);
09643         break;
09644     case SQL_CONVERT_FUNCTIONS:
09645         *((SQLUINTEGER *) val) = 0;
09646         *valLen = sizeof (SQLUINTEGER);
09647        break;
09648     case SQL_SYSTEM_FUNCTIONS:
09649     case SQL_NUMERIC_FUNCTIONS:
09650     case SQL_STRING_FUNCTIONS:
09651     case SQL_TIMEDATE_FUNCTIONS:
09652         *((SQLUINTEGER *) val) = 0;
09653         *valLen = sizeof (SQLUINTEGER);
09654         break;
09655     case SQL_CONVERT_BIGINT:
09656     case SQL_CONVERT_BIT:
09657     case SQL_CONVERT_CHAR:
09658     case SQL_CONVERT_DATE:
09659     case SQL_CONVERT_DECIMAL:
09660     case SQL_CONVERT_DOUBLE:
09661     case SQL_CONVERT_FLOAT:
09662     case SQL_CONVERT_INTEGER:
09663     case SQL_CONVERT_LONGVARCHAR:
09664     case SQL_CONVERT_NUMERIC:
09665     case SQL_CONVERT_REAL:
09666     case SQL_CONVERT_SMALLINT:
09667     case SQL_CONVERT_TIME:
09668     case SQL_CONVERT_TIMESTAMP:
09669     case SQL_CONVERT_TINYINT:
09670     case SQL_CONVERT_VARCHAR:
09671         *((SQLUINTEGER *) val) = 
09672             SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
09673             SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
09674             SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
09675             SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
09676             SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
09677         *valLen = sizeof (SQLUINTEGER);
09678         break;
09679     case SQL_CONVERT_BINARY:
09680     case SQL_CONVERT_VARBINARY:
09681     case SQL_CONVERT_LONGVARBINARY:
09682         *((SQLUINTEGER *) val) = 0;
09683         *valLen = sizeof (SQLUINTEGER);
09684         break;
09685     case SQL_POSITIONED_STATEMENTS:
09686     case SQL_LOCK_TYPES:
09687         *((SQLUINTEGER *) val) = 0;
09688         *valLen = sizeof (SQLUINTEGER);
09689         break;
09690     case SQL_BOOKMARK_PERSISTENCE:
09691         *((SQLUINTEGER *) val) = SQL_BP_SCROLL;
09692         *valLen = sizeof (SQLUINTEGER);
09693         break;
09694     case SQL_UNION:
09695         *((SQLUINTEGER *) val) = SQL_U_UNION | SQL_U_UNION_ALL;
09696         *valLen = sizeof (SQLUINTEGER);
09697         break;
09698     case SQL_OWNER_USAGE:
09699     case SQL_SUBQUERIES:
09700     case SQL_TIMEDATE_ADD_INTERVALS:
09701     case SQL_TIMEDATE_DIFF_INTERVALS:
09702         *((SQLUINTEGER *) val) = 0;
09703         *valLen = sizeof (SQLUINTEGER);
09704         break;
09705     case SQL_QUOTED_IDENTIFIER_CASE:
09706         *((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
09707         *valLen = sizeof (SQLUSMALLINT);
09708         break;
09709     case SQL_POS_OPERATIONS:
09710         *((SQLUINTEGER *) val) = 0;
09711         *valLen = sizeof (SQLUINTEGER);
09712         break;
09713     case SQL_ALTER_TABLE:
09714         *((SQLUINTEGER *) val) = 0;
09715         *valLen = sizeof (SQLUINTEGER);
09716         break;
09717     case SQL_CORRELATION_NAME:
09718         *((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
09719         *valLen = sizeof (SQLSMALLINT);
09720         break;
09721     case SQL_NON_NULLABLE_COLUMNS:
09722         *((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
09723         *valLen = sizeof (SQLSMALLINT);
09724         break;
09725     case SQL_NULL_COLLATION:
09726         *((SQLSMALLINT *) val) = SQL_NC_START;
09727         *valLen = sizeof (SQLSMALLINT);
09728         break;
09729     case SQL_MAX_COLUMNS_IN_GROUP_BY:
09730     case SQL_MAX_COLUMNS_IN_ORDER_BY:
09731     case SQL_MAX_COLUMNS_IN_SELECT:
09732     case SQL_MAX_COLUMNS_IN_TABLE:
09733     case SQL_MAX_ROW_SIZE:
09734     case SQL_MAX_TABLES_IN_SELECT:
09735         *((SQLSMALLINT *) val) = 0;
09736         *valLen = sizeof (SQLSMALLINT);
09737         break;
09738     case SQL_MAX_BINARY_LITERAL_LEN:
09739     case SQL_MAX_CHAR_LITERAL_LEN:
09740         *((SQLUINTEGER *) val) = 0;
09741         *valLen = sizeof (SQLUINTEGER);
09742         break;
09743     case SQL_MAX_COLUMNS_IN_INDEX:
09744         *((SQLSMALLINT *) val) = 0;
09745         *valLen = sizeof (SQLSMALLINT);
09746         break;
09747     case SQL_MAX_INDEX_SIZE:
09748         *((SQLUINTEGER *) val) = 0;
09749         *valLen = sizeof (SQLUINTEGER);
09750         break;
09751 #ifdef SQL_MAX_IDENTIFIER_LENGTH
09752     case SQL_MAX_IDENTIFIER_LENGTH:
09753         *((SQLUINTEGER *) val) = 255;
09754         *valLen = sizeof (SQLUINTEGER);
09755         break;
09756 #endif
09757     case SQL_MAX_STATEMENT_LEN:
09758         *((SQLUINTEGER *) val) = 16384;
09759         *valLen = sizeof (SQLUINTEGER);
09760         break;
09761     case SQL_QUALIFIER_LOCATION:
09762         *((SQLSMALLINT *) val) = SQL_QL_START;
09763         *valLen = sizeof (SQLSMALLINT);
09764         break;
09765     case SQL_GETDATA_EXTENSIONS:
09766         *((SQLUINTEGER *) val) =
09767             SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
09768         *valLen = sizeof (SQLUINTEGER);
09769         break;
09770     case SQL_STATIC_SENSITIVITY:
09771         *((SQLUINTEGER *) val) = 0;
09772         *valLen = sizeof (SQLUINTEGER);
09773         break;
09774     case SQL_FILE_USAGE:
09775 #if defined(_WIN32) || defined(_WIN64)
09776         *((SQLSMALLINT *) val) =
09777             d->xcelqrx ? SQL_FILE_CATALOG : SQL_FILE_NOT_SUPPORTED;
09778 #else
09779         *((SQLSMALLINT *) val) = SQL_FILE_NOT_SUPPORTED;
09780 #endif
09781         *valLen = sizeof (SQLSMALLINT);
09782         break;
09783     case SQL_GROUP_BY:
09784         *((SQLSMALLINT *) val) = 0;
09785         *valLen = sizeof (SQLSMALLINT);
09786         break;
09787     case SQL_KEYWORDS:
09788         strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
09789                "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
09790                valMax, valLen);
09791         break;
09792     case SQL_SPECIAL_CHARACTERS:
09793 #ifdef SQL_COLLATION_SEQ
09794     case SQL_COLLATION_SEQ:
09795 #endif
09796         strmak(val, "", valMax, valLen);
09797         break;
09798     case SQL_BATCH_SUPPORT:
09799     case SQL_BATCH_ROW_COUNT:
09800     case SQL_PARAM_ARRAY_ROW_COUNTS:
09801         *((SQLUINTEGER *) val) = 0;
09802         *valLen = sizeof (SQLUINTEGER);
09803         break;
09804     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
09805         *((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
09806         *valLen = sizeof (SQLUINTEGER);
09807         break;
09808     case SQL_STATIC_CURSOR_ATTRIBUTES1:
09809         *((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
09810             SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
09811         *valLen = sizeof (SQLUINTEGER);
09812         break;
09813     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
09814     case SQL_STATIC_CURSOR_ATTRIBUTES2:
09815         *((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
09816             SQL_CA2_LOCK_CONCURRENCY;
09817         *valLen = sizeof (SQLUINTEGER);
09818         break;
09819     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
09820     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
09821     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
09822     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
09823         *((SQLUINTEGER *) val) = 0;
09824         *valLen = sizeof (SQLUINTEGER);
09825         break;
09826     case SQL_ODBC_INTERFACE_CONFORMANCE:
09827         *((SQLUINTEGER *) val) = SQL_OIC_CORE;
09828         *valLen = sizeof (SQLUINTEGER);
09829         break;
09830     default:
09831         setstatd(d, -1, "unsupported info option %d",
09832                  (*d->ov3) ? "HYC00" : "S1C00", type);
09833         return SQL_ERROR;
09834     }
09835     return SQL_SUCCESS;
09836 }
09837 
09838 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
09839 
09849 SQLRETURN SQL_API
09850 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
09851            SQLSMALLINT *valLen)
09852 {
09853     SQLRETURN ret;
09854 
09855     HDBC_LOCK(dbc);
09856     ret = drvgetinfo(dbc, type, val, valMax, valLen);
09857     HDBC_UNLOCK(dbc);
09858     return ret;
09859 }
09860 #endif
09861 
09862 #ifdef WINTERFACE
09863 
09873 SQLRETURN SQL_API
09874 SQLGetInfoW(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
09875             SQLSMALLINT *valLen)
09876 {
09877     SQLRETURN ret;
09878     SQLSMALLINT len = 0;
09879 
09880     HDBC_LOCK(dbc);
09881     ret = drvgetinfo(dbc, type, val, valMax, &len);
09882     HDBC_UNLOCK(dbc);
09883     if (ret == SQL_SUCCESS) {
09884         SQLWCHAR *v = NULL;
09885 
09886         switch (type) {
09887         case SQL_USER_NAME:
09888         case SQL_DRIVER_ODBC_VER:
09889         case SQL_DATA_SOURCE_NAME:
09890         case SQL_DRIVER_NAME:
09891         case SQL_DRIVER_VER:
09892         case SQL_ODBC_VER:
09893         case SQL_SERVER_NAME:
09894         case SQL_DATABASE_NAME:
09895         case SQL_SEARCH_PATTERN_ESCAPE:
09896         case SQL_DBMS_NAME:
09897         case SQL_DBMS_VER:
09898         case SQL_NEED_LONG_DATA_LEN:
09899         case SQL_ROW_UPDATES:
09900         case SQL_ACCESSIBLE_PROCEDURES:
09901         case SQL_PROCEDURES:
09902         case SQL_EXPRESSIONS_IN_ORDERBY:
09903         case SQL_ODBC_SQL_OPT_IEF:
09904         case SQL_LIKE_ESCAPE_CLAUSE:
09905         case SQL_ORDER_BY_COLUMNS_IN_SELECT:
09906         case SQL_OUTER_JOINS:
09907         case SQL_COLUMN_ALIAS:
09908         case SQL_ACCESSIBLE_TABLES:
09909         case SQL_MULT_RESULT_SETS:
09910         case SQL_MULTIPLE_ACTIVE_TXN:
09911         case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
09912         case SQL_DATA_SOURCE_READ_ONLY:
09913 #ifdef SQL_DESCRIBE_PARAMETER
09914         case SQL_DESCRIBE_PARAMETER:
09915 #endif
09916         case SQL_IDENTIFIER_QUOTE_CHAR:
09917         case SQL_OWNER_TERM:
09918         case SQL_PROCEDURE_TERM:
09919         case SQL_QUALIFIER_NAME_SEPARATOR:
09920         case SQL_QUALIFIER_TERM:
09921         case SQL_TABLE_TERM:
09922         case SQL_KEYWORDS:
09923         case SQL_SPECIAL_CHARACTERS:
09924 #ifdef SQL_CATALOG_NAME
09925         case SQL_CATALOG_NAME:
09926 #endif
09927 #ifdef SQL_COLLATION_SEQ
09928         case SQL_COLLATION_SEQ:
09929 #endif
09930             if (val) {
09931                 if (len > 0) {
09932                     v = uc_from_utf((SQLCHAR *) val, len);
09933                     if (v) {
09934                         int vmax = valMax / sizeof (SQLWCHAR);
09935 
09936                         uc_strncpy(val, v, vmax);
09937                         v[len] = 0;
09938                         len = min(vmax, uc_strlen(v));
09939                         uc_free(v);
09940                         len *= sizeof (SQLWCHAR);
09941                     } else {
09942                         len = 0;
09943                     }
09944                 }
09945                 if (len <= 0) {
09946                     len = 0;
09947                     if (valMax >= sizeof (SQLWCHAR)) {
09948                         *((SQLWCHAR *)val) = 0;
09949                     }
09950                 }
09951             } else {
09952                 len *= sizeof (SQLWCHAR);
09953             }
09954             break;
09955         }
09956         if (valLen) {
09957             *valLen = len;
09958         }
09959     }
09960     return ret;
09961 }
09962 #endif
09963 
09972 SQLRETURN SQL_API
09973 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
09974                 SQLUSMALLINT *flags)
09975 {
09976     int i;
09977     SQLUSMALLINT exists[100];
09978 
09979     if (dbc == SQL_NULL_HDBC) {
09980         return SQL_INVALID_HANDLE;
09981     }
09982     for (i = 0; i < array_size(exists); i++) {
09983         exists[i] = SQL_FALSE;
09984     }
09985     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
09986     exists[SQL_API_SQLFETCH] = SQL_TRUE;
09987     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
09988     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
09989     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
09990     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
09991     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
09992     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
09993     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
09994     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
09995     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
09996     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
09997     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
09998     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
09999     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
10000     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
10001     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
10002     exists[SQL_API_SQLSETCURSORNAME] = SQL_FALSE;
10003     exists[SQL_API_SQLERROR] = SQL_TRUE;
10004     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
10005     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
10006     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
10007     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
10008     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
10009     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
10010     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
10011     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
10012     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
10013     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
10014     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
10015     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
10016     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
10017     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
10018     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
10019     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
10020     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
10021     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
10022     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
10023     exists[SQL_API_SQLTABLES] = SQL_TRUE;
10024     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
10025     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
10026     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
10027     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
10028     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
10029     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
10030     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
10031     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
10032     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
10033     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
10034     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
10035     exists[SQL_API_SQLSETPOS] = SQL_TRUE;
10036     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
10037     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
10038     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
10039     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_TRUE;
10040     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
10041     if (func == SQL_API_ALL_FUNCTIONS) {
10042         memcpy(flags, exists, sizeof (exists));
10043     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
10044         int i;
10045 #define SET_EXISTS(x) \
10046         flags[(x) >> 4] |= (1 << ((x) & 0xF))
10047 #define CLR_EXISTS(x) \
10048         flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
10049 
10050         memset(flags, 0,
10051                sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
10052         for (i = 0; i < array_size(exists); i++) {
10053             if (exists[i]) {
10054                 flags[i >> 4] |= (1 << (i & 0xF));
10055             }
10056         }
10057         SET_EXISTS(SQL_API_SQLALLOCHANDLE);
10058         SET_EXISTS(SQL_API_SQLFREEHANDLE);
10059         SET_EXISTS(SQL_API_SQLGETSTMTATTR);
10060         SET_EXISTS(SQL_API_SQLSETSTMTATTR);
10061         SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
10062         SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
10063         SET_EXISTS(SQL_API_SQLGETENVATTR);
10064         SET_EXISTS(SQL_API_SQLSETENVATTR);
10065         SET_EXISTS(SQL_API_SQLCLOSECURSOR);
10066         SET_EXISTS(SQL_API_SQLBINDPARAM);
10067 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
10068         /*
10069          * Some unixODBC versions have problems with
10070          * SQLError() vs. SQLGetDiagRec() with loss
10071          * of error/warning messages.
10072          */
10073         SET_EXISTS(SQL_API_SQLGETDIAGREC);
10074 #endif
10075         SET_EXISTS(SQL_API_SQLGETDIAGFIELD);
10076         SET_EXISTS(SQL_API_SQLFETCHSCROLL);
10077         SET_EXISTS(SQL_API_SQLENDTRAN);
10078     } else {
10079         if (func < array_size(exists)) {
10080             *flags = exists[func];
10081         } else {
10082             switch (func) {
10083             case SQL_API_SQLALLOCHANDLE:
10084             case SQL_API_SQLFREEHANDLE:
10085             case SQL_API_SQLGETSTMTATTR:
10086             case SQL_API_SQLSETSTMTATTR:
10087             case SQL_API_SQLGETCONNECTATTR:
10088             case SQL_API_SQLSETCONNECTATTR:
10089             case SQL_API_SQLGETENVATTR:
10090             case SQL_API_SQLSETENVATTR:
10091             case SQL_API_SQLCLOSECURSOR:
10092             case SQL_API_SQLBINDPARAM:
10093 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
10094             /*
10095              * Some unixODBC versions have problems with
10096              * SQLError() vs. SQLGetDiagRec() with loss
10097              * of error/warning messages.
10098              */
10099             case SQL_API_SQLGETDIAGREC:
10100 #endif
10101             case SQL_API_SQLGETDIAGFIELD:
10102             case SQL_API_SQLFETCHSCROLL:
10103             case SQL_API_SQLENDTRAN:
10104                 *flags = SQL_TRUE;
10105                 break;
10106             default:
10107                 *flags = SQL_FALSE;
10108             }
10109         }
10110     }
10111     return SQL_SUCCESS;
10112 }
10113 
10120 static SQLRETURN
10121 drvallocenv(SQLHENV *env)
10122 {
10123     ENV *e;
10124 
10125     if (env == NULL) {
10126         return SQL_INVALID_HANDLE;
10127     }
10128     e = (ENV *) xmalloc(sizeof (ENV));
10129     if (e == NULL) {
10130         *env = SQL_NULL_HENV;
10131         return SQL_ERROR;
10132     }
10133     e->magic = ENV_MAGIC;
10134     e->ov3 = 0;
10135 #if defined(_WIN32) || defined(_WIN64)
10136     InitializeCriticalSection(&e->cs);
10137     e->owner = 0;
10138 #else
10139 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
10140     nvfs_init();
10141 #endif
10142 #endif
10143     e->dbcs = NULL;
10144     *env = (SQLHENV) e;
10145     return SQL_SUCCESS;
10146 }
10147 
10154 SQLRETURN SQL_API
10155 SQLAllocEnv(SQLHENV *env)
10156 {
10157     return drvallocenv(env);
10158 }
10159 
10166 static SQLRETURN
10167 drvfreeenv(SQLHENV env)
10168 {
10169     ENV *e;
10170 
10171     if (env == SQL_NULL_HENV) {
10172         return SQL_INVALID_HANDLE;
10173     }
10174     e = (ENV *) env;
10175     if (e->magic != ENV_MAGIC) {
10176         return SQL_SUCCESS;
10177     }
10178 #if defined(_WIN32) || defined(_WIN64)
10179     EnterCriticalSection(&e->cs);
10180     e->owner = GetCurrentThreadId();
10181 #endif
10182     if (e->dbcs) {
10183 #if defined(_WIN32) || defined(_WIN64)
10184         LeaveCriticalSection(&e->cs);
10185         e->owner = 0;
10186 #endif
10187         return SQL_ERROR;
10188     }
10189     e->magic = DEAD_MAGIC;
10190 #if defined(_WIN32) || defined(_WIN64)
10191     e->owner = 0;
10192     LeaveCriticalSection(&e->cs);
10193     DeleteCriticalSection(&e->cs);
10194 #endif
10195     xfree(e);
10196     return SQL_SUCCESS;
10197 }
10198 
10205 SQLRETURN SQL_API
10206 SQLFreeEnv(SQLHENV env)
10207 {
10208     return drvfreeenv(env);
10209 }
10210 
10218 static SQLRETURN
10219 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
10220 {
10221     DBC *d;
10222     ENV *e;
10223     const char *verstr;
10224     int maj = 0, min = 0, lev = 0;
10225 
10226     if (dbc == NULL) {
10227         return SQL_ERROR;
10228     }
10229     d = (DBC *) xmalloc(sizeof (DBC));
10230     if (d == NULL) {
10231         *dbc = SQL_NULL_HDBC;
10232         return SQL_ERROR;
10233     }
10234     memset(d, 0, sizeof (DBC));
10235     d->curtype = SQL_CURSOR_STATIC;
10236     d->ov3 = &d->ov3val;
10237     verstr = sqlite3_libversion();
10238     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
10239     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
10240     e = (ENV *) env;
10241 #if defined(_WIN32) || defined(_WIN64)
10242     if (e->magic == ENV_MAGIC) {
10243         EnterCriticalSection(&e->cs);
10244         e->owner = GetCurrentThreadId();
10245     }
10246 #endif
10247     if (e->magic == ENV_MAGIC) {
10248         DBC *n, *p;
10249 
10250         d->env = e;
10251         d->ov3 = &e->ov3;
10252         p = NULL;
10253         n = e->dbcs;
10254         while (n) {
10255             p = n;
10256             n = n->next;
10257         }
10258         if (p) {
10259             p->next = d;
10260         } else {
10261             e->dbcs = d;
10262         }
10263     }
10264 #if defined(_WIN32) || defined(_WIN64)
10265     if (e->magic == ENV_MAGIC) {
10266         e->owner = 0;
10267         LeaveCriticalSection(&e->cs);
10268     }
10269     d->oemcp = 1;
10270 #endif
10271     d->autocommit = 1;
10272     d->magic = DBC_MAGIC;
10273     *dbc = (SQLHDBC) d;
10274     drvgetgpps(d);
10275     return SQL_SUCCESS;
10276 }
10277 
10285 SQLRETURN SQL_API
10286 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
10287 {
10288     return drvallocconnect(env, dbc);
10289 }
10290 
10297 static SQLRETURN
10298 drvfreeconnect(SQLHDBC dbc)
10299 {
10300     DBC *d;
10301     ENV *e;
10302     SQLRETURN ret = SQL_ERROR;
10303 
10304     if (dbc == SQL_NULL_HDBC) {
10305         return SQL_INVALID_HANDLE;
10306     }
10307     d = (DBC *) dbc;
10308     if (d->magic != DBC_MAGIC) {
10309         return SQL_INVALID_HANDLE;
10310     }
10311     e = d->env;
10312     if (e && e->magic == ENV_MAGIC) {
10313 #if defined(_WIN32) || defined(_WIN64)
10314         EnterCriticalSection(&e->cs);
10315         e->owner = GetCurrentThreadId();
10316 #endif
10317     } else {
10318         e = NULL;
10319     }
10320     if (d->sqlite) {
10321         setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
10322         goto done;
10323     }
10324     while (d->stmt) {
10325         freestmt((HSTMT) d->stmt);
10326     }
10327     if (e && e->magic == ENV_MAGIC) {
10328         DBC *n, *p;
10329 
10330         p = NULL;
10331         n = e->dbcs;
10332         while (n) {
10333             if (n == d) {
10334                 break;
10335             }
10336             p = n;
10337             n = n->next;
10338         }
10339         if (n) {
10340             if (p) {
10341                 p->next = d->next;
10342             } else {
10343                 e->dbcs = d->next;
10344             }
10345         }
10346     }
10347     drvrelgpps(d);
10348     d->magic = DEAD_MAGIC;
10349     if (d->trace) {
10350         fclose(d->trace);
10351     }
10352     xfree(d);
10353     ret = SQL_SUCCESS;
10354 done:
10355 #if defined(_WIN32) || defined(_WIN64)
10356     if (e) {
10357         e->owner = 0;
10358         LeaveCriticalSection(&e->cs);
10359     }
10360 #endif
10361     return ret;
10362 }
10363 
10370 SQLRETURN SQL_API
10371 SQLFreeConnect(SQLHDBC dbc)
10372 {
10373     return drvfreeconnect(dbc);
10374 }
10375 
10386 static SQLRETURN
10387 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10388                   SQLINTEGER bufmax, SQLINTEGER *buflen)
10389 {
10390     DBC *d;
10391     SQLINTEGER dummy;
10392 
10393     if (dbc == SQL_NULL_HDBC) {
10394         return SQL_INVALID_HANDLE;
10395     }
10396     d = (DBC *) dbc;
10397     if (!val) {
10398         val = (SQLPOINTER) &dummy;
10399     }
10400     if (!buflen) {
10401         buflen = &dummy;
10402     }
10403     switch (attr) {
10404     case SQL_ATTR_CONNECTION_DEAD:
10405         *((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
10406         *buflen = sizeof (SQLINTEGER);
10407         break;
10408     case SQL_ATTR_ACCESS_MODE:
10409         *((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
10410         *buflen = sizeof (SQLINTEGER);
10411         break;
10412     case SQL_ATTR_AUTOCOMMIT:
10413         *((SQLINTEGER *) val) =
10414             d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
10415         *buflen = sizeof (SQLINTEGER);
10416         break;
10417     case SQL_ATTR_LOGIN_TIMEOUT:
10418         *((SQLINTEGER *) val) = 100;
10419         *buflen = sizeof (SQLINTEGER);
10420         break;
10421     case SQL_ATTR_ODBC_CURSORS:
10422         *((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
10423         *buflen = sizeof (SQLINTEGER);
10424         break;
10425     case SQL_ATTR_PACKET_SIZE:
10426         *((SQLINTEGER *) val) = 16384;
10427         *buflen = sizeof (SQLINTEGER);
10428         break;
10429     case SQL_ATTR_TXN_ISOLATION:
10430         *((SQLINTEGER *) val) = SQL_TXN_SERIALIZABLE;
10431         *buflen = sizeof (SQLINTEGER);
10432         break;
10433     case SQL_ATTR_TRACEFILE:
10434     case SQL_ATTR_TRANSLATE_LIB:
10435     case SQL_ATTR_CURRENT_CATALOG:
10436         *((SQLCHAR *) val) = 0;
10437         *buflen = 0;
10438         break;
10439     case SQL_ATTR_TRACE:
10440     case SQL_ATTR_QUIET_MODE:
10441     case SQL_ATTR_TRANSLATE_OPTION:
10442     case SQL_ATTR_KEYSET_SIZE:
10443     case SQL_ATTR_QUERY_TIMEOUT:
10444         *((SQLINTEGER *) val) = 0;
10445         *buflen = sizeof (SQLINTEGER);
10446         break;
10447     case SQL_ATTR_PARAM_BIND_TYPE:
10448         *((SQLULEN *) val) = SQL_PARAM_BIND_BY_COLUMN;
10449         *buflen = sizeof (SQLUINTEGER);
10450         break;
10451     case SQL_ATTR_ROW_BIND_TYPE:
10452         *((SQLULEN *) val) = SQL_BIND_BY_COLUMN;
10453         *buflen = sizeof (SQLULEN);
10454         break;
10455     case SQL_ATTR_USE_BOOKMARKS:
10456         *((SQLINTEGER *) val) = SQL_UB_OFF;
10457         *buflen = sizeof (SQLINTEGER);
10458         break;
10459     case SQL_ATTR_ASYNC_ENABLE:
10460         *((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
10461         *buflen = sizeof (SQLINTEGER);
10462         break;
10463     case SQL_ATTR_NOSCAN:
10464         *((SQLINTEGER *) val) = SQL_NOSCAN_ON;
10465         *buflen = sizeof (SQLINTEGER);
10466         break;
10467     case SQL_ATTR_CONCURRENCY:
10468         *((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
10469         *buflen = sizeof (SQLINTEGER);
10470         break;
10471 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
10472     case SQL_ATTR_CURSOR_SENSITIVITY:
10473         *((SQLINTEGER *) val) = SQL_UNSPECIFIED;
10474         *buflen = sizeof (SQLINTEGER);
10475         break;
10476 #endif
10477     case SQL_ATTR_SIMULATE_CURSOR:
10478         *((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
10479         *buflen = sizeof (SQLINTEGER);
10480         break;
10481     case SQL_ATTR_MAX_ROWS:
10482         *((SQLINTEGER *) val) = 0;
10483         *buflen = sizeof (SQLINTEGER);
10484     case SQL_ATTR_MAX_LENGTH:
10485         *((SQLINTEGER *) val) = 1000000000;
10486         *buflen = sizeof (SQLINTEGER);
10487         break;
10488     case SQL_ATTR_CURSOR_TYPE:
10489         *((SQLINTEGER *) val) = d->curtype;
10490         *buflen = sizeof (SQLINTEGER);
10491         break;
10492     case SQL_ATTR_RETRIEVE_DATA:
10493         *((SQLINTEGER *) val) = SQL_RD_ON;
10494         *buflen = sizeof (SQLINTEGER);
10495         break;
10496 #ifdef SQL_ATTR_METADATA_ID
10497     case SQL_ATTR_METADATA_ID:
10498         *((SQLULEN *) val) = SQL_FALSE;
10499         return SQL_SUCCESS;
10500 #endif
10501     default:
10502         *((SQLINTEGER *) val) = 0;
10503         *buflen = sizeof (SQLINTEGER);
10504         setstatd(d, -1, "unsupported connect attribute %d",
10505                  (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
10506         return SQL_ERROR;
10507     }
10508     return SQL_SUCCESS;
10509 }
10510 
10511 #ifndef WINTERFACE
10512 
10522 SQLRETURN SQL_API
10523 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10524                   SQLINTEGER bufmax, SQLINTEGER *buflen)
10525 {
10526     SQLRETURN ret;
10527 
10528     HDBC_LOCK(dbc);
10529     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
10530     HDBC_UNLOCK(dbc);
10531     return ret;
10532 }
10533 #endif
10534 
10535 #ifdef WINTERFACE
10536 
10546 SQLRETURN SQL_API
10547 SQLGetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10548                    SQLINTEGER bufmax, SQLINTEGER *buflen)
10549 {
10550     SQLRETURN ret;
10551 
10552     HDBC_LOCK(dbc);
10553     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
10554     if (SQL_SUCCEEDED(ret)) {
10555         switch (attr) {
10556         case SQL_ATTR_TRACEFILE:
10557         case SQL_ATTR_CURRENT_CATALOG:
10558         case SQL_ATTR_TRANSLATE_LIB:
10559             if (val && bufmax >= sizeof (SQLWCHAR)) {
10560                 *(SQLWCHAR *) val = 0;
10561             }
10562             break;
10563         }
10564     }
10565     HDBC_UNLOCK(dbc);
10566     return ret;
10567 }
10568 #endif
10569 
10579 static SQLRETURN
10580 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10581                   SQLINTEGER len)
10582 {
10583     DBC *d;
10584 
10585     if (dbc == SQL_NULL_HDBC) {
10586         return SQL_INVALID_HANDLE;
10587     }
10588     d = (DBC *) dbc;
10589     switch (attr) {
10590     case SQL_AUTOCOMMIT:
10591         d->autocommit = val == (SQLPOINTER) SQL_AUTOCOMMIT_ON;
10592         if (d->autocommit && d->intrans) {
10593             return endtran(d, SQL_COMMIT, 1);
10594         } else if (!d->autocommit) {
10595             s3stmt_end(d->cur_s3stmt);
10596         }
10597         return SQL_SUCCESS;
10598 #ifdef SQL_ATTR_METADATA_ID
10599     case SQL_ATTR_METADATA_ID:
10600         if (val == (SQLPOINTER) SQL_FALSE) {
10601             return SQL_SUCCESS;
10602         }
10603         /* fall through */
10604 #endif
10605     default:
10606         setstatd(d, -1, "option value changed", "01S02");
10607         return SQL_SUCCESS_WITH_INFO;
10608     }
10609     return SQL_SUCCESS;
10610 }
10611 
10612 #ifndef WINTERFACE
10613 
10622 SQLRETURN SQL_API
10623 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10624                   SQLINTEGER len)
10625 {
10626     SQLRETURN ret;
10627 
10628     HDBC_LOCK(dbc);
10629     ret = drvsetconnectattr(dbc, attr, val, len);
10630     HDBC_UNLOCK(dbc);
10631     return ret;
10632 }
10633 #endif
10634 
10635 #ifdef WINTERFACE
10636 
10645 SQLRETURN SQL_API
10646 SQLSetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10647                    SQLINTEGER len)
10648 {
10649     SQLRETURN ret;
10650 
10651     HDBC_LOCK(dbc);
10652     ret = drvsetconnectattr(dbc, attr, val, len);
10653     HDBC_UNLOCK(dbc);
10654     return ret;
10655 }
10656 #endif
10657 
10666 static SQLRETURN
10667 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
10668 {
10669     DBC *d;
10670     SQLINTEGER dummy;
10671 
10672     if (dbc == SQL_NULL_HDBC) {
10673         return SQL_INVALID_HANDLE;
10674     }
10675     d = (DBC *) dbc;
10676     if (!param) {
10677         param = (SQLPOINTER) &dummy;
10678     }
10679     switch (opt) {
10680     case SQL_ACCESS_MODE:
10681         *((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
10682         break;
10683     case SQL_AUTOCOMMIT:
10684         *((SQLINTEGER *) param) =
10685             d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
10686         break;
10687     case SQL_LOGIN_TIMEOUT:
10688         *((SQLINTEGER *) param) = 100;
10689         break;
10690     case SQL_ODBC_CURSORS:
10691         *((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
10692         break;
10693     case SQL_PACKET_SIZE:
10694         *((SQLINTEGER *) param) = 16384;
10695         break;
10696     case SQL_TXN_ISOLATION:
10697         *((SQLINTEGER *) param) = SQL_TXN_SERIALIZABLE;
10698         break;
10699     case SQL_OPT_TRACE:
10700     case SQL_OPT_TRACEFILE:
10701     case SQL_QUIET_MODE:
10702     case SQL_TRANSLATE_DLL:
10703     case SQL_TRANSLATE_OPTION:
10704     case SQL_KEYSET_SIZE:
10705     case SQL_QUERY_TIMEOUT:
10706     case SQL_BIND_TYPE:
10707     case SQL_CURRENT_QUALIFIER:
10708         *((SQLINTEGER *) param) = 0;
10709         break;
10710     case SQL_USE_BOOKMARKS:
10711         *((SQLINTEGER *) param) = SQL_UB_OFF;
10712         break;
10713     case SQL_ASYNC_ENABLE:
10714         *((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
10715         break;
10716     case SQL_NOSCAN:
10717         *((SQLINTEGER *) param) = SQL_NOSCAN_ON;
10718         break;
10719     case SQL_CONCURRENCY:
10720         *((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
10721         break;
10722     case SQL_SIMULATE_CURSOR:
10723         *((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
10724         break;
10725     case SQL_MAX_ROWS:
10726         *((SQLINTEGER *) param) = 0;
10727         break;
10728     case SQL_ROWSET_SIZE:
10729     case SQL_MAX_LENGTH:
10730         *((SQLINTEGER *) param) = 1000000000;
10731         break;
10732     case SQL_CURSOR_TYPE:
10733         *((SQLINTEGER *) param) = d->curtype;
10734         break;
10735     case SQL_RETRIEVE_DATA:
10736         *((SQLINTEGER *) param) = SQL_RD_ON;
10737         break;
10738     default:
10739         *((SQLINTEGER *) param) = 0;
10740         setstatd(d, -1, "unsupported connect option %d",
10741                  (*d->ov3) ? "HYC00" : "S1C00", opt);
10742         return SQL_ERROR;
10743     }
10744     return SQL_SUCCESS;
10745 }
10746 
10747 #ifndef WINTERFACE
10748 
10756 SQLRETURN SQL_API
10757 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
10758 {
10759     SQLRETURN ret;
10760 
10761     HDBC_LOCK(dbc);
10762     ret = drvgetconnectoption(dbc, opt, param);
10763     HDBC_UNLOCK(dbc);
10764     return ret;
10765 }
10766 #endif
10767 
10768 #ifdef WINTERFACE
10769 
10777 SQLRETURN SQL_API
10778 SQLGetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
10779 {
10780     SQLRETURN ret;
10781 
10782     HDBC_LOCK(dbc);
10783     ret = drvgetconnectoption(dbc, opt, param);
10784     if (SQL_SUCCEEDED(ret)) {
10785         switch (opt) {
10786         case SQL_OPT_TRACEFILE:
10787         case SQL_CURRENT_QUALIFIER:
10788         case SQL_TRANSLATE_DLL:
10789             if (param) {
10790                 *(SQLWCHAR *) param = 0;
10791             }
10792             break;
10793         }
10794     }
10795     HDBC_UNLOCK(dbc);
10796     return ret;
10797 }
10798 #endif
10799 
10808 static SQLRETURN
10809 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
10810 {
10811     DBC *d;
10812 
10813     if (dbc == SQL_NULL_HDBC) {
10814         return SQL_INVALID_HANDLE;
10815     }
10816     d = (DBC *) dbc;
10817     switch (opt) {
10818     case SQL_AUTOCOMMIT:
10819         d->autocommit = param == SQL_AUTOCOMMIT_ON;
10820         if (d->autocommit && d->intrans) {
10821             return endtran(d, SQL_COMMIT, 1);
10822         } else if (!d->autocommit) {
10823             s3stmt_end(d->cur_s3stmt);
10824         }
10825         break;
10826     default:
10827         setstatd(d, -1, "option value changed", "01S02");
10828         return SQL_SUCCESS_WITH_INFO;
10829     }
10830     return SQL_SUCCESS;
10831 }
10832 
10833 #ifndef WINTERFACE
10834 
10842 SQLRETURN SQL_API
10843 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
10844 {
10845     SQLRETURN ret;
10846 
10847     HDBC_LOCK(dbc);
10848     ret = drvsetconnectoption(dbc, opt, param);
10849     HDBC_UNLOCK(dbc);
10850     return ret;
10851 }
10852 #endif
10853 
10854 #ifdef WINTERFACE
10855 
10863 SQLRETURN SQL_API
10864 SQLSetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
10865 {
10866     SQLRETURN ret;
10867 
10868     HDBC_LOCK(dbc);
10869     ret = drvsetconnectoption(dbc, opt, param);
10870     HDBC_UNLOCK(dbc);
10871     return ret;
10872 }
10873 #endif
10874 
10875 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
10876 
10887 static int
10888 getdsnattr(char *dsn, char *attr, char *out, int outLen)
10889 {
10890     char *str = dsn, *start;
10891     int len = strlen(attr);
10892 
10893     while (*str) {
10894         while (*str && *str == ';') {
10895             ++str;
10896         }
10897         start = str;
10898         if ((str = strchr(str, '=')) == NULL) {
10899             return 0;
10900         }
10901         if (str - start == len && strncasecmp(start, attr, len) == 0) {
10902             start = ++str;
10903             while (*str && *str != ';') {
10904                 ++str;
10905             }
10906             len = min(outLen - 1, str - start);
10907             strncpy(out, start, len);
10908             out[len] = '\0';
10909             return 1;
10910         }
10911         while (*str && *str != ';') {
10912             ++str;
10913         }
10914     }
10915     return 0;
10916 }
10917 #endif
10918 
10930 static SQLRETURN
10931 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen, char *pwd,
10932            int pwdLen, int isu)
10933 {
10934     DBC *d;
10935     int len;
10936     SQLRETURN ret;
10937     char buf[SQL_MAX_MESSAGE_LENGTH], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
10938     char busy[SQL_MAX_MESSAGE_LENGTH / 4], tracef[SQL_MAX_MESSAGE_LENGTH];
10939     char loadext[SQL_MAX_MESSAGE_LENGTH];
10940     char sflag[32], spflag[32], ntflag[32], nwflag[32], biflag[32];
10941     char snflag[32], lnflag[32], ncflag[32], fkflag[32], jmode[32];
10942     char jdflag[32];
10943 #if defined(_WIN32) || defined(_WIN64)
10944     char oemcp[32];
10945 #endif
10946 
10947     if (dbc == SQL_NULL_HDBC) {
10948         return SQL_INVALID_HANDLE;
10949     }
10950     d = (DBC *) dbc;
10951     if (d->magic != DBC_MAGIC) {
10952         return SQL_INVALID_HANDLE;
10953     }
10954     if (d->sqlite != NULL) {
10955         setstatd(d, -1, "connection already established", "08002");
10956         return SQL_ERROR;
10957     }
10958     buf[0] = '\0';
10959     if (dsnLen == SQL_NTS) {
10960         len = sizeof (buf) - 1;
10961     } else {
10962         len = min(sizeof (buf) - 1, dsnLen);
10963     }
10964     if (dsn != NULL) {
10965         strncpy(buf, (char *) dsn, len);
10966     }
10967     buf[len] = '\0';
10968     if (buf[0] == '\0') {
10969         setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
10970         return SQL_ERROR;
10971     }
10972 #if defined(_WIN32) || defined(_WIN64)
10973     /*
10974      * When DSN is in UTF it must be converted to ANSI
10975      * here for ANSI SQLGetPrivateProfileString()
10976      */
10977     if (isu) {
10978         char *cdsn = utf_to_wmb(buf, len);
10979 
10980         if (!cdsn) {
10981             setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
10982             return SQL_ERROR;
10983         }
10984         strcpy(buf, cdsn);
10985         uc_free(cdsn);
10986     }
10987 #endif
10988     busy[0] = '\0';
10989     dbname[0] = '\0';
10990 #ifdef WITHOUT_DRIVERMGR
10991     getdsnattr(buf, "database", dbname, sizeof (dbname));
10992     if (dbname[0] == '\0') {
10993         strncpy(dbname, buf, sizeof (dbname));
10994         dbname[sizeof (dbname) - 1] = '\0';
10995     }
10996     getdsnattr(buf, "timeout", busy, sizeof (busy));
10997     sflag[0] = '\0';
10998     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
10999     spflag[0] = '\0';
11000     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
11001     ntflag[0] = '\0';
11002     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
11003     nwflag[0] = '\0';
11004     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
11005     snflag[0] = '\0';
11006     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
11007     lnflag[0] = '\0';
11008     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
11009     ncflag[0] = '\0';
11010     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
11011     fkflag[0] = '\0';
11012     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
11013     loadext[0] = '\0';
11014     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
11015     jmode[0] = '\0';
11016     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
11017     jdflag[0] = '\0';
11018     getdsnattr(buf, "jdconv", jdflag, sizeof (jdflag));
11019 #if defined(_WIN32) || defined(_WIN64)
11020     oemcp[0] = '\0';
11021     getdsnattr(buf, "oemcp", oemcp, sizeof (oemcp));
11022 #endif
11023     biflag[0] = '\0';
11024     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
11025 #else
11026     SQLGetPrivateProfileString(buf, "timeout", "100000",
11027                                busy, sizeof (busy), ODBC_INI);
11028     SQLGetPrivateProfileString(buf, "database", "",
11029                                dbname, sizeof (dbname), ODBC_INI);
11030 #if defined(_WIN32) || defined(_WIN64)
11031     /* database name read from registry is not UTF8 !!! */
11032     isu = 0;
11033 #endif
11034     SQLGetPrivateProfileString(buf, "stepapi", "",
11035                                sflag, sizeof (sflag), ODBC_INI);
11036     SQLGetPrivateProfileString(buf, "syncpragma", "NORMAL",
11037                                spflag, sizeof (spflag), ODBC_INI);
11038     SQLGetPrivateProfileString(buf, "notxn", "",
11039                                ntflag, sizeof (ntflag), ODBC_INI);
11040     SQLGetPrivateProfileString(buf, "nowchar", "",
11041                                nwflag, sizeof (nwflag), ODBC_INI);
11042     SQLGetPrivateProfileString(buf, "shortnames", "",
11043                                snflag, sizeof (snflag), ODBC_INI);
11044     SQLGetPrivateProfileString(buf, "longnames", "",
11045                                lnflag, sizeof (lnflag), ODBC_INI);
11046     SQLGetPrivateProfileString(buf, "nocreat", "",
11047                                ncflag, sizeof (ncflag), ODBC_INI);
11048     SQLGetPrivateProfileString(buf, "fksupport", "",
11049                                fkflag, sizeof (fkflag), ODBC_INI);
11050     SQLGetPrivateProfileString(buf, "loadext", "",
11051                                loadext, sizeof (loadext), ODBC_INI);
11052     SQLGetPrivateProfileString(buf, "journalmode", "",
11053                                jmode, sizeof (jmode), ODBC_INI);
11054     SQLGetPrivateProfileString(buf, "jdconv", "",
11055                                jdflag, sizeof (jdflag), ODBC_INI);
11056 #if defined(_WIN32) || defined(_WIN64)
11057     SQLGetPrivateProfileString(buf, "oemcp", "1",
11058                                oemcp, sizeof (oemcp), ODBC_INI);
11059 #endif
11060     SQLGetPrivateProfileString(buf, "bigint", "",
11061                                biflag, sizeof (biflag), ODBC_INI);
11062 #endif
11063     tracef[0] = '\0';
11064 #ifdef WITHOUT_DRIVERMGR
11065     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
11066 #else
11067     SQLGetPrivateProfileString(buf, "tracefile", "",
11068                                tracef, sizeof (tracef), ODBC_INI);
11069 #endif
11070     if (tracef[0] != '\0') {
11071         d->trace = fopen(tracef, "a");
11072     }
11073     d->nowchar = getbool(nwflag);
11074     d->shortnames = getbool(snflag);
11075     d->longnames = getbool(lnflag);
11076     d->nocreat = getbool(ncflag);
11077     d->fksupport = getbool(fkflag);
11078     d->jdconv = getbool(jdflag);
11079 #if defined(_WIN32) || defined(_WIN64)
11080     d->oemcp = getbool(oemcp);
11081 #else
11082     d->oemcp = 0;
11083 #endif
11084     d->dobigint = getbool(biflag);
11085     d->pwd = pwd;
11086     d->pwdLen = 0;
11087     if (d->pwd) {
11088         d->pwdLen = (pwdLen == SQL_NTS) ? strlen(d->pwd) : pwdLen;
11089     }
11090     ret = dbopen(d, dbname, isu, (char *) dsn, sflag, spflag, ntflag,
11091                   jmode, busy);
11092     if (ret == SQL_SUCCESS) {
11093         dbloadext(d, loadext);
11094     }
11095     return ret;
11096 }
11097 
11098 #ifndef WINTERFACE
11099 
11111 SQLRETURN SQL_API
11112 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
11113            SQLCHAR *uid, SQLSMALLINT uidLen,
11114            SQLCHAR *pwd, SQLSMALLINT pwdLen)
11115 {
11116     SQLRETURN ret;
11117 
11118     HDBC_LOCK(dbc);
11119     ret = drvconnect(dbc, dsn, dsnLen, (char *) pwd, pwdLen, 0);
11120     HDBC_UNLOCK(dbc);
11121     return ret;
11122 }
11123 #endif
11124 
11125 #ifdef WINTERFACE
11126 
11138 SQLRETURN SQL_API
11139 SQLConnectW(SQLHDBC dbc, SQLWCHAR *dsn, SQLSMALLINT dsnLen,
11140             SQLWCHAR *uid, SQLSMALLINT uidLen,
11141             SQLWCHAR *pwd, SQLSMALLINT pwdLen)
11142 {
11143     char *dsna = NULL;
11144     char *pwda = NULL;
11145     SQLRETURN ret;
11146 
11147     HDBC_LOCK(dbc);
11148     if (dsn) {
11149         dsna = uc_to_utf_c(dsn, dsnLen);
11150         if (!dsna) {
11151             DBC *d = (DBC *) dbc;
11152 
11153             setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
11154             ret = SQL_ERROR;
11155             goto done;
11156         }
11157     }
11158     if (pwd) {
11159         pwda = uc_to_utf_c(pwd, pwdLen);
11160         if (!pwda) {
11161             DBC *d = (DBC *) dbc;
11162 
11163             setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
11164             ret = SQL_ERROR;
11165             goto done;
11166         }
11167     }
11168     ret = drvconnect(dbc, (SQLCHAR *) dsna, SQL_NTS, pwda, SQL_NTS, 1);
11169 done:
11170     HDBC_UNLOCK(dbc);
11171     uc_free(dsna);
11172     uc_free(pwda);
11173     return ret;
11174 }
11175 #endif
11176 
11183 static SQLRETURN
11184 drvdisconnect(SQLHDBC dbc)
11185 {
11186     DBC *d;
11187 
11188     if (dbc == SQL_NULL_HDBC) {
11189         return SQL_INVALID_HANDLE;
11190     }
11191     d = (DBC *) dbc;
11192     if (d->magic != DBC_MAGIC) {
11193         return SQL_INVALID_HANDLE;
11194     }
11195     if (d->intrans) {
11196         setstatd(d, -1, "incomplete transaction", "25000");
11197         return SQL_ERROR;
11198     }
11199     if (d->cur_s3stmt) {
11200         s3stmt_end(d->cur_s3stmt);
11201     }
11202     if (d->sqlite) {
11203         if (d->trace) {
11204             fprintf(d->trace, "-- sqlite3_close: '%s'\n",
11205                     d->dbname);
11206             fflush(d->trace);
11207         }
11208         sqlite3_close(d->sqlite);
11209         d->sqlite = NULL;
11210     }
11211     freep(&d->dbname);
11212     freep(&d->dsn);
11213     return SQL_SUCCESS;
11214 }
11215 
11222 SQLRETURN SQL_API
11223 SQLDisconnect(SQLHDBC dbc)
11224 {
11225     SQLRETURN ret;
11226 
11227     HDBC_LOCK(dbc);
11228     ret = drvdisconnect(dbc);
11229     HDBC_UNLOCK(dbc);
11230     return ret;
11231 }
11232 
11233 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
11234 
11248 static SQLRETURN
11249 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
11250                  SQLCHAR *connIn, SQLSMALLINT connInLen,
11251                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
11252                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
11253 {
11254     DBC *d;
11255     int len;
11256     SQLRETURN ret;
11257     char buf[SQL_MAX_MESSAGE_LENGTH * 6], dbname[SQL_MAX_MESSAGE_LENGTH];
11258     char dsn[SQL_MAX_MESSAGE_LENGTH / 4], busy[SQL_MAX_MESSAGE_LENGTH / 4];
11259     char tracef[SQL_MAX_MESSAGE_LENGTH], loadext[SQL_MAX_MESSAGE_LENGTH];
11260     char pwd[SQL_MAX_MESSAGE_LENGTH];
11261     char sflag[32], spflag[32], ntflag[32], snflag[32], lnflag[32];
11262     char ncflag[32], nwflag[32], fkflag[32], jmode[32], biflag[32];
11263     char jdflag[32];
11264 
11265     if (dbc == SQL_NULL_HDBC) {
11266         return SQL_INVALID_HANDLE;
11267     }
11268     if (drvcompl != SQL_DRIVER_COMPLETE &&
11269         drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
11270         drvcompl != SQL_DRIVER_PROMPT &&
11271         drvcompl != SQL_DRIVER_NOPROMPT) {
11272         return SQL_NO_DATA;
11273     }
11274     d = (DBC *) dbc;
11275     if (d->sqlite) {
11276         setstatd(d, -1, "connection already established", "08002");
11277         return SQL_ERROR;
11278     }
11279     buf[0] = '\0';
11280     if (connInLen == SQL_NTS) {
11281         len = sizeof (buf) - 1;
11282     } else {
11283         len = min(connInLen, sizeof (buf) - 1);
11284     }
11285     if (connIn != NULL) {
11286         strncpy(buf, (char *) connIn, len);
11287     }
11288     buf[len] = '\0';
11289     if (!buf[0]) {
11290         setstatd(d, -1, "invalid connect attributes",
11291                  (*d->ov3) ? "HY090" : "S1090");
11292         return SQL_ERROR;
11293     }
11294     dsn[0] = '\0';
11295     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
11296 
11297     /* special case: connIn is sole DSN value without keywords */
11298     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
11299         strncpy(dsn, buf, sizeof (dsn) - 1);
11300         dsn[sizeof (dsn) - 1] = '\0';
11301     }
11302 
11303     busy[0] = '\0';
11304     getdsnattr(buf, "timeout", busy, sizeof (busy));
11305 #ifndef WITHOUT_DRIVERMGR
11306     if (dsn[0] && !busy[0]) {
11307         SQLGetPrivateProfileString(dsn, "timeout", "100000",
11308                                    busy, sizeof (busy), ODBC_INI);
11309     }
11310 #endif
11311     dbname[0] = '\0';
11312     getdsnattr(buf, "database", dbname, sizeof (dbname));
11313 #ifndef WITHOUT_DRIVERMGR
11314     if (dsn[0] && !dbname[0]) {
11315         SQLGetPrivateProfileString(dsn, "database", "",
11316                                    dbname, sizeof (dbname), ODBC_INI);
11317     }
11318 #endif
11319     sflag[0] = '\0';
11320     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
11321 #ifndef WITHOUT_DRIVERMGR
11322     if (dsn[0] && !sflag[0]) {
11323         SQLGetPrivateProfileString(dsn, "stepapi", "",
11324                                    sflag, sizeof (sflag), ODBC_INI);
11325     }
11326 #endif
11327     spflag[0] = '\0';
11328     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
11329 #ifndef WITHOUT_DRIVERMGR
11330     if (dsn[0] && !spflag[0]) {
11331         SQLGetPrivateProfileString(dsn, "syncpragma", "NORMAL",
11332                                    spflag, sizeof (spflag), ODBC_INI);
11333     }
11334 #endif
11335     ntflag[0] = '\0';
11336     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
11337 #ifndef WITHOUT_DRIVERMGR
11338     if (dsn[0] && !ntflag[0]) {
11339         SQLGetPrivateProfileString(dsn, "notxn", "",
11340                                    ntflag, sizeof (ntflag), ODBC_INI);
11341     }
11342 #endif
11343     snflag[0] = '\0';
11344     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
11345 #ifndef WITHOUT_DRIVERMGR
11346     if (dsn[0] && !snflag[0]) {
11347         SQLGetPrivateProfileString(dsn, "shortnames", "",
11348                                    snflag, sizeof (snflag), ODBC_INI);
11349     }
11350 #endif
11351     lnflag[0] = '\0';
11352     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
11353 #ifndef WITHOUT_DRIVERMGR
11354     if (dsn[0] && !lnflag[0]) {
11355         SQLGetPrivateProfileString(dsn, "longnames", "",
11356                                    lnflag, sizeof (lnflag), ODBC_INI);
11357     }
11358 #endif
11359     ncflag[0] = '\0';
11360     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
11361 #ifndef WITHOUT_DRIVERMGR
11362     if (dsn[0] && !ncflag[0]) {
11363         SQLGetPrivateProfileString(dsn, "nocreat", "",
11364                                    ncflag, sizeof (ncflag), ODBC_INI);
11365     }
11366 #endif
11367     nwflag[0] = '\0';
11368     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
11369 #ifndef WITHOUT_DRIVERMGR
11370     if (dsn[0] && !nwflag[0]) {
11371         SQLGetPrivateProfileString(dsn, "nowchar", "",
11372                                    nwflag, sizeof (nwflag), ODBC_INI);
11373     }
11374 #endif
11375     fkflag[0] = '\0';
11376     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
11377 #ifndef WITHOUT_DRIVERMGR
11378     if (dsn[0] && !fkflag[0]) {
11379         SQLGetPrivateProfileString(dsn, "fksupport", "",
11380                                    fkflag, sizeof (fkflag), ODBC_INI);
11381     }
11382 #endif
11383     loadext[0] = '\0';
11384     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
11385 #ifndef WITHOUT_DRIVERMGR
11386     if (dsn[0] && !loadext[0]) {
11387         SQLGetPrivateProfileString(dsn, "loadext", "",
11388                                    loadext, sizeof (loadext), ODBC_INI);
11389     }
11390 #endif
11391     jmode[0] = '\0';
11392     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
11393 #ifndef WITHOUT_DRIVERMGR
11394     if (dsn[0] && !jmode[0]) {
11395         SQLGetPrivateProfileString(dsn, "journalmode", "",
11396                                    jmode, sizeof (jmode), ODBC_INI);
11397     }
11398 #endif
11399     biflag[0] = '\0';
11400     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
11401 #ifndef WITHOUT_DRIVERMGR
11402     if (dsn[0] && !biflag[0]) {
11403         SQLGetPrivateProfileString(dsn, "bigint", "",
11404                                    biflag, sizeof (biflag), ODBC_INI);
11405     }
11406 #endif
11407     jdflag[0] = '\0';
11408     getdsnattr(buf, "jdconv", jdflag, sizeof (jdflag));
11409 #ifndef WITHOUT_DRIVERMGR
11410     if (dsn[0] && !jdflag[0]) {
11411         SQLGetPrivateProfileString(dsn, "jdconv", "",
11412                                    jdflag, sizeof (jdflag), ODBC_INI);
11413     }
11414 #endif
11415     pwd[0] = '\0';
11416     getdsnattr(buf, "pwd", pwd, sizeof (pwd));
11417 #ifndef WITHOUT_DRIVERMGR
11418     if (dsn[0] && !pwd[0]) {
11419         SQLGetPrivateProfileString(dsn, "pwd", "",
11420                                    pwd, sizeof (pwd), ODBC_INI);
11421     }
11422 #endif
11423 
11424     if (!dbname[0] && !dsn[0]) {
11425         strcpy(dsn, "SQLite");
11426         strncpy(dbname, buf, sizeof (dbname));
11427         dbname[sizeof (dbname) - 1] = '\0';
11428     }
11429     tracef[0] = '\0';
11430     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
11431 #ifndef WITHOUT_DRIVERMGR
11432     if (dsn[0] && !tracef[0]) {
11433         SQLGetPrivateProfileString(dsn, "tracefile", "",
11434                                    tracef, sizeof (tracef), ODBC_INI);
11435     }
11436 #endif
11437     if (connOut || connOutLen) {
11438         int count;
11439 
11440         buf[0] = '\0';
11441         count = snprintf(buf, sizeof (buf),
11442                          "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s;"
11443                          "SyncPragma=%s;NoTXN=%s;ShortNames=%s;LongNames=%s;"
11444                          "NoCreat=%s;NoWCHAR=%s;FKSupport=%s;Tracefile=%s;"
11445                          "JournalMode=%s;LoadExt=%s;BigInt=%s;JDConv=%s;"
11446                          "PWD=%s",
11447                          dsn, dbname, sflag, busy, spflag, ntflag,
11448                          snflag, lnflag, ncflag, nwflag, fkflag, tracef,
11449                          jmode, loadext, biflag, jdflag, pwd);
11450         if (count < 0) {
11451             buf[sizeof (buf) - 1] = '\0';
11452         }
11453         len = min(connOutMax - 1, strlen(buf));
11454         if (connOut) {
11455             strncpy((char *) connOut, buf, len);
11456             connOut[len] = '\0';
11457         }
11458         if (connOutLen) {
11459             *connOutLen = len;
11460         }
11461     }
11462     if (tracef[0] != '\0') {
11463         d->trace = fopen(tracef, "a");
11464     }
11465     d->shortnames = getbool(snflag);
11466     d->longnames = getbool(lnflag);
11467     d->nocreat = getbool(ncflag);
11468     d->nowchar = getbool(nwflag);
11469     d->fksupport = getbool(fkflag);
11470     d->dobigint = getbool(biflag);
11471     d->jdconv = getbool(jdflag);
11472     d->oemcp = 0;
11473     d->pwdLen = strlen(pwd);
11474     d->pwd = (d->pwdLen > 0) ? pwd : NULL;
11475     ret = dbopen(d, dbname, 0, dsn, sflag, spflag, ntflag, jmode, busy);
11476     memset(pwd, 0, sizeof (pwd));
11477     if (ret == SQL_SUCCESS) {
11478         dbloadext(d, loadext);
11479     }
11480     return ret;
11481 }
11482 #endif
11483 
11490 static SQLRETURN
11491 freestmt(SQLHSTMT stmt)
11492 {
11493     STMT *s;
11494     DBC *d;
11495 
11496     if (stmt == SQL_NULL_HSTMT) {
11497         return SQL_INVALID_HANDLE;
11498     }
11499     s = (STMT *) stmt;
11500     s3stmt_drop(s);
11501     freeresult(s, 1);
11502     freep(&s->query);
11503     d = (DBC *) s->dbc;
11504     if (d && d->magic == DBC_MAGIC) {
11505         STMT *p, *n;
11506 
11507         p = NULL;
11508         n = d->stmt;
11509         while (n) {
11510             if (n == s) {
11511                 break;
11512             }
11513             p = n;
11514             n = n->next;
11515         }
11516         if (n) {
11517             if (p) {
11518                 p->next = s->next;
11519             } else {
11520                 d->stmt = s->next;
11521             }
11522         }
11523     }
11524     freeparams(s);
11525     freep(&s->bindparms);
11526     if (s->row_status0 != &s->row_status1) {
11527         freep(&s->row_status0);
11528         s->rowset_size = 1;
11529         s->row_status0 = &s->row_status1;
11530     }
11531     xfree(s);
11532     return SQL_SUCCESS;
11533 }
11534 
11542 static SQLRETURN
11543 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
11544 {
11545     DBC *d;
11546     STMT *s, *sl, *pl;
11547 
11548     if (dbc == SQL_NULL_HDBC) {
11549         return SQL_INVALID_HANDLE;
11550     }
11551     d = (DBC *) dbc;
11552     if (d->magic != DBC_MAGIC || stmt == NULL) {
11553         return SQL_INVALID_HANDLE;
11554     }
11555     s = (STMT *) xmalloc(sizeof (STMT));
11556     if (s == NULL) {
11557         *stmt = SQL_NULL_HSTMT;
11558         return SQL_ERROR;
11559     }
11560     *stmt = (SQLHSTMT) s;
11561     memset(s, 0, sizeof (STMT));
11562     s->dbc = dbc;
11563     s->ov3 = d->ov3;
11564     s->oemcp = &d->oemcp;
11565     s->jdconv = &d->jdconv;
11566     s->nowchar[0] = d->nowchar;
11567     s->nowchar[1] = 0;
11568     s->dobigint = d->dobigint;
11569     s->curtype = d->curtype;
11570     s->row_status0 = &s->row_status1;
11571     s->rowset_size = 1;
11572     s->longnames = d->longnames;
11573     s->retr_data = SQL_RD_ON;
11574     s->max_rows = 0;
11575     s->bind_type = SQL_BIND_BY_COLUMN;
11576     s->bind_offs = NULL;
11577     s->paramset_size = 1;
11578     s->parm_bind_type = SQL_PARAM_BIND_BY_COLUMN;
11579 #ifdef _WIN64
11580     sprintf((char *) s->cursorname, "CUR_%I64X", (SQLUBIGINT) *stmt);
11581 #else
11582     sprintf((char *) s->cursorname, "CUR_%016lX", (long) *stmt);
11583 #endif
11584     sl = d->stmt;
11585     pl = NULL;
11586     while (sl) {
11587         pl = sl;
11588         sl = sl->next;
11589     }
11590     if (pl) {
11591         pl->next = s;
11592     } else {
11593         d->stmt = s;
11594     }
11595     return SQL_SUCCESS;
11596 }
11597 
11605 SQLRETURN SQL_API
11606 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
11607 {
11608     SQLRETURN ret;  
11609 
11610     HDBC_LOCK(dbc);
11611     ret = drvallocstmt(dbc, stmt);
11612     HDBC_UNLOCK(dbc);
11613     return ret;
11614 }
11615 
11623 static SQLRETURN
11624 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
11625 {
11626     STMT *s;
11627     SQLRETURN ret = SQL_SUCCESS;
11628     SQLHDBC dbc;
11629 
11630     if (stmt == SQL_NULL_HSTMT) {
11631         return SQL_INVALID_HANDLE;
11632     }
11633     HSTMT_LOCK(stmt);
11634     s = (STMT *) stmt;
11635     dbc = s->dbc;
11636     switch (opt) {
11637     case SQL_RESET_PARAMS:
11638         freeparams(s);
11639         break;
11640     case SQL_UNBIND:
11641         unbindcols(s);
11642         break;
11643     case SQL_CLOSE:
11644         s3stmt_end_if(s);
11645         freeresult(s, 0);
11646         break;
11647     case SQL_DROP:
11648         s3stmt_end_if(s);
11649         ret = freestmt(stmt);
11650         break;
11651     default:
11652         setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
11653         ret = SQL_ERROR;
11654         break;
11655     }
11656     HDBC_UNLOCK(dbc);
11657     return ret;
11658 }
11659 
11667 SQLRETURN SQL_API
11668 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
11669 {
11670     return drvfreestmt(stmt, opt);
11671 }
11672 
11679 SQLRETURN SQL_API
11680 SQLCancel(SQLHSTMT stmt)
11681 {
11682     if (stmt != SQL_NULL_HSTMT) {
11683         DBC *d = (DBC *) ((STMT *) stmt)->dbc;
11684 #if defined(_WIN32) || defined(_WIN64)
11685         /* interrupt when other thread owns critical section */
11686         int i;
11687 
11688         for (i = 0; i < 2; i++) {
11689             if (d->magic == DBC_MAGIC && d->env &&
11690                 d->env->magic == ENV_MAGIC &&
11691                 d->env->owner != GetCurrentThreadId() &&
11692                 d->env->owner != 0) {
11693                 d->busyint = 1;
11694                 sqlite3_interrupt(d->sqlite);
11695             }
11696             Sleep(1);
11697         }
11698 
11699 #else
11700         if (d->magic == DBC_MAGIC) {
11701             d->busyint = 1;
11702             sqlite3_interrupt(d->sqlite);
11703         }
11704 #endif
11705     }
11706     return drvfreestmt(stmt, SQL_CLOSE);
11707 }
11708 
11718 static SQLRETURN
11719 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
11720                  SQLSMALLINT *lenp)
11721 {
11722     STMT *s;
11723 
11724     if (stmt == SQL_NULL_HSTMT) {
11725         return SQL_INVALID_HANDLE;
11726     }
11727     s = (STMT *) stmt;
11728     if (lenp && !cursor) {
11729         *lenp = strlen((char *) s->cursorname);
11730         return SQL_SUCCESS;
11731     }
11732     if (cursor) {
11733         if (buflen > 0) {
11734             strncpy((char *) cursor, (char *) s->cursorname, buflen - 1);
11735             cursor[buflen - 1] = '\0';
11736         }
11737         if (lenp) {
11738             *lenp = min(strlen((char *) s->cursorname), buflen - 1);
11739         }
11740     }
11741     return SQL_SUCCESS;
11742 }
11743 
11744 #ifndef WINTERFACE
11745 
11754 SQLRETURN SQL_API
11755 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
11756                  SQLSMALLINT *lenp)
11757 {
11758     SQLRETURN ret;
11759 #if defined(_WIN32) || defined(_WIN64)
11760     SQLSMALLINT len = 0;
11761 #endif
11762 
11763     HSTMT_LOCK(stmt);
11764 #if defined(_WIN32) || defined(_WIN64)
11765     if (!((STMT *) stmt)->oemcp[0]) {
11766         ret = drvgetcursorname(stmt, cursor, buflen, lenp);
11767         goto done;
11768     }
11769     ret = drvgetcursorname(stmt, cursor, buflen, &len);
11770     if (ret == SQL_SUCCESS) {
11771         char *c = NULL;
11772 
11773         if (cursor) {
11774             c = utf_to_wmb((char *) cursor, len);
11775             if (!c) {
11776                 ret = nomem((STMT *) stmt);
11777                 goto done;
11778             }
11779             c[len] = 0;
11780             len = strlen(c);
11781             if (buflen > 0) {
11782                 strncpy((char *) cursor, c, buflen - 1);
11783                 cursor[buflen - 1] = 0;
11784             }
11785             uc_free(c);
11786         }
11787         if (lenp) {
11788             *lenp = min(len, buflen - 1);
11789         }
11790     }
11791 done:
11792     ;
11793 #else
11794     ret = drvgetcursorname(stmt, cursor, buflen, lenp);
11795 #endif
11796     HSTMT_UNLOCK(stmt);
11797     return ret;
11798 }
11799 #endif
11800 
11801 #ifdef WINTERFACE
11802 
11811 SQLRETURN SQL_API
11812 SQLGetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT buflen,
11813                   SQLSMALLINT *lenp)
11814 {
11815     SQLRETURN ret;
11816     SQLSMALLINT len = 0;
11817 
11818     HSTMT_LOCK(stmt);
11819     ret = drvgetcursorname(stmt, (SQLCHAR *) cursor, buflen, &len);
11820     if (ret == SQL_SUCCESS) {
11821         SQLWCHAR *c = NULL;
11822 
11823         if (cursor) {
11824             c = uc_from_utf((SQLCHAR *) cursor, len);
11825             if (!c) {
11826                 ret = nomem((STMT *) stmt);
11827                 goto done;
11828             }
11829             c[len] = 0;
11830             len = uc_strlen(c);
11831             if (buflen > 0) {
11832                 uc_strncpy(cursor, c, buflen - 1);
11833                 cursor[buflen - 1] = 0;
11834             }
11835             uc_free(c);
11836         }
11837         if (lenp) {
11838             *lenp = min(len, buflen - 1);
11839         }
11840     }
11841 done:
11842     HSTMT_UNLOCK(stmt);
11843     return ret;
11844 }
11845 #endif
11846 
11855 static SQLRETURN
11856 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
11857 {
11858     STMT *s;
11859 
11860     if (stmt == SQL_NULL_HSTMT) {
11861         return SQL_INVALID_HANDLE;
11862     }
11863     s = (STMT *) stmt;
11864     if (!cursor ||
11865         !((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
11866           (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
11867         setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
11868         return SQL_ERROR;
11869     }
11870     if (len == SQL_NTS) {
11871         len = sizeof (s->cursorname) - 1;
11872     } else {
11873         len = min(sizeof (s->cursorname) - 1, len);
11874     }
11875     strncpy((char *) s->cursorname, (char *) cursor, len);
11876     s->cursorname[len] = '\0';
11877     return SQL_SUCCESS;
11878 }
11879 
11880 #ifndef WINTERFACE
11881 
11889 SQLRETURN SQL_API
11890 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
11891 {
11892 #if defined(_WIN32) || defined(_WIN64)
11893     char *c = NULL;
11894 #endif
11895     SQLRETURN ret;
11896 
11897     HSTMT_LOCK(stmt);
11898 #if defined(_WIN32) || defined(_WIN64)
11899     if (!((STMT *) stmt)->oemcp[0]) {
11900         ret = drvsetcursorname(stmt, cursor, len);
11901         goto done2;
11902     }
11903     if (cursor) {
11904         c = wmb_to_utf_c((char *) cursor, len);
11905         if (!c) {
11906             ret = nomem((STMT *) stmt);
11907             goto done;
11908         }
11909     }
11910     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
11911 #else
11912     ret = drvsetcursorname(stmt, cursor, len);
11913 #endif
11914 #if defined(_WIN32) || defined(_WIN64)
11915 done:
11916     uc_free(c);
11917 done2:
11918     ;
11919 #endif
11920     HSTMT_UNLOCK(stmt);
11921     return ret;
11922 }
11923 #endif
11924 
11925 #ifdef WINTERFACE
11926 
11934 SQLRETURN SQL_API
11935 SQLSetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT len)
11936 {
11937     char *c = NULL;
11938     SQLRETURN ret;
11939 
11940     HSTMT_LOCK(stmt);
11941     if (cursor) {
11942         c = uc_to_utf_c(cursor, len);
11943         if (!c) {
11944             ret = nomem((STMT *) stmt);
11945             goto done;
11946         }
11947     }
11948     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
11949 done:
11950     uc_free(c);
11951     HSTMT_UNLOCK(stmt);
11952     return ret;
11953 }
11954 #endif
11955 
11962 SQLRETURN SQL_API
11963 SQLCloseCursor(SQLHSTMT stmt)
11964 {
11965     return drvfreestmt(stmt, SQL_CLOSE);
11966 }
11967 
11976 SQLRETURN SQL_API
11977 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
11978 {
11979     SQLRETURN ret;
11980 
11981     switch (type) {
11982     case SQL_HANDLE_ENV:
11983         ret = drvallocenv((SQLHENV *) output);
11984         if (ret == SQL_SUCCESS) {
11985             ENV *e = (ENV *) *output;
11986 
11987             if (e && e->magic == ENV_MAGIC) {
11988                 e->ov3 = 1;
11989             }
11990         }
11991         return ret;
11992     case SQL_HANDLE_DBC:
11993         return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
11994     case SQL_HANDLE_STMT:
11995         HDBC_LOCK((SQLHDBC) input);
11996         ret = drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
11997         HDBC_UNLOCK((SQLHDBC) input);
11998         return ret;
11999     }
12000     return SQL_ERROR;
12001 }
12002 
12010 SQLRETURN SQL_API
12011 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
12012 {
12013     switch (type) {
12014     case SQL_HANDLE_ENV:
12015         return drvfreeenv((SQLHENV) h);
12016     case SQL_HANDLE_DBC:
12017         return drvfreeconnect((SQLHDBC) h);
12018     case SQL_HANDLE_STMT:
12019         return drvfreestmt((SQLHSTMT) h, SQL_DROP);
12020     }
12021     return SQL_ERROR;
12022 }
12023 
12029 static void
12030 freedyncols(STMT *s)
12031 {
12032     if (s->dyncols) {
12033         int i;
12034 
12035         for (i = 0; i < s->dcols; i++) {
12036             freep(&s->dyncols[i].typename);
12037         }
12038         if (s->cols == s->dyncols) {
12039             s->cols = NULL;
12040             s->ncols = 0;
12041         }
12042         freep(&s->dyncols);
12043     }
12044     s->dcols = 0;
12045 }
12046 
12058 static void
12059 freeresult(STMT *s, int clrcols)
12060 {
12061     freep(&s->bincache);
12062     s->bincell = NULL;
12063     s->binlen = 0;
12064     if (s->rows) {
12065         if (s->rowfree) {
12066             s->rowfree(s->rows);
12067             s->rowfree = NULL;
12068         }
12069         s->rows = NULL;
12070     }
12071     s->nrows = -1;
12072     if (clrcols > 0) {
12073         freep(&s->bindcols);
12074         s->nbindcols = 0;
12075     }
12076     if (clrcols) {
12077         freedyncols(s);
12078         s->cols = NULL;
12079         s->ncols = 0;
12080         s->nowchar[1] = 0;
12081     }
12082 }
12083 
12089 static void
12090 unbindcols(STMT *s)
12091 {
12092     int i;
12093 
12094     s->bkmrkcol.type = -1;
12095     s->bkmrkcol.max = 0;
12096     s->bkmrkcol.lenp = NULL;
12097     s->bkmrkcol.valp = NULL;
12098     s->bkmrkcol.index = 0;
12099     s->bkmrkcol.offs = 0;
12100     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
12101         s->bindcols[i].type = -1;
12102         s->bindcols[i].max = 0;
12103         s->bindcols[i].lenp = NULL;
12104         s->bindcols[i].valp = NULL;
12105         s->bindcols[i].index = i;
12106         s->bindcols[i].offs = 0;
12107     }
12108 }
12109 
12117 static SQLRETURN
12118 mkbindcols(STMT *s, int ncols)
12119 {
12120     if (s->bindcols) {
12121         if (s->nbindcols < ncols) {
12122             int i;
12123             BINDCOL *bindcols =
12124                 xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
12125 
12126             if (!bindcols) {
12127                 return nomem(s);
12128             }
12129             for (i = s->nbindcols; i < ncols; i++) {
12130                 bindcols[i].type = -1;
12131                 bindcols[i].max = 0;
12132                 bindcols[i].lenp = NULL;
12133                 bindcols[i].valp = NULL;
12134                 bindcols[i].index = i;
12135                 bindcols[i].offs = 0;
12136             }
12137             s->bindcols = bindcols;
12138             s->nbindcols = ncols;
12139         }
12140     } else if (ncols > 0) {
12141         s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
12142         if (!s->bindcols) {
12143             return nomem(s);
12144         }
12145         s->nbindcols = ncols;
12146         unbindcols(s);
12147     }
12148     return SQL_SUCCESS;
12149 }
12150 
12164 static SQLRETURN
12165 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
12166            SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp, int partial)
12167 {
12168     char **data, valdummy[16];
12169     SQLLEN dummy;
12170     SQLINTEGER *ilenp = NULL;
12171     int valnull = 0;
12172     int type = otype;
12173     SQLRETURN sret = SQL_NO_DATA;
12174 
12175     if (!lenp) {
12176         lenp = &dummy;
12177     }
12178     /* workaround for JDK 1.7.0 on x86_64 */
12179     if (((SQLINTEGER *) lenp) + 1 == (SQLINTEGER *) val) {
12180         ilenp = (SQLINTEGER *) lenp;
12181         lenp = &dummy;
12182     }
12183     if (col >= s->ncols) {
12184         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
12185         return SQL_ERROR;
12186     }
12187     if (!s->rows) {
12188         *lenp = SQL_NULL_DATA;
12189         goto done;
12190     }
12191     if (s->rowp < 0 || s->rowp >= s->nrows) {
12192         *lenp = SQL_NULL_DATA;
12193         goto done;
12194     }
12195     if (s->retr_data != SQL_RD_ON) {
12196         return SQL_SUCCESS;
12197     }
12198     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0,
12199                       s->nowchar[0]);
12200 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
12201     /* MS Access hack part 3 (map SQL_C_DEFAULT to SQL_C_CHAR) */
12202     if (type == SQL_C_WCHAR && otype == SQL_C_DEFAULT) {
12203         type = SQL_C_CHAR;
12204     }
12205 #endif
12206     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
12207     if (!val) {
12208         valnull = 1;
12209         val = (SQLPOINTER) valdummy;
12210     }
12211     if (*data == NULL) {
12212         *lenp = SQL_NULL_DATA;
12213         switch (type) {
12214         case SQL_C_UTINYINT:
12215         case SQL_C_TINYINT:
12216         case SQL_C_STINYINT:
12217 #ifdef SQL_BIT
12218         case SQL_C_BIT:
12219 #endif
12220             *((SQLCHAR *) val) = 0;
12221             break;
12222         case SQL_C_USHORT:
12223         case SQL_C_SHORT:
12224         case SQL_C_SSHORT:
12225             *((SQLSMALLINT *) val) = 0;
12226             break;
12227         case SQL_C_ULONG:
12228         case SQL_C_LONG:
12229         case SQL_C_SLONG:
12230             *((SQLINTEGER *) val) = 0;
12231             break;
12232 #ifdef SQL_BIGINT
12233         case SQL_C_SBIGINT:
12234         case SQL_C_UBIGINT:
12235             *((SQLBIGINT *) val) = 0;
12236             break;
12237 #endif
12238         case SQL_C_FLOAT:
12239             *((float *) val) = 0;
12240             break;
12241         case SQL_C_DOUBLE:
12242             *((double *) val) = 0;
12243             break;
12244         case SQL_C_BINARY:
12245         case SQL_C_CHAR:
12246             *((SQLCHAR *) val) = '\0';
12247             break;
12248 #ifdef WCHARSUPPORT
12249         case SQL_C_WCHAR:
12250             *((SQLWCHAR *) val) = '\0';
12251             break;
12252 #endif
12253 #ifdef SQL_C_TYPE_DATE
12254         case SQL_C_TYPE_DATE:
12255 #endif
12256         case SQL_C_DATE:
12257             memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
12258             break;
12259 #ifdef SQL_C_TYPE_TIME
12260         case SQL_C_TYPE_TIME:
12261 #endif
12262         case SQL_C_TIME:
12263             memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
12264             break;
12265 #ifdef SQL_C_TYPE_TIMESTAMP
12266         case SQL_C_TYPE_TIMESTAMP:
12267 #endif
12268         case SQL_C_TIMESTAMP:
12269             memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
12270             break;
12271         default:
12272             return SQL_ERROR;
12273         }
12274     } else {
12275         char *endp = NULL;
12276 #if defined(_WIN32) || defined(_WIN64)
12277 #ifdef SQL_BIGINT
12278         char endc;
12279 #endif
12280 #endif
12281 
12282         switch (type) {
12283         case SQL_C_UTINYINT:
12284         case SQL_C_TINYINT:
12285         case SQL_C_STINYINT:
12286             *((SQLCHAR *) val) = strtol(*data, &endp, 0);
12287             if (endp && endp == *data) {
12288                 *lenp = SQL_NULL_DATA;
12289             } else {
12290                 *lenp = sizeof (SQLCHAR);
12291             }
12292             break;
12293 #ifdef SQL_BIT
12294         case SQL_C_BIT:
12295             *((SQLCHAR *) val) = getbool(*data);
12296             *lenp = sizeof (SQLCHAR);
12297             break;
12298 #endif
12299         case SQL_C_USHORT:
12300         case SQL_C_SHORT:
12301         case SQL_C_SSHORT:
12302             *((SQLSMALLINT *) val) = strtol(*data, &endp, 0);
12303             if (endp && endp == *data) {
12304                 *lenp = SQL_NULL_DATA;
12305             } else {
12306                 *lenp = sizeof (SQLSMALLINT);
12307             }
12308             break;
12309         case SQL_C_ULONG:
12310         case SQL_C_LONG:
12311         case SQL_C_SLONG:
12312             *((SQLINTEGER *) val) = strtol(*data, &endp, 0);
12313             if (endp && endp == *data) {
12314                 *lenp = SQL_NULL_DATA;
12315             } else {
12316                 *lenp = sizeof (SQLINTEGER);
12317             }
12318             break;
12319 #ifdef SQL_BIGINT
12320         case SQL_C_UBIGINT:
12321 #if defined(_WIN32) || defined(_WIN64)
12322             if (sscanf(*data, "%I64u%c", (SQLUBIGINT *) val, &endc) != 1) {
12323                 *lenp = SQL_NULL_DATA;
12324             } else {
12325                 *lenp = sizeof (SQLUBIGINT);
12326             }
12327 #else
12328 #ifdef __osf__
12329             *((SQLUBIGINT *) val) = strtoul(*data, &endp, 0);
12330 #else
12331             *((SQLUBIGINT *) val) = strtoull(*data, &endp, 0);
12332 #endif
12333             if (endp && endp == *data) {
12334                 *lenp = SQL_NULL_DATA;
12335             } else {
12336                 *lenp = sizeof (SQLUBIGINT);
12337             }
12338 #endif
12339             break;
12340         case SQL_C_SBIGINT:
12341 #if defined(_WIN32) || defined(_WIN64)
12342             if (sscanf(*data, "%I64d%c", (SQLBIGINT *) val, &endc) != 1) {
12343                 *lenp = SQL_NULL_DATA;
12344             } else {
12345                 *lenp = sizeof (SQLBIGINT);
12346             }
12347 #else
12348 #ifdef __osf__
12349             *((SQLBIGINT *) val) = strtol(*data, &endp, 0);
12350 #else
12351             *((SQLBIGINT *) val) = strtoll(*data, &endp, 0);
12352 #endif
12353             if (endp && endp == *data) {
12354                 *lenp = SQL_NULL_DATA;
12355             } else {
12356                 *lenp = sizeof (SQLBIGINT);
12357             }
12358 #endif
12359             break;
12360 #endif
12361         case SQL_C_FLOAT:
12362             *((float *) val) = ln_strtod(*data, &endp);
12363             if (endp && endp == *data) {
12364                 *lenp = SQL_NULL_DATA;
12365             } else {
12366                 *lenp = sizeof (float);
12367             }
12368             break;
12369         case SQL_C_DOUBLE:
12370             *((double *) val) = ln_strtod(*data, &endp);
12371             if (endp && endp == *data) {
12372                 *lenp = SQL_NULL_DATA;
12373             } else {
12374                 *lenp = sizeof (double);
12375             }
12376             break;
12377         case SQL_C_BINARY: {
12378             int dlen, offs = 0;
12379             char *bin;
12380 
12381             if (valnull) {
12382                 freep(&s->bincache);
12383                 s->binlen = 0;
12384                 goto doCHAR;
12385             }
12386             if (*data == s->bincell) {
12387                 if (s->bincache) {
12388                     bin = s->bincache;
12389                     dlen = s->binlen;
12390                 } else {
12391                     goto doCHAR;
12392                 }
12393             } else {
12394                 char *dp;
12395                 int i;
12396 
12397                 freep(&s->bincache);
12398                 dp = *data;
12399                 dlen = strlen(dp);
12400                 s->bincell = dp;
12401                 s->binlen = 0;
12402                 if (!(dp[0] == 'x' || dp[0] == 'X') || dp[1] != '\'' ||
12403                     dp[dlen - 1] != '\'') {
12404                     goto doCHAR;
12405                 }
12406                 dlen -= 2;
12407                 dp += 2;
12408                 dlen = dlen / 2;
12409                 s->bincache = bin = xmalloc(dlen);
12410                 if (!bin) {
12411                     return nomem(s);
12412                 }
12413                 s->binlen = dlen;
12414                 memset(s->bincache, 0, dlen);
12415                 for (i = 0; i < dlen; i++) {
12416                     char *x;
12417                     int v;
12418 
12419                     if (!*dp || !(x = strchr(xdigits, *dp))) {
12420                         goto converr;
12421                     }
12422                     v = x - xdigits;
12423                     bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
12424                     ++dp;
12425                     if (!*dp || !(x = strchr(xdigits, *dp))) {
12426 converr:
12427                         freep(&s->bincache);
12428                         s->binlen = 0;
12429                         setstat(s, -1, "conversion error",
12430                                 (*s->ov3) ? "HY000" : "S1000");
12431                         return SQL_ERROR;
12432                     }
12433                     v = x - xdigits;
12434                     bin[i] |= (v >= 16) ? (v - 6) : v;
12435                     ++dp;
12436                 }
12437                 bin = s->bincache;
12438             }
12439             if (partial && len && s->bindcols) {
12440                 if (s->bindcols[col].offs >= dlen) {
12441                     *lenp = 0;
12442                     if (!dlen && s->bindcols[col].offs == dlen) {
12443                         s->bindcols[col].offs = 1;
12444                         sret = SQL_SUCCESS;
12445                         goto done;
12446                     }
12447                     s->bindcols[col].offs = 0;
12448                     sret = SQL_NO_DATA;
12449                     goto done;
12450                 }
12451                 offs = s->bindcols[col].offs;
12452                 dlen -= offs;
12453             }
12454             if (val && len) {
12455                 memcpy(val, bin + offs, min(len, dlen));
12456             }
12457             if (len < 1) {
12458                 *lenp = dlen;
12459             } else {
12460                 *lenp = min(len, dlen);
12461                 if (*lenp == len && *lenp != dlen) {
12462                     *lenp = SQL_NO_TOTAL;
12463                 }
12464             }
12465             if (partial && len && s->bindcols) {
12466                 if (*lenp == SQL_NO_TOTAL) {
12467                     *lenp = dlen;
12468                     s->bindcols[col].offs += len;
12469                     setstat(s, -1, "data right truncated", "01004");
12470                     if (s->bindcols[col].lenp) {
12471                         *s->bindcols[col].lenp = dlen;
12472                     }
12473                     sret = SQL_SUCCESS_WITH_INFO;
12474                     goto done;
12475                 }
12476                 s->bindcols[col].offs += *lenp;
12477             }
12478             if (*lenp == SQL_NO_TOTAL) {
12479                 *lenp = dlen;
12480                 setstat(s, -1, "data right truncated", "01004");
12481                 sret = SQL_SUCCESS_WITH_INFO;
12482                 goto done;
12483             }
12484             break;
12485         }
12486         doCHAR:
12487 #ifdef WCHARSUPPORT
12488         case SQL_C_WCHAR:
12489 #endif
12490         case SQL_C_CHAR: {
12491             int doz, zlen = len - 1;
12492             int dlen = strlen(*data);
12493             int offs = 0;
12494 #ifdef WCHARSUPPORT
12495             SQLWCHAR *ucdata = NULL;
12496             SQLCHAR *cdata = (SQLCHAR *) *data;
12497 #endif
12498 
12499 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
12500             /* MS Access hack part 2 (reserved error -7748) */
12501             if (!valnull &&
12502                 (s->cols == statSpec2P || s->cols == statSpec3P) &&
12503                 type == SQL_C_WCHAR) {
12504                 if (len > 0 && len <= sizeof (SQLWCHAR)) {
12505                     ((char *) val)[0] = data[0][0];
12506                     memset((char *) val + 1, 0, len - 1);
12507                     *lenp = 1;
12508                     sret = SQL_SUCCESS;
12509                     goto done;
12510                 }
12511             }
12512 #endif
12513 
12514 #ifdef WCHARSUPPORT
12515             switch (type) {
12516             case SQL_C_CHAR:
12517                 doz = 1;
12518                 break;
12519             case SQL_C_WCHAR:
12520                 doz = sizeof (SQLWCHAR);
12521                 break;
12522             default:
12523                 doz = 0;
12524                 break;
12525             }
12526             if (type == SQL_C_WCHAR) {
12527                 ucdata = uc_from_utf(cdata, dlen);
12528                 if (!ucdata) {
12529                     return nomem(s);
12530                 }
12531                 dlen = uc_strlen(ucdata) * sizeof (SQLWCHAR);
12532             }
12533 #if defined(_WIN32) || defined(_WIN64)
12534             else if (*s->oemcp && type == SQL_C_CHAR) {
12535                 ucdata = (SQLWCHAR *) utf_to_wmb((char *) cdata, dlen);
12536                 if (!ucdata) {
12537                     return nomem(s);
12538                 }
12539                 cdata = (SQLCHAR *) ucdata;
12540                 dlen = strlen((char *) cdata);
12541             }
12542 #endif
12543 #else
12544             doz = (type == SQL_C_CHAR) ? 1 : 0;
12545 #endif
12546             if (partial && len && s->bindcols) {
12547                 if (s->bindcols[col].offs >= dlen) {
12548 #ifdef WCHARSUPPORT
12549                     uc_free(ucdata);
12550 #endif
12551                     *lenp = 0;
12552                     if (doz && val) {
12553 #ifdef WCHARSUPPORT
12554                         if (type == SQL_C_WCHAR) {
12555                             ((SQLWCHAR *) val)[0] = 0;
12556                         } else {
12557                             ((char *) val)[0] = '\0';
12558                         }
12559 #else
12560                         ((char *) val)[0] = '\0';
12561 #endif
12562                     }
12563                     if (!dlen && s->bindcols[col].offs == dlen) {
12564                         s->bindcols[col].offs = 1;
12565                         sret = SQL_SUCCESS;
12566                         goto done;
12567                     }
12568                     s->bindcols[col].offs = 0;
12569                     sret = SQL_NO_DATA;
12570                     goto done;
12571                 }
12572                 offs = s->bindcols[col].offs;
12573                 dlen -= offs;
12574             }
12575             if (val && !valnull && len) {
12576 #ifdef WCHARSUPPORT
12577                 if (type == SQL_C_WCHAR) {
12578                     uc_strncpy(val, ucdata + offs / sizeof (SQLWCHAR),
12579                                (len - doz) / sizeof (SQLWCHAR));
12580                 } else {
12581                     strncpy(val, (char *) cdata + offs, len - doz);
12582                 }
12583 #else
12584                 strncpy(val, *data + offs, len - doz);
12585 #endif
12586             }
12587             if (valnull || len < 1) {
12588                 *lenp = dlen;
12589             } else {
12590                 *lenp = min(len - doz, dlen);
12591                 if (*lenp == len - doz && *lenp != dlen) {
12592                     *lenp = SQL_NO_TOTAL;
12593                 } else if (*lenp < zlen) {
12594                     zlen = *lenp;
12595                 }           
12596             }
12597             if (len && !valnull && doz) {
12598 #ifdef WCHARSUPPORT
12599                 if (type == SQL_C_WCHAR) {
12600                     ((SQLWCHAR *) val)[zlen / sizeof (SQLWCHAR)] = 0;
12601                 } else {
12602                     ((char *) val)[zlen] = '\0';
12603                 }
12604 #else
12605                 ((char *) val)[zlen] = '\0';
12606 #endif
12607             }
12608 #ifdef WCHARSUPPORT
12609             uc_free(ucdata);
12610 #endif
12611             if (partial && len && s->bindcols) {
12612                 if (*lenp == SQL_NO_TOTAL) {
12613                     *lenp = dlen;
12614                     s->bindcols[col].offs += len - doz;
12615                     setstat(s, -1, "data right truncated", "01004");
12616                     if (s->bindcols[col].lenp) {
12617                         *s->bindcols[col].lenp = dlen;
12618                     }
12619                     sret = SQL_SUCCESS_WITH_INFO;
12620                     goto done;
12621                 }
12622                 s->bindcols[col].offs += *lenp;
12623             }
12624             if (*lenp == SQL_NO_TOTAL) {
12625                 *lenp = dlen;
12626                 setstat(s, -1, "data right truncated", "01004");
12627                 sret = SQL_SUCCESS_WITH_INFO;
12628                 goto done;
12629             }
12630             break;
12631         }
12632 #ifdef SQL_C_TYPE_DATE
12633         case SQL_C_TYPE_DATE:
12634 #endif
12635         case SQL_C_DATE:
12636             if (str2date(*s->jdconv, *data, (DATE_STRUCT *) val) < 0) {
12637                 *lenp = SQL_NULL_DATA;
12638             } else {
12639                 *lenp = sizeof (DATE_STRUCT);
12640             }
12641             break;
12642 #ifdef SQL_C_TYPE_TIME
12643         case SQL_C_TYPE_TIME:
12644 #endif
12645         case SQL_C_TIME:
12646             if (str2time(*s->jdconv, *data, (TIME_STRUCT *) val) < 0) {
12647                 *lenp = SQL_NULL_DATA;
12648             } else {
12649                 *lenp = sizeof (TIME_STRUCT);
12650             }
12651             break;
12652 #ifdef SQL_C_TYPE_TIMESTAMP
12653         case SQL_C_TYPE_TIMESTAMP:
12654 #endif
12655         case SQL_C_TIMESTAMP:
12656             if (str2timestamp(*s->jdconv, *data,
12657                               (TIMESTAMP_STRUCT *) val) < 0) {
12658                 *lenp = SQL_NULL_DATA;
12659             } else {
12660                 *lenp = sizeof (TIMESTAMP_STRUCT);
12661             }
12662             switch (s->cols[col].prec) {
12663             case 0:
12664                 ((TIMESTAMP_STRUCT *) val)->fraction = 0;
12665                 break;
12666             case 1:
12667                 ((TIMESTAMP_STRUCT *) val)->fraction /= 100000000;
12668                 ((TIMESTAMP_STRUCT *) val)->fraction *= 100000000;
12669                 break;
12670             case 2:
12671                 ((TIMESTAMP_STRUCT *) val)->fraction /= 10000000;
12672                 ((TIMESTAMP_STRUCT *) val)->fraction *= 10000000;
12673                 break;
12674             }
12675             break;
12676         default:
12677             return SQL_ERROR;
12678         }
12679     }
12680     sret = SQL_SUCCESS;
12681 done:
12682     if (ilenp) {
12683         *ilenp = *lenp;
12684     }
12685     return sret;
12686 }
12687 
12699 static SQLRETURN
12700 drvbindcol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
12701            SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
12702 {
12703     STMT *s;
12704     int sz = 0;
12705 
12706     if (stmt == SQL_NULL_HSTMT) {
12707         return SQL_INVALID_HANDLE;
12708     }
12709     s = (STMT *) stmt;
12710     if (col < 1) {
12711         if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
12712             s->bkmrkcol.type = type;
12713             s->bkmrkcol.max = sizeof (SQLINTEGER);
12714             s->bkmrkcol.lenp = lenp;
12715             s->bkmrkcol.valp = val;
12716             s->bkmrkcol.offs = 0;
12717             if (lenp) {
12718                 *lenp = 0;
12719             }
12720             return SQL_SUCCESS;
12721         }
12722         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
12723         return SQL_ERROR;
12724     }
12725     if (mkbindcols(s, col) != SQL_SUCCESS) {
12726         return SQL_ERROR;
12727     }
12728     --col;
12729     if (type == SQL_C_DEFAULT) {
12730         type = mapdeftype(type, s->cols[col].type, 0,
12731                           s->nowchar[0] || s->nowchar[1]);
12732     }
12733     switch (type) {
12734     case SQL_C_LONG:
12735     case SQL_C_ULONG:
12736     case SQL_C_SLONG:
12737         sz = sizeof (SQLINTEGER);
12738         break;
12739     case SQL_C_TINYINT:
12740     case SQL_C_UTINYINT:
12741     case SQL_C_STINYINT:
12742         sz = sizeof (SQLCHAR);
12743         break;
12744     case SQL_C_SHORT:
12745     case SQL_C_USHORT:
12746     case SQL_C_SSHORT:
12747         sz = sizeof (SQLSMALLINT);
12748         break;
12749     case SQL_C_FLOAT:
12750         sz = sizeof (SQLFLOAT);
12751         break;
12752     case SQL_C_DOUBLE:
12753         sz = sizeof (SQLDOUBLE);
12754         break;
12755     case SQL_C_TIMESTAMP:
12756         sz = sizeof (SQL_TIMESTAMP_STRUCT);
12757         break;
12758     case SQL_C_TIME:
12759         sz = sizeof (SQL_TIME_STRUCT);
12760         break;
12761     case SQL_C_DATE:
12762         sz = sizeof (SQL_DATE_STRUCT);
12763         break;
12764     case SQL_C_CHAR:
12765         break;
12766 #ifdef WCHARSUPPORT
12767     case SQL_C_WCHAR:
12768         break;
12769 #endif
12770 #ifdef SQL_C_TYPE_DATE
12771     case SQL_C_TYPE_DATE:
12772         sz = sizeof (SQL_DATE_STRUCT);
12773         break;
12774 #endif
12775 #ifdef SQL_C_TYPE_TIME
12776     case SQL_C_TYPE_TIME:
12777         sz = sizeof (SQL_TIME_STRUCT);
12778         break;
12779 #endif
12780 #ifdef SQL_C_TYPE_TIMESTAMP
12781     case SQL_C_TYPE_TIMESTAMP:
12782         sz = sizeof (SQL_TIMESTAMP_STRUCT);
12783         break;
12784 #endif
12785 #ifdef SQL_BIT
12786     case SQL_C_BIT:
12787         sz = sizeof (SQLCHAR);
12788         break;
12789 #endif
12790     case SQL_C_BINARY:
12791         break;
12792 #ifdef SQL_BIGINT
12793     case SQL_C_SBIGINT:
12794     case SQL_C_UBIGINT:
12795         sz = sizeof (SQLBIGINT);
12796         break;
12797 #endif
12798     default:
12799         if (val == NULL) {
12800             /* fall through, unbinding column */
12801             break;
12802         }
12803         setstat(s, -1, "invalid type %d", "HY003", type);
12804         return SQL_ERROR;
12805     }
12806     if (val == NULL) {
12807         /* unbind column */
12808         s->bindcols[col].type = -1;
12809         s->bindcols[col].max = 0;
12810         s->bindcols[col].lenp = NULL;
12811         s->bindcols[col].valp = NULL;
12812         s->bindcols[col].offs = 0;
12813     } else {
12814         if (sz == 0 && max < 0) {
12815             setstat(s, -1, "invalid length", "HY090");
12816             return SQL_ERROR;
12817         }
12818         s->bindcols[col].type = type;
12819         s->bindcols[col].max = (sz == 0) ? max : sz;
12820         s->bindcols[col].lenp = lenp;
12821         s->bindcols[col].valp = val;
12822         s->bindcols[col].offs = 0;
12823         if (lenp) {
12824             *lenp = 0;
12825         }
12826     }
12827     return SQL_SUCCESS; 
12828 }
12829 
12841 SQLRETURN SQL_API
12842 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
12843            SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
12844 {
12845     SQLRETURN ret;
12846 
12847     HSTMT_LOCK(stmt);
12848     ret = drvbindcol(stmt, col, type, val, max, lenp);
12849     HSTMT_UNLOCK(stmt);
12850     return ret;
12851 }
12852 
12857 static COL tableSpec2[] = {
12858     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
12859     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
12860     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
12861     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
12862     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
12863 };
12864 
12865 static COL tableSpec3[] = {
12866     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
12867     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
12868     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
12869     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
12870     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
12871 };
12872 
12887 static SQLRETURN
12888 drvtables(SQLHSTMT stmt,
12889           SQLCHAR *cat, SQLSMALLINT catLen,
12890           SQLCHAR *schema, SQLSMALLINT schemaLen,
12891           SQLCHAR *table, SQLSMALLINT tableLen,
12892           SQLCHAR *type, SQLSMALLINT typeLen)
12893 {
12894     SQLRETURN ret;
12895     STMT *s;
12896     DBC *d;
12897     int ncols, asize, rc, size, npatt;
12898     char *errp = NULL, *sql, tname[512];
12899     char *where = "(type = 'table' or type = 'view')";
12900 
12901     ret = mkresultset(stmt, tableSpec2, array_size(tableSpec2),
12902                       tableSpec3, array_size(tableSpec3), &asize);
12903     if (ret != SQL_SUCCESS) {
12904         return ret;
12905     }
12906     s = (STMT *) stmt;
12907     d = (DBC *) s->dbc;
12908     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
12909         int size = 3 * asize;
12910 
12911         s->rows = xmalloc(size * sizeof (char *));
12912         if (!s->rows) {
12913             s->nrows = 0;
12914             return nomem(s);
12915         }
12916         memset(s->rows, 0, sizeof (char *) * size);
12917         s->ncols = asize;
12918         s->rows[s->ncols + 0] = "";
12919         s->rows[s->ncols + 1] = "";
12920         s->rows[s->ncols + 2] = "";
12921         s->rows[s->ncols + 3] = "TABLE";
12922         s->rows[s->ncols + 5] = "";
12923         s->rows[s->ncols + 6] = "";
12924         s->rows[s->ncols + 7] = "";
12925         s->rows[s->ncols + 8] = "VIEW";
12926 #ifdef MEMORY_DEBUG
12927         s->rowfree = xfree__;
12928 #else
12929         s->rowfree = sqlite3_free;
12930 #endif
12931         s->nrows = 2;
12932         s->rowp = -1;
12933         return SQL_SUCCESS;
12934     }
12935     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
12936         table = NULL;
12937         goto doit;
12938     }
12939     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
12940         schema[0] == '%') {
12941         if ((!cat || catLen == 0 || !cat[0]) &&
12942             (!table || tableLen == 0 || !table[0])) {
12943             table = NULL;
12944             goto doit;
12945         }
12946     }
12947     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] != '\0') {
12948         char tmp[256], *t;
12949         int with_view = 0, with_table = 0;
12950 
12951         if (typeLen == SQL_NTS) {
12952             strncpy(tmp, (char *) type, sizeof (tmp));
12953             tmp[sizeof (tmp) - 1] = '\0';
12954         } else {
12955             int len = min(sizeof (tmp) - 1, typeLen);
12956 
12957             strncpy(tmp, (char *) type, len);
12958             tmp[len] = '\0';
12959         }
12960         t = tmp;
12961         while (*t) {
12962             *t = TOLOWER(*t);
12963             t++;
12964         }
12965         t = tmp;
12966         unescpat(t);
12967         while (t) {
12968             if (t[0] == '\'') {
12969                 ++t;
12970             }
12971             if (strncmp(t, "table", 5) == 0) {
12972                 with_table++;
12973             } else if (strncmp(t, "view", 4) == 0) {
12974                 with_view++;
12975             }
12976             t = strchr(t, ',');
12977             if (t) {
12978                 ++t;
12979             }
12980         }
12981         if (with_view && with_table) {
12982             /* where is already preset */
12983         } else if (with_view && !with_table) {
12984             where = "type = 'view'";
12985         } else if (!with_view && with_table) {
12986             where = "type = 'table'";
12987         } else {
12988             return SQL_SUCCESS;
12989         }
12990     }
12991 doit:
12992     if (!table) {
12993         size = 1;
12994         tname[0] = '%';
12995     } else {
12996         if (tableLen == SQL_NTS) {
12997             size = sizeof (tname) - 1;
12998         } else {
12999             size = min(sizeof (tname) - 1, tableLen);
13000         }
13001         strncpy(tname, (char *) table, size);
13002     }
13003     tname[size] = '\0';
13004     npatt = unescpat(tname);
13005 #if defined(_WIN32) || defined(_WIN64)
13006     sql = sqlite3_mprintf("select %s as 'TABLE_QUALIFIER', "
13007                           "%s as 'TABLE_OWNER', "
13008                           "tbl_name as 'TABLE_NAME', "
13009                           "upper(type) as 'TABLE_TYPE', "
13010                           "NULL as 'REMARKS' "
13011                           "from sqlite_master where %s "
13012                           "and tbl_name %s %Q",
13013                           d->xcelqrx ? "''" : "NULL",
13014                           d->xcelqrx ? "'main'" : "NULL",
13015                           where,
13016                           npatt ? "like" : "=", tname);
13017 #else
13018     sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
13019                           "NULL as 'TABLE_OWNER', "
13020                           "tbl_name as 'TABLE_NAME', "
13021                           "upper(type) as 'TABLE_TYPE', "
13022                           "NULL as 'REMARKS' "
13023                           "from sqlite_master where %s "
13024                           "and tbl_name %s %Q", where,
13025                           npatt ? "like" : "=", tname);
13026 #endif
13027     if (!sql) {
13028         return nomem(s);
13029     }
13030     ret = starttran(s);
13031     if (ret != SQL_SUCCESS) {
13032         sqlite3_free(sql);
13033         return ret;
13034     }
13035     dbtraceapi(d, "sqlite3_get_table", sql);
13036     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
13037     sqlite3_free(sql);
13038     if (rc == SQLITE_OK) {
13039         if (ncols != s->ncols) {
13040             freeresult(s, 0);
13041             s->nrows = 0;
13042         } else {
13043             s->rowfree = sqlite3_free_table;
13044         }
13045     } else {
13046         s->nrows = 0;
13047         s->rows = NULL;
13048         s->rowfree = NULL;
13049     }
13050     if (errp) {
13051         sqlite3_free(errp);
13052         errp = NULL;
13053     }
13054     s->rowp = -1;
13055     return SQL_SUCCESS;
13056 }
13057 
13058 #ifndef WINTERFACE
13059 
13073 SQLRETURN SQL_API
13074 SQLTables(SQLHSTMT stmt,
13075           SQLCHAR *cat, SQLSMALLINT catLen,
13076           SQLCHAR *schema, SQLSMALLINT schemaLen,
13077           SQLCHAR *table, SQLSMALLINT tableLen,
13078           SQLCHAR *type, SQLSMALLINT typeLen)
13079 {
13080 #if defined(_WIN32) || defined(_WIN64)
13081     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
13082 #endif
13083     SQLRETURN ret;
13084 
13085     HSTMT_LOCK(stmt);
13086 #if defined(_WIN32) || defined(_WIN64)
13087     if (!((STMT *) stmt)->oemcp[0]) {
13088         ret = drvtables(stmt, cat, catLen, schema, schemaLen,
13089                         table, tableLen, type, typeLen);
13090         goto done2;
13091     }
13092     if (cat) {
13093         c = wmb_to_utf_c((char *) cat, catLen);
13094         if (!c) {
13095             ret = nomem((STMT *) stmt);
13096             goto done;
13097         }
13098     }
13099     if (schema) {
13100         s = wmb_to_utf_c((char *) schema, schemaLen);
13101         if (!s) {
13102             ret = nomem((STMT *) stmt);
13103             goto done;
13104         }
13105     }
13106     if (table) {
13107         t = wmb_to_utf_c((char *) table, tableLen);
13108         if (!t) {
13109             ret = nomem((STMT *) stmt);
13110             goto done;
13111         }
13112     }
13113     if (type) {
13114         y = wmb_to_utf_c((char *) type, typeLen);
13115         if (!y) {
13116             ret = nomem((STMT *) stmt);
13117             goto done;
13118         }
13119     }
13120     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
13121                     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
13122 #else
13123     ret = drvtables(stmt, cat, catLen, schema, schemaLen,
13124                     table, tableLen, type, typeLen);
13125 #endif
13126 #if defined(_WIN32) || defined(_WIN64)
13127 done:
13128     uc_free(y);
13129     uc_free(t);
13130     uc_free(s);
13131     uc_free(c);
13132 done2:
13133     ;
13134 #endif
13135     HSTMT_UNLOCK(stmt);
13136     return ret;
13137 }
13138 #endif
13139 
13140 #ifdef WINTERFACE
13141 
13155 SQLRETURN SQL_API
13156 SQLTablesW(SQLHSTMT stmt,
13157            SQLWCHAR *cat, SQLSMALLINT catLen,
13158            SQLWCHAR *schema, SQLSMALLINT schemaLen,
13159            SQLWCHAR *table, SQLSMALLINT tableLen,
13160            SQLWCHAR *type, SQLSMALLINT typeLen)
13161 {
13162     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
13163     SQLRETURN ret;
13164 
13165     HSTMT_LOCK(stmt);
13166     if (cat) {
13167         c = uc_to_utf_c(cat, catLen);
13168         if (!c) {
13169             ret = nomem((STMT *) stmt);
13170             goto done;
13171         }
13172     }
13173     if (schema) {
13174         s = uc_to_utf_c(schema, schemaLen);
13175         if (!s) {
13176             ret = nomem((STMT *) stmt);
13177             goto done;
13178         }
13179     }
13180     if (table) {
13181         t = uc_to_utf_c(table, tableLen);
13182         if (!t) {
13183             ret = nomem((STMT *) stmt);
13184             goto done;
13185         }
13186     }
13187     if (type) {
13188         y = uc_to_utf_c(type, typeLen);
13189         if (!y) {
13190             ret = nomem((STMT *) stmt);
13191             goto done;
13192         }
13193     }
13194     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
13195                     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
13196 done:
13197     uc_free(y);
13198     uc_free(t);
13199     uc_free(s);
13200     uc_free(c);
13201     HSTMT_UNLOCK(stmt);
13202     return ret;
13203 }
13204 #endif
13205 
13210 static COL colSpec2[] = {
13211     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
13212     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
13213     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
13214     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
13215     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
13216     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
13217     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
13218     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
13219     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
13220     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
13221     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
13222     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
13223     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
13224     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
13225     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
13226     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
13227     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
13228     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
13229 };
13230 
13231 static COL colSpec3[] = {
13232     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
13233     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
13234     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
13235     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
13236     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
13237     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
13238     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
13239     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
13240     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_SMALLINT, 50 },
13241     { "SYSTEM", "COLUMN", "NUM_PREC_RADIX", SQL_SMALLINT, 50 },
13242     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
13243     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
13244     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
13245     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
13246     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
13247     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
13248     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
13249     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
13250 };
13251 
13266 static SQLRETURN
13267 drvcolumns(SQLHSTMT stmt,
13268            SQLCHAR *cat, SQLSMALLINT catLen,
13269            SQLCHAR *schema, SQLSMALLINT schemaLen,
13270            SQLCHAR *table, SQLSMALLINT tableLen,
13271            SQLCHAR *col, SQLSMALLINT colLen)
13272 {
13273     SQLRETURN sret;
13274     STMT *s;
13275     DBC *d;
13276     int ret, nrows, ncols, asize, i, k, roffs, namec;
13277     int tnrows, tncols, npatt;
13278     PTRDIFF_T size;
13279     char *errp = NULL, *sql, tname[512], cname[512], **rowp, **trows;
13280 
13281     sret = mkresultset(stmt, colSpec2, array_size(colSpec2),
13282                        colSpec3, array_size(colSpec3), &asize);
13283     if (sret != SQL_SUCCESS) {
13284         return sret;
13285     }
13286     s = (STMT *) stmt;
13287     d = (DBC *) s->dbc;
13288     if (!table) {
13289         size = 1;
13290         tname[0] = '%';
13291     } else {
13292         if (tableLen == SQL_NTS) {
13293             size = sizeof (tname) - 1;
13294         } else {
13295             size = min(sizeof (tname) - 1, tableLen);
13296         }
13297         strncpy(tname, (char *) table, size);
13298     }
13299     tname[size] = '\0';
13300     npatt = unescpat(tname);
13301     size = 0;
13302     if (col) {
13303         if (colLen == SQL_NTS) {
13304             size = sizeof (cname) - 1;
13305         } else {
13306             size = min(sizeof (cname) - 1, colLen);
13307         }
13308         strncpy(cname, (char *) col, size);
13309     }
13310     cname[size] = '\0';
13311     if (!strcmp(cname, "%")) {
13312         cname[0] = '\0';
13313     }
13314     sql = sqlite3_mprintf("select tbl_name from sqlite_master where "
13315                           "(type = 'table' or type = 'view') "
13316                           "and tbl_name %s %Q", npatt ? "like" : "=", tname);
13317     if (!sql) {
13318         return nomem(s);
13319     }
13320     sret = starttran(s);
13321     if (sret != SQL_SUCCESS) {
13322         sqlite3_free(sql);
13323         return sret;
13324     }
13325     dbtraceapi(d, "sqlite3_get_table", sql);
13326     ret = sqlite3_get_table(d->sqlite, sql, &trows, &tnrows, &tncols, &errp);
13327     sqlite3_free(sql);
13328     if (ret != SQLITE_OK) {
13329         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
13330                 errp ? errp : "unknown error", ret);
13331         if (errp) {
13332             sqlite3_free(errp);
13333             errp = NULL;
13334         }
13335         return SQL_ERROR;       
13336     }
13337     if (errp) {
13338         sqlite3_free(errp);
13339         errp = NULL;
13340     }
13341     /* pass 1: compute number of rows of result set */
13342     if (tncols * tnrows <= 0) {
13343         sqlite3_free_table(trows);
13344         return SQL_SUCCESS;
13345     }
13346     size = 0;
13347     for (i = 1; i <= tnrows; i++) {
13348         sql = sqlite3_mprintf("PRAGMA table_info(%Q)", trows[i]);
13349         if (!sql) {
13350             sqlite3_free_table(trows);
13351             return nomem(s);
13352         }
13353         dbtraceapi(d, "sqlite3_get_table", sql);
13354         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
13355         sqlite3_free(sql);
13356         if (ret != SQLITE_OK) {
13357             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
13358                     errp ? errp : "unknown error", ret);
13359             if (errp) {
13360                 sqlite3_free(errp);
13361                 errp = NULL;
13362             }
13363             sqlite3_free_table(trows);
13364             return SQL_ERROR;   
13365         }
13366         if (errp) {
13367             sqlite3_free(errp);
13368             errp = NULL;
13369         }
13370         if (ncols * nrows > 0) {
13371             namec = -1;
13372             for (k = 0; k < ncols; k++) {
13373                 if (strcmp(rowp[k], "name") == 0) {
13374                     namec = k;
13375                     break;
13376                 }
13377             }
13378             if (cname[0]) {
13379                 if (namec >= 0) {
13380                     for (k = 1; k <= nrows; k++) {
13381                         if (namematch(rowp[k * ncols + namec], cname, 1)) {
13382                             size++;
13383                         }
13384                     }
13385                 }
13386             } else {
13387                 size += nrows;
13388             }
13389         }
13390         sqlite3_free_table(rowp);
13391     }
13392     /* pass 2: fill result set */
13393     if (size <= 0) {
13394         sqlite3_free_table(trows);
13395         return SQL_SUCCESS;
13396     }
13397     s->nrows = size;
13398     size = (size + 1) * asize;
13399     s->rows = xmalloc((size + 1) * sizeof (char *));
13400     if (!s->rows) {
13401         s->nrows = 0;
13402         sqlite3_free_table(trows);
13403         return nomem(s);
13404     }
13405     s->rows[0] = (char *) size;
13406     s->rows += 1;
13407     memset(s->rows, 0, sizeof (char *) * size);
13408     s->rowfree = freerows;
13409     roffs = 1;
13410     for (i = 1; i <= tnrows; i++) {
13411         sql = sqlite3_mprintf("PRAGMA table_info(%Q)", trows[i]);
13412         if (!sql) {
13413             sqlite3_free_table(trows);
13414             return nomem(s);
13415         }
13416         dbtraceapi(d, "sqlite3_get_table", sql);
13417         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
13418         sqlite3_free(sql);
13419         if (ret != SQLITE_OK) {
13420             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
13421                     errp ? errp : "unknown error", ret);
13422             if (errp) {
13423                 sqlite3_free(errp);
13424                 errp = NULL;
13425             }
13426             sqlite3_free_table(trows);
13427             return SQL_ERROR;   
13428         }
13429         if (errp) {
13430             sqlite3_free(errp);
13431             errp = NULL;
13432         }
13433         if (ncols * nrows > 0) {
13434             int m, mr, nr = nrows;
13435 
13436             namec = -1;
13437             for (k = 0; k < ncols; k++) {
13438                 if (strcmp(rowp[k], "name") == 0) {
13439                     namec = k;
13440                     break;
13441                 }
13442             }
13443             if (cname[0]) {
13444                 nr = 0;
13445                 if (namec >= 0) {
13446                     for (k = 1; k <= nrows; k++) {
13447                         if (namematch(rowp[k * ncols + namec], cname, 1)) {
13448                             nr++;
13449                         }
13450                     }
13451                 }
13452             }
13453             for (k = 0; k < nr; k++) {
13454                 m = asize * (roffs + k);
13455                 s->rows[m + 0] = xstrdup("");
13456 #if defined(_WIN32) || defined(_WIN64)
13457                 s->rows[m + 1] = xstrdup(d->xcelqrx ? "main" : "");
13458 #else
13459                 s->rows[m + 1] = xstrdup("");
13460 #endif
13461                 s->rows[m + 2] = xstrdup(trows[i]);
13462                 s->rows[m + 8] = xstrdup("10");
13463                 s->rows[m + 9] = xstrdup("0");
13464                 s->rows[m + 15] = xstrdup("16384");
13465             }
13466             for (k = 0; nr && k < ncols; k++) {
13467                 if (strcmp(rowp[k], "cid") == 0) {
13468                     for (mr = 0, m = 1; m <= nrows; m++) {
13469                         char buf[256];
13470                         int ir, coln = k;
13471 
13472                         if (cname[0] &&
13473                             !namematch(rowp[m * ncols + namec], cname, 1)) {
13474                             continue;
13475                         }
13476                         ir = asize * (roffs + mr);
13477                         sscanf(rowp[m * ncols + k], "%d", &coln);
13478                         sprintf(buf, "%d", coln + 1);
13479                         s->rows[ir + 16] = xstrdup(buf);
13480                         ++mr;
13481                     }
13482                 } else if (k == namec) {
13483                     for (mr = 0, m = 1; m <= nrows; m++) {
13484                         int ir;
13485 
13486                         if (cname[0] &&
13487                             !namematch(rowp[m * ncols + namec], cname, 1)) {
13488                             continue;
13489                         }
13490                         ir = asize * (roffs + mr);
13491                         s->rows[ir + 3] = xstrdup(rowp[m * ncols + k]);
13492                         ++mr;
13493                     }
13494                 } else if (strcmp(rowp[k], "notnull") == 0) {
13495                     for (mr = 0, m = 1; m <= nrows; m++) {
13496                         int ir;
13497 
13498                         if (cname[0] &&
13499                             !namematch(rowp[m * ncols + namec], cname, 1)) {
13500                             continue;
13501                         }
13502                         ir = asize * (roffs + mr);
13503                         if (*rowp[m * ncols + k] != '0') {
13504                             s->rows[ir + 10] = xstrdup(stringify(SQL_FALSE));
13505                         } else {
13506                             s->rows[ir + 10] = xstrdup(stringify(SQL_TRUE));
13507                         }
13508                         s->rows[ir + 17] =
13509                             xstrdup((*rowp[m * ncols + k] != '0') ?
13510                                     "NO" : "YES");
13511                         ++mr;
13512                     }
13513                 } else if (strcmp(rowp[k], "dflt_value") == 0) {
13514                     for (mr = 0, m = 1; m <= nrows; m++) {
13515                         char *dflt = unquote(rowp[m * ncols + k]);
13516                         int ir;
13517 
13518                         if (cname[0] &&
13519                             !namematch(rowp[m * ncols + namec], cname, 1)) {
13520                             continue;
13521                         }
13522                         ir = asize * (roffs + mr);
13523                         s->rows[ir + 12] = xstrdup(dflt ? dflt : "NULL");
13524                         ++mr;
13525                     }
13526                 } else if (strcmp(rowp[k], "type") == 0) {
13527                     for (mr = 0, m = 1; m <= nrows; m++) {
13528                         char *typename = rowp[m * ncols + k];
13529                         int sqltype, mm, dd, ir;
13530                         char buf[256];
13531 
13532                         if (cname[0] &&
13533                             !namematch(rowp[m * ncols + namec], cname, 1)) {
13534                             continue;
13535                         }
13536                         ir = asize * (roffs + mr);
13537                         s->rows[ir + 5] = xstrdup(typename);
13538                         sqltype = mapsqltype(typename, NULL, *s->ov3,
13539                                              s->nowchar[0], s->dobigint);
13540                         getmd(typename, sqltype, &mm, &dd);
13541 #ifdef SQL_LONGVARCHAR
13542                         if (sqltype == SQL_VARCHAR && mm > 255) {
13543                             sqltype = SQL_LONGVARCHAR;
13544                         }
13545 #endif
13546 #ifdef WINTERFACE
13547 #ifdef SQL_WLONGVARCHAR
13548                         if (sqltype == SQL_WVARCHAR && mm > 255) {
13549                             sqltype = SQL_WLONGVARCHAR;
13550                         }
13551 #endif
13552 #endif
13553                         if (sqltype == SQL_VARBINARY && mm > 255) {
13554                             sqltype = SQL_LONGVARBINARY;
13555                         }
13556                         sprintf(buf, "%d", sqltype);
13557                         s->rows[ir + 4] = xstrdup(buf);
13558                         s->rows[ir + 13] = xstrdup(buf);
13559                         sprintf(buf, "%d", mm);
13560                         s->rows[ir + 7] = xstrdup(buf);
13561                         sprintf(buf, "%d", dd);
13562                         s->rows[ir + 6] = xstrdup(buf);
13563                         ++mr;
13564                     }
13565                 }
13566             }
13567             roffs += nr;
13568         }
13569         sqlite3_free_table(rowp);
13570     }
13571     sqlite3_free_table(trows);
13572     return SQL_SUCCESS;
13573 }
13574 
13575 #ifndef WINTERFACE
13576 
13590 SQLRETURN SQL_API
13591 SQLColumns(SQLHSTMT stmt,
13592            SQLCHAR *cat, SQLSMALLINT catLen,
13593            SQLCHAR *schema, SQLSMALLINT schemaLen,
13594            SQLCHAR *table, SQLSMALLINT tableLen,
13595            SQLCHAR *col, SQLSMALLINT colLen)
13596 {
13597 #if defined(_WIN32) || defined(_WIN64)
13598     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
13599 #endif
13600     SQLRETURN ret;
13601 
13602     HSTMT_LOCK(stmt);
13603 #if defined(_WIN32) || defined(_WIN64)
13604     if (!((STMT *) stmt)->oemcp[0]) {
13605         ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
13606                          table, tableLen, col, colLen);
13607         goto done2;
13608     }
13609     if (cat) {
13610         c = wmb_to_utf_c((char *) cat, catLen);
13611         if (!c) {
13612             ret = nomem((STMT *) stmt);
13613             goto done;
13614         }
13615     }
13616     if (schema) {
13617         s = wmb_to_utf_c((char *) schema, schemaLen);
13618         if (!s) {
13619             ret = nomem((STMT *) stmt);
13620             goto done;
13621         }
13622     }
13623     if (table) {
13624         t = wmb_to_utf_c((char *) table, tableLen);
13625         if (!t) {
13626             ret = nomem((STMT *) stmt);
13627             goto done;
13628         }
13629     }
13630     if (col) {
13631         k = wmb_to_utf_c((char *) col, colLen);
13632         if (!k) {
13633             ret = nomem((STMT *) stmt);
13634             goto done;
13635         }
13636     }
13637     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
13638                      (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
13639 #else
13640     ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
13641                      table, tableLen, col, colLen);
13642 #endif
13643 #if defined(_WIN32) || defined(_WIN64)
13644 done:
13645     uc_free(k);
13646     uc_free(t);
13647     uc_free(s);
13648     uc_free(c);
13649 done2:
13650     ;
13651 #endif
13652     HSTMT_UNLOCK(stmt);
13653     return ret;
13654 }
13655 #endif
13656 
13657 #ifdef WINTERFACE
13658 
13672 SQLRETURN SQL_API
13673 SQLColumnsW(SQLHSTMT stmt,
13674             SQLWCHAR *cat, SQLSMALLINT catLen,
13675             SQLWCHAR *schema, SQLSMALLINT schemaLen,
13676             SQLWCHAR *table, SQLSMALLINT tableLen,
13677             SQLWCHAR *col, SQLSMALLINT colLen)
13678 {
13679     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
13680     SQLRETURN ret;
13681 
13682     HSTMT_LOCK(stmt);
13683     if (cat) {
13684         c = uc_to_utf_c(cat, catLen);
13685         if (!c) {
13686             ret = nomem((STMT *) stmt);
13687             goto done;
13688         }
13689     }
13690     if (schema) {
13691         s = uc_to_utf_c(schema, schemaLen);
13692         if (!s) {
13693             ret = nomem((STMT *) stmt);
13694             goto done;
13695         }
13696     }
13697     if (table) {
13698         t = uc_to_utf_c(table, tableLen);
13699         if (!t) {
13700             ret = nomem((STMT *) stmt);
13701             goto done;
13702         }
13703     }
13704     if (col) {
13705         k = uc_to_utf_c(col, colLen);
13706         if (!k) {
13707             ret = nomem((STMT *) stmt);
13708             goto done;
13709         }
13710     }
13711     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
13712                      (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
13713 done:
13714     uc_free(k);
13715     uc_free(t);
13716     uc_free(s);
13717     uc_free(c);
13718     HSTMT_UNLOCK(stmt);
13719     return ret;
13720 
13721 }
13722 #endif
13723 
13728 static COL typeSpec2[] = {
13729     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
13730     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
13731     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 9 },
13732     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
13733     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
13734     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
13735     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
13736     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
13737     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
13738     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
13739     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
13740     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
13741     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
13742     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
13743     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
13744 };
13745 
13746 static COL typeSpec3[] = {
13747     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
13748     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
13749     { "SYSTEM", "TYPE", "COLUMN_SIZE", SQL_INTEGER, 9 },
13750     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
13751     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
13752     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
13753     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
13754     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
13755     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
13756     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
13757     { "SYSTEM", "TYPE", "FIXED_PREC_SCALE", SQL_SMALLINT, 2 },
13758     { "SYSTEM", "TYPE", "AUTO_UNIQUE_VALUE", SQL_SMALLINT, 2 },
13759     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
13760     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
13761     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 },
13762     { "SYSTEM", "TYPE", "SQL_DATA_TYPE", SQL_SMALLINT, 2 },
13763     { "SYSTEM", "TYPE", "SQL_DATETIME_SUB", SQL_SMALLINT, 2 },
13764     { "SYSTEM", "TYPE", "NUM_PREC_RADIX", SQL_INTEGER, 4 },
13765     { "SYSTEM", "TYPE", "INTERVAL_PRECISION", SQL_SMALLINT, 2 }
13766 };
13767 
13778 static void
13779 mktypeinfo(STMT *s, int row, int asize, char *typename, int type, int tind)
13780 {
13781     int offs = row * asize;
13782     char *tcode, *crpar = NULL, *quote = NULL, *sign = stringify(SQL_FALSE);
13783     static char tcodes[32 * 32];
13784 
13785     if (tind <= 0) {
13786         tind = row;
13787     }
13788     tcode = tcodes + tind * 32;
13789     sprintf(tcode, "%d", type);
13790     s->rows[offs + 0] = typename;
13791     s->rows[offs + 1] = tcode;
13792     if (asize >= 17) {
13793         s->rows[offs + 15] = tcode;
13794         s->rows[offs + 16] = "0";
13795     }
13796     switch (type) {
13797     default:
13798 #ifdef SQL_LONGVARCHAR
13799     case SQL_LONGVARCHAR:
13800 #ifdef WINTERFACE
13801     case SQL_WLONGVARCHAR:
13802 #endif
13803         crpar = "length";
13804         quote = "'";
13805         sign = NULL;
13806         s->rows[offs + 2] = "65536";
13807         break;
13808 #endif
13809 #ifdef SQL_BIT
13810     case SQL_BIT:
13811         sign = NULL;
13812         s->rows[offs + 2] = "1";
13813         break;
13814 #endif
13815     case SQL_CHAR:
13816     case SQL_VARCHAR:
13817 #ifdef WINTERFACE
13818     case SQL_WCHAR:
13819     case SQL_WVARCHAR:
13820 #endif
13821         s->rows[offs + 2] = "255";
13822         crpar = "length";
13823         quote = "'";
13824         sign = NULL;
13825         break;
13826     case SQL_TINYINT:
13827         s->rows[offs + 2] = "3";
13828         break;
13829     case SQL_SMALLINT:
13830         s->rows[offs + 2] = "5";
13831         break;
13832     case SQL_INTEGER:
13833         s->rows[offs + 2] = "9";
13834         break;
13835 #ifdef SQL_BIGINT
13836     case SQL_BIGINT:
13837         s->rows[offs + 2] = "19";
13838         break;
13839 #endif
13840     case SQL_FLOAT:
13841         s->rows[offs + 2] = "7";
13842         break;
13843     case SQL_DOUBLE:
13844         s->rows[offs + 2] = "15";
13845         break;
13846 #ifdef SQL_TYPE_DATE
13847     case SQL_TYPE_DATE:
13848 #endif
13849     case SQL_DATE:
13850         s->rows[offs + 2] = "10";
13851         quote = "'";
13852         sign = NULL;
13853         break;
13854 #ifdef SQL_TYPE_TIME
13855     case SQL_TYPE_TIME:
13856 #endif
13857     case SQL_TIME:
13858         s->rows[offs + 2] = "8";
13859         quote = "'";
13860         sign = NULL;
13861         break;
13862 #ifdef SQL_TYPE_TIMESTAMP
13863     case SQL_TYPE_TIMESTAMP:
13864 #endif
13865     case SQL_TIMESTAMP:
13866         s->rows[offs + 2] = "32";
13867         quote = "'";
13868         sign = NULL;
13869         break;
13870     case SQL_VARBINARY:
13871         sign = NULL;
13872         s->rows[offs + 2] = "255";
13873         break;
13874     case SQL_LONGVARBINARY:
13875         sign = NULL;
13876         s->rows[offs + 2] = "65536";
13877         break;
13878     }
13879     s->rows[offs + 3] = s->rows[offs + 4] = quote;
13880     s->rows[offs + 5] = crpar;
13881     s->rows[offs + 6] = stringify(SQL_NULLABLE);
13882     s->rows[offs + 7] = stringify(SQL_FALSE);
13883     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
13884     s->rows[offs + 9] = sign;
13885     s->rows[offs + 10] = stringify(SQL_FALSE);
13886     s->rows[offs + 11] = stringify(SQL_FALSE);
13887     s->rows[offs + 12] = typename;
13888     switch (type) {
13889     case SQL_DATE:
13890     case SQL_TIME:
13891         s->rows[offs + 13] = "0";
13892         s->rows[offs + 14] = "0";
13893         break;
13894 #ifdef SQL_TYPE_TIMESTAMP
13895     case SQL_TYPE_TIMESTAMP:
13896 #endif
13897     case SQL_TIMESTAMP:
13898         s->rows[offs + 13] = "0";
13899         s->rows[offs + 14] = "3";
13900         break;
13901     default:
13902         s->rows[offs + 13] = NULL;
13903         s->rows[offs + 14] = NULL;
13904         break;
13905     }
13906 }
13907 
13916 static int
13917 typeinfosort(const void *a, const void *b)
13918 {
13919     char **pa = (char **) a;
13920     char **pb = (char **) b;
13921     int na, nb;
13922 
13923     na = strtol(pa[1], NULL, 0);
13924     nb = strtol(pb[1], NULL, 0);
13925     return na - nb;
13926 }
13927 
13935 static SQLRETURN
13936 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
13937 {
13938     SQLRETURN ret;
13939     STMT *s;
13940     int asize;
13941 
13942     ret = mkresultset(stmt, typeSpec2, array_size(typeSpec2),
13943                       typeSpec3, array_size(typeSpec3), &asize);
13944     if (ret != SQL_SUCCESS) {
13945         return ret;
13946     }
13947     s = (STMT *) stmt;
13948 #ifdef SQL_LONGVARCHAR
13949     s->nrows = (sqltype == SQL_ALL_TYPES) ? 13 : 1;
13950 #else
13951     s->nrows = (sqltype == SQL_ALL_TYPES) ? 12 : 1;
13952 #endif
13953     if (sqltype == SQL_ALL_TYPES) {
13954 #ifdef WINTERFACE
13955         s->nrows += 2;
13956 #ifdef SQL_WLONGVARCHAR
13957         s->nrows += 2;
13958 #endif
13959 #endif
13960     }
13961     if (sqltype == SQL_ALL_TYPES) {
13962         s->nrows += 2;
13963 #ifdef SQL_BIT
13964         s->nrows += 1;
13965 #endif
13966 #ifdef SQL_BIGINT
13967         s->nrows += 1;
13968 #endif
13969     }
13970     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1) * asize);
13971     if (!s->rows) {
13972         s->nrows = 0;
13973         return nomem(s);
13974     }
13975 #ifdef MEMORY_DEBUG
13976     s->rowfree = xfree__;
13977 #else
13978     s->rowfree = sqlite3_free;
13979 #endif
13980     memset(s->rows, 0, sizeof (char *) * (s->nrows + 1) * asize);
13981     if (sqltype == SQL_ALL_TYPES) {
13982         int cc = 1;
13983 
13984         mktypeinfo(s, cc++, asize, "varchar", SQL_VARCHAR, 0);
13985         mktypeinfo(s, cc++, asize, "tinyint", SQL_TINYINT, 0);
13986         mktypeinfo(s, cc++, asize, "smallint", SQL_SMALLINT, 0);
13987         mktypeinfo(s, cc++, asize, "integer", SQL_INTEGER, 0);
13988         mktypeinfo(s, cc++, asize, "float", SQL_FLOAT, 0);
13989         mktypeinfo(s, cc++, asize, "double", SQL_DOUBLE, 0);
13990 #ifdef SQL_TYPE_DATE
13991         mktypeinfo(s, cc++, asize, "date",
13992                    (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
13993 #else
13994         mktypeinfo(s, cc++, asize, "date", SQL_DATE, 0);
13995 #endif
13996 #ifdef SQL_TYPE_TIME
13997         mktypeinfo(s, cc++, asize, "time",
13998                    (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
13999 #else
14000         mktypeinfo(s, cc++, asize, "time", SQL_TIME, 0);
14001 #endif
14002 #ifdef SQL_TYPE_TIMESTAMP
14003         mktypeinfo(s, cc++, asize, "timestamp",
14004                    (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
14005 #else
14006         mktypeinfo(s, cc++, asize, "timestamp", SQL_TIMESTAMP, 0);
14007 #endif
14008         mktypeinfo(s, cc++, asize, "char", SQL_CHAR, 0);
14009         mktypeinfo(s, cc++, asize, "numeric", SQL_DOUBLE, 0);
14010 #ifdef SQL_LONGVARCHAR
14011         mktypeinfo(s, cc++, asize, "text", SQL_LONGVARCHAR, 0);
14012         mktypeinfo(s, cc++, asize, "longvarchar", SQL_LONGVARCHAR, 0);
14013 #else
14014         mktypeinfo(s, cc++, asize, "text", SQL_VARCHAR, 0);
14015 #endif
14016         mktypeinfo(s, cc++, asize, "varbinary", SQL_VARBINARY, 0);
14017         mktypeinfo(s, cc++, asize, "longvarbinary", SQL_LONGVARBINARY, 0);
14018 #ifdef SQL_BIT
14019         mktypeinfo(s, cc++, asize, "bit", SQL_BIT, 0);
14020 #endif
14021 #ifdef SQL_BIGINT
14022         mktypeinfo(s, cc++, asize, "bigint", SQL_BIGINT, 0);
14023 #endif
14024 #ifdef WINTERFACE
14025         mktypeinfo(s, cc++, asize, "wvarchar", SQL_WVARCHAR, 0);
14026         mktypeinfo(s, cc++, asize, "wchar", SQL_WCHAR, 0);
14027 #ifdef SQL_WLONGVARCHAR
14028         mktypeinfo(s, cc++, asize, "wtext", SQL_WLONGVARCHAR, 0);
14029         mktypeinfo(s, cc++, asize, "longwvarchar", SQL_WLONGVARCHAR, 0);
14030 #endif
14031 #endif
14032         qsort(s->rows + asize, s->nrows, sizeof (char *) * asize,
14033               typeinfosort);
14034     } else {
14035         switch (sqltype) {
14036         case SQL_CHAR:
14037             mktypeinfo(s, 1, asize, "char", SQL_CHAR, 10);
14038             break;
14039         case SQL_VARCHAR:
14040             mktypeinfo(s, 1, asize, "varchar", SQL_VARCHAR, 1);
14041             break;
14042         case SQL_TINYINT:
14043             mktypeinfo(s, 1, asize, "tinyint", SQL_TINYINT, 2);
14044             break;
14045         case SQL_SMALLINT:
14046             mktypeinfo(s, 1, asize, "smallint", SQL_SMALLINT, 3);
14047             break;
14048         case SQL_INTEGER:
14049             mktypeinfo(s, 1, asize, "integer", SQL_INTEGER, 4);
14050             break;
14051         case SQL_FLOAT:
14052             mktypeinfo(s, 1, asize, "float", SQL_FLOAT, 5);
14053             break;
14054         case SQL_DOUBLE:
14055             mktypeinfo(s, 1, asize, "double", SQL_DOUBLE, 6);
14056             break;
14057 #ifdef SQL_TYPE_DATE
14058         case SQL_TYPE_DATE:
14059             mktypeinfo(s, 1, asize, "date", SQL_TYPE_DATE, 25);
14060             break;
14061 #endif
14062         case SQL_DATE:
14063             mktypeinfo(s, 1, asize, "date", SQL_DATE, 7);
14064             break;
14065 #ifdef SQL_TYPE_TIME
14066         case SQL_TYPE_TIME:
14067             mktypeinfo(s, 1, asize, "time", SQL_TYPE_TIME, 26);
14068             break;
14069 #endif
14070         case SQL_TIME:
14071             mktypeinfo(s, 1, asize, "time", SQL_TIME, 8);
14072             break;
14073 #ifdef SQL_TYPE_TIMESTAMP
14074         case SQL_TYPE_TIMESTAMP:
14075             mktypeinfo(s, 1, asize, "timestamp", SQL_TYPE_TIMESTAMP, 27);
14076             break;
14077 #endif
14078         case SQL_TIMESTAMP:
14079             mktypeinfo(s, 1, asize, "timestamp", SQL_TIMESTAMP, 9);
14080             break;
14081 #ifdef SQL_LONGVARCHAR
14082         case SQL_LONGVARCHAR:
14083             mktypeinfo(s, 1, asize, "longvarchar", SQL_LONGVARCHAR, 12);
14084             break;
14085 #endif
14086         case SQL_VARBINARY:
14087             mktypeinfo(s, 1, asize, "varbinary", SQL_VARBINARY, 30);
14088             break;
14089         case SQL_LONGVARBINARY:
14090             mktypeinfo(s, 1, asize, "longvarbinary", SQL_LONGVARBINARY, 31);
14091             break;
14092 #ifdef SQL_BIT
14093         case SQL_BIT:
14094             mktypeinfo(s, 1, asize, "bit", SQL_BIT, 29);
14095             break;
14096 #endif
14097 #ifdef SQL_BIGINT
14098         case SQL_BIGINT:
14099             mktypeinfo(s, 1, asize, "bigint", SQL_BIGINT, 28);
14100             break;
14101 #endif
14102 #ifdef WINTERFACE
14103 #ifdef SQL_WCHAR
14104         case SQL_WCHAR:
14105             mktypeinfo(s, 1, asize, "wchar", SQL_WCHAR, 18);
14106             break;
14107 #endif
14108 #ifdef SQL_WVARCHAR
14109         case SQL_WVARCHAR:
14110             mktypeinfo(s, 1, asize, "wvarchar", SQL_WVARCHAR, 19);
14111             break;
14112 #endif
14113 #ifdef SQL_WLONGVARCHAR
14114         case SQL_WLONGVARCHAR:
14115             mktypeinfo(s, 1, asize, "longwvarchar", SQL_WLONGVARCHAR, 20);
14116             break;
14117 #endif
14118 #endif
14119         default:
14120             s->nrows = 0;
14121         }
14122     }
14123     return SQL_SUCCESS;
14124 }
14125 
14126 #ifndef WINTERFACE
14127 
14134 SQLRETURN SQL_API
14135 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
14136 {
14137     SQLRETURN ret;
14138 
14139     HSTMT_LOCK(stmt);
14140     ret = drvgettypeinfo(stmt, sqltype);
14141     HSTMT_UNLOCK(stmt);
14142     return ret;
14143 }
14144 #endif
14145 
14146 #ifdef WINTERFACE
14147 
14154 SQLRETURN SQL_API
14155 SQLGetTypeInfoW(SQLHSTMT stmt, SQLSMALLINT sqltype)
14156 {
14157     SQLRETURN ret;
14158 
14159     HSTMT_LOCK(stmt);
14160     ret = drvgettypeinfo(stmt, sqltype);
14161     HSTMT_UNLOCK(stmt);
14162     return ret;
14163 }
14164 #endif
14165 
14170 static COL statSpec2[] = {
14171     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
14172     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
14173     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
14174     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
14175     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
14176     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
14177     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
14178     { "SYSTEM", "STATISTICS", "SEQ_IN_INDEX", SQL_SMALLINT, 50 },
14179     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
14180     { "SYSTEM", "STATISTICS", "COLLATION", SCOL_CHAR, 1 },
14181     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
14182     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
14183     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
14184 };
14185 
14186 static COL statSpec3[] = {
14187     { "SYSTEM", "STATISTICS", "TABLE_CAT", SCOL_VARCHAR, 50 },
14188     { "SYSTEM", "STATISTICS", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
14189     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
14190     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
14191     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
14192     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
14193     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
14194     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
14195     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
14196     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
14197     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
14198     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
14199     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
14200 };
14201 
14216 static SQLRETURN
14217 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
14218               SQLCHAR *schema, SQLSMALLINT schemaLen,
14219               SQLCHAR *table, SQLSMALLINT tableLen,
14220               SQLUSMALLINT itype, SQLUSMALLINT resv)
14221 {
14222     SQLRETURN sret;
14223     STMT *s;
14224     DBC *d;
14225     int i, asize, ret, nrows, ncols, offs, namec, uniquec, addipk = 0;
14226     PTRDIFF_T size;
14227     char **rowp, *errp = NULL, *sql, tname[512];
14228 
14229     sret = mkresultset(stmt, statSpec2, array_size(statSpec2),
14230                        statSpec3, array_size(statSpec3), &asize);
14231     if (sret != SQL_SUCCESS) {
14232         return sret;
14233     }
14234     s = (STMT *) stmt;
14235     d = (DBC *) s->dbc;
14236     if (!table || table[0] == '\0' || table[0] == '%') {
14237         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
14238         return SQL_ERROR;
14239     }
14240     if (tableLen == SQL_NTS) {
14241         size = sizeof (tname) - 1;
14242     } else {
14243         size = min(sizeof (tname) - 1, tableLen);
14244     }
14245     strncpy(tname, (char *) table, size);
14246     tname[size] = '\0';
14247     unescpat(tname);
14248     sret = starttran(s);
14249     if (sret != SQL_SUCCESS) {
14250         return sret;
14251     }
14252     /*
14253      * Try integer primary key (autoincrement) first
14254      */
14255     if (itype == SQL_INDEX_UNIQUE || itype == SQL_INDEX_ALL) {
14256         rowp = 0;
14257         ret = SQLITE_ERROR;
14258         sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
14259         if (sql) {
14260             dbtraceapi(d, "sqlite3_get_table", sql);
14261             ret = sqlite3_get_table(d->sqlite, sql, &rowp,
14262                                     &nrows, &ncols, NULL);
14263             sqlite3_free(sql);
14264         }
14265         if (ret == SQLITE_OK) {
14266             int colid, typec, npk = 0;
14267 
14268             namec = findcol(rowp, ncols, "name");
14269             uniquec = findcol(rowp, ncols, "pk");
14270             typec = findcol(rowp, ncols, "type");
14271             colid = findcol(rowp, ncols, "cid");
14272             if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
14273                 goto noipk;
14274             }
14275             for (i = 1; i <= nrows; i++) {
14276                 if (*rowp[i * ncols + uniquec] != '0' &&
14277                     strlen(rowp[i * ncols + typec]) == 7 &&
14278                     strncasecmp(rowp[i * ncols + typec], "integer", 7)
14279                     == 0) {
14280                     npk++;
14281                 }
14282             }
14283             if (npk == 1) {
14284                 addipk = 1;
14285             }
14286         }
14287 noipk:
14288         sqlite3_free_table(rowp);
14289     }
14290     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
14291     if (!sql) {
14292         return nomem(s);
14293     }
14294     dbtraceapi(d, "sqlite3_get_table", sql);
14295     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
14296     sqlite3_free(sql);
14297     if (ret != SQLITE_OK) {
14298         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
14299                 errp ? errp : "unknown error", ret);
14300         if (errp) {
14301             sqlite3_free(errp);
14302             errp = NULL;
14303         }
14304         return SQL_ERROR;
14305     }
14306     if (errp) {
14307         sqlite3_free(errp);
14308         errp = NULL;
14309     }
14310     size = 0;
14311     namec = findcol(rowp, ncols, "name");
14312     uniquec = findcol(rowp, ncols, "unique");
14313     if (namec < 0 || uniquec < 0) {
14314         goto nodata;
14315     }
14316     for (i = 1; i <= nrows; i++) {
14317         int nnrows, nncols;
14318         char **rowpp;
14319         int isuniq;
14320 
14321         isuniq = *rowp[i * ncols + uniquec] != '0';
14322         if (isuniq || itype == SQL_INDEX_ALL) {
14323             ret = SQLITE_ERROR;
14324             sql = sqlite3_mprintf("PRAGMA index_info(%Q)", 
14325                                   rowp[i * ncols + namec]);
14326             if (sql) {
14327                 dbtraceapi(d, "sqlite3_get_table", sql);
14328                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
14329                                         &nnrows, &nncols, NULL);
14330                 sqlite3_free(sql);
14331             }
14332             if (ret == SQLITE_OK) {
14333                 size += nnrows;
14334                 sqlite3_free_table(rowpp);
14335             }
14336         }
14337     }
14338 nodata:
14339     if (addipk) {
14340         size++;
14341     }
14342     if (size == 0) {
14343         sqlite3_free_table(rowp);
14344         return SQL_SUCCESS;
14345     }
14346     s->nrows = size;
14347     size = (size + 1) * asize;
14348     s->rows = xmalloc((size + 1) * sizeof (char *));
14349     if (!s->rows) {
14350         s->nrows = 0;
14351         return nomem(s);
14352     }
14353     s->rows[0] = (char *) size;
14354     s->rows += 1;
14355     memset(s->rows, 0, sizeof (char *) * size);
14356     s->rowfree = freerows;
14357     offs = 0;
14358     if (addipk) {
14359         char **rowpp = 0;
14360         int nrows2, ncols2;
14361 
14362         sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
14363         if (sql) {
14364             dbtraceapi(d, "sqlite3_get_table", sql);
14365             ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
14366                                     &nrows2, &ncols2, NULL);
14367             sqlite3_free(sql);
14368         }
14369         if (ret == SQLITE_OK) {
14370             int colid, typec, roffs, namecc, uniquecc;
14371 
14372             namecc = findcol(rowpp, ncols2, "name");
14373             uniquecc = findcol(rowpp, ncols2, "pk");
14374             typec = findcol(rowpp, ncols2, "type");
14375             colid = findcol(rowpp, ncols2, "cid");
14376             if (namecc < 0 || uniquecc < 0 || typec < 0 || colid < 0) {
14377                 addipk = 0;
14378                 s->nrows--;
14379                 goto nodata2;
14380             }
14381             for (i = 1; i <= nrows2; i++) {
14382                 if (*rowpp[i * ncols2 + uniquecc] != '0' &&
14383                     strlen(rowpp[i * ncols2 + typec]) == 7 &&
14384                     strncasecmp(rowpp[i * ncols2 + typec], "integer", 7)
14385                     == 0) {
14386                     break;
14387                 }
14388             }
14389             if (i > nrows2) {
14390                 addipk = 0;
14391                 s->nrows--;
14392                 goto nodata2;
14393             }
14394             roffs = s->ncols;
14395             s->rows[roffs + 0] = xstrdup("");
14396 #if defined(_WIN32) || defined(_WIN64)
14397             s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
14398 #else
14399             s->rows[roffs + 1] = xstrdup("");
14400 #endif
14401             s->rows[roffs + 2] = xstrdup(tname);
14402             s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
14403             s->rows[roffs + 5] = xstrdup("sqlite_autoindex_0");
14404             s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
14405             s->rows[roffs + 7] = xstrdup("1");
14406             s->rows[roffs + 8] = xstrdup(rowpp[i * ncols2 + namecc]);
14407             s->rows[roffs + 9] = xstrdup("A");
14408         }
14409 nodata2:
14410         sqlite3_free_table(rowpp);
14411     }
14412     for (i = 1; i <= nrows; i++) {
14413         int nnrows, nncols;
14414         char **rowpp = 0;
14415 
14416         if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
14417             int k;
14418 
14419             ret = SQLITE_ERROR;
14420             sql = sqlite3_mprintf("PRAGMA index_info(%Q)", 
14421                                   rowp[i * ncols + namec]);
14422             if (sql) {
14423                 dbtraceapi(d, "sqlite3_get_table", sql);
14424                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
14425                                         &nnrows, &nncols, NULL);
14426                 sqlite3_free(sql);
14427             }
14428             if (ret != SQLITE_OK) {
14429                 continue;
14430             }
14431             for (k = 0; nnrows && k < nncols; k++) {
14432                 if (strcmp(rowpp[k], "name") == 0) {
14433                     int m;
14434 
14435                     for (m = 1; m <= nnrows; m++) {
14436                         int roffs = (offs + addipk + m) * s->ncols;
14437                         int isuniq;
14438 
14439                         isuniq = *rowp[i * ncols + uniquec] != '0';
14440                         s->rows[roffs + 0] = xstrdup("");
14441                         s->rows[roffs + 1] = xstrdup("");
14442                         s->rows[roffs + 2] = xstrdup(tname);
14443                         if (isuniq) {
14444                             s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
14445                         } else {
14446                             s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
14447                         }
14448                         s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
14449                         s->rows[roffs + 6] =
14450                             xstrdup(stringify(SQL_INDEX_OTHER));
14451                         s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
14452                         s->rows[roffs + 9] = xstrdup("A");
14453                     }
14454                 } else if (strcmp(rowpp[k], "seqno") == 0) {
14455                     int m;
14456 
14457                     for (m = 1; m <= nnrows; m++) {
14458                         int roffs = (offs + addipk + m) * s->ncols;
14459                         int pos = m - 1;
14460                         char buf[32];
14461 
14462                         sscanf(rowpp[m * nncols + k], "%d", &pos);
14463                         sprintf(buf, "%d", pos + 1);
14464                         s->rows[roffs + 7] = xstrdup(buf);
14465                     }
14466                 }
14467             }
14468             offs += nnrows;
14469             sqlite3_free_table(rowpp);
14470         }
14471     }
14472     sqlite3_free_table(rowp);
14473     return SQL_SUCCESS;
14474 }
14475 
14476 #ifndef WINTERFACE
14477 
14491 SQLRETURN SQL_API
14492 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
14493               SQLCHAR *schema, SQLSMALLINT schemaLen,
14494               SQLCHAR *table, SQLSMALLINT tableLen,
14495               SQLUSMALLINT itype, SQLUSMALLINT resv)
14496 {
14497 #if defined(_WIN32) || defined(_WIN64)
14498     char *c = NULL, *s = NULL, *t = NULL;
14499 #endif
14500     SQLRETURN ret;
14501 
14502     HSTMT_LOCK(stmt);
14503 #if defined(_WIN32) || defined(_WIN64)
14504     if (!((STMT *) stmt)->oemcp[0]) {
14505         ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
14506                             table, tableLen, itype, resv);
14507         goto done2;
14508     }
14509     if (cat) {
14510         c = wmb_to_utf_c((char *) cat, catLen);
14511         if (!c) {
14512             ret = nomem((STMT *) stmt);
14513             goto done;
14514         }
14515     }
14516     if (schema) {
14517         s = wmb_to_utf_c((char *) schema, schemaLen);
14518         if (!s) {
14519             ret = nomem((STMT *) stmt);
14520             goto done;
14521         }
14522     }
14523     if (table) {
14524         t = wmb_to_utf_c((char *) table, tableLen);
14525         if (!t) {
14526             ret = nomem((STMT *) stmt);
14527             goto done;
14528         }
14529     }
14530     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14531                         (SQLCHAR *) t, SQL_NTS, itype, resv);
14532 #else
14533     ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
14534                         table, tableLen, itype, resv);
14535 #endif
14536 #if defined(_WIN32) || defined(_WIN64)
14537 done:
14538     uc_free(t);
14539     uc_free(s);
14540     uc_free(c);
14541 done2:
14542     ;
14543 #endif
14544     HSTMT_UNLOCK(stmt);
14545     return ret;
14546 }
14547 #endif
14548 
14549 #ifdef WINTERFACE
14550 
14564 SQLRETURN SQL_API
14565 SQLStatisticsW(SQLHSTMT stmt, SQLWCHAR *cat, SQLSMALLINT catLen,
14566                SQLWCHAR *schema, SQLSMALLINT schemaLen,
14567                SQLWCHAR *table, SQLSMALLINT tableLen,
14568                SQLUSMALLINT itype, SQLUSMALLINT resv)
14569 {
14570     char *c = NULL, *s = NULL, *t = NULL;
14571     SQLRETURN ret;
14572 
14573     HSTMT_LOCK(stmt);
14574     if (cat) {
14575         c = uc_to_utf_c(cat, catLen);
14576         if (!c) {
14577             ret = nomem((STMT *) stmt);
14578             goto done;
14579         }
14580     }
14581     if (schema) {
14582         s = uc_to_utf_c(schema, schemaLen);
14583         if (!s) {
14584             ret = nomem((STMT *) stmt);
14585             goto done;
14586         }
14587     }
14588     if (table) {
14589         t = uc_to_utf_c(table, tableLen);
14590         if (!t) {
14591             ret = nomem((STMT *) stmt);
14592             goto done;
14593         }
14594     }
14595     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14596                         (SQLCHAR *) t, SQL_NTS, itype, resv);
14597 done:
14598     uc_free(t);
14599     uc_free(s);
14600     uc_free(c);
14601     HSTMT_UNLOCK(stmt);
14602     return ret;
14603 }
14604 #endif
14605 
14617 SQLRETURN SQL_API
14618 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
14619            SQLPOINTER val, SQLLEN len, SQLLEN *lenp)
14620 {
14621     STMT *s;
14622     SQLRETURN ret = SQL_ERROR;
14623 
14624     HSTMT_LOCK(stmt);
14625     if (stmt == SQL_NULL_HSTMT) {
14626         return SQL_INVALID_HANDLE;
14627     }
14628     s = (STMT *) stmt;
14629     if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
14630         *((long *) val) = s->rowp;
14631         if (lenp) {
14632             *lenp = sizeof (long);
14633         }
14634         ret = SQL_SUCCESS;
14635         goto done;
14636     }
14637     if (col < 1 || col > s->ncols) {
14638         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
14639         goto done;
14640     }
14641     --col;
14642     ret = getrowdata(s, col, type, val, len, lenp, 1);
14643 done:
14644     HSTMT_UNLOCK(stmt);
14645     return ret;
14646 }
14647 
14655 static SQLRETURN
14656 dofetchbind(STMT *s, int rsi)
14657 {
14658     int ret, i, withinfo = 0;
14659 
14660     s->row_status0[rsi] = SQL_ROW_SUCCESS;
14661     if (s->bkmrk && s->bkmrkcol.valp) {
14662         long *val;
14663 
14664         if (s->bind_type != SQL_BIND_BY_COLUMN) {
14665             val = (long *) ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
14666         } else {
14667             val = (long *) s->bkmrkcol.valp + rsi;
14668         }
14669         if (s->bind_offs) {
14670             val = (long *) ((char *) val + *s->bind_offs);
14671         }
14672         *val = s->rowp;
14673         if (s->bkmrkcol.lenp) {
14674             SQLLEN *ival;
14675 
14676             if (s->bind_type != SQL_BIND_BY_COLUMN) {
14677                 ival = (SQLLEN *)
14678                     ((char *) s->bkmrkcol.lenp + s->bind_type * rsi);
14679             } else {
14680                 ival = &s->bkmrkcol.lenp[rsi];
14681             }
14682             if (s->bind_offs) {
14683                 ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
14684             }
14685             *ival = sizeof (long);
14686         }
14687     }
14688     ret = SQL_SUCCESS;
14689     for (i = 0; s->bindcols && i < s->ncols; i++) {
14690         BINDCOL *b = &s->bindcols[i];
14691         SQLPOINTER dp = 0;
14692         SQLLEN *lp = 0;
14693 
14694         b->offs = 0;
14695         if (b->valp) {
14696             if (s->bind_type != SQL_BIND_BY_COLUMN) {
14697                 dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
14698             } else {
14699                 dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
14700             }
14701             if (s->bind_offs) {
14702                 dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
14703             }
14704         }
14705         if (b->lenp) {
14706             if (s->bind_type != SQL_BIND_BY_COLUMN) {
14707                 lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
14708             } else {
14709                 lp = b->lenp + rsi;
14710             }
14711             if (s->bind_offs) {
14712                 lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
14713             }
14714         }
14715         if (dp || lp) {
14716             ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
14717             if (!SQL_SUCCEEDED(ret)) {
14718                 s->row_status0[rsi] = SQL_ROW_ERROR;
14719                 break;
14720             }
14721             if (ret != SQL_SUCCESS) {
14722                 withinfo = 1;
14723 #ifdef SQL_ROW_SUCCESS_WITH_INFO
14724                 s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
14725 #endif
14726             }
14727         }
14728     }
14729     if (SQL_SUCCEEDED(ret)) {
14730         ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
14731     }
14732     return ret;
14733 }
14734 
14743 static SQLRETURN
14744 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
14745 {
14746     STMT *s;
14747     int i, withinfo = 0;
14748     SQLRETURN ret;
14749 
14750     if (stmt == SQL_NULL_HSTMT) {
14751         return SQL_INVALID_HANDLE;
14752     }
14753     s = (STMT *) stmt;
14754     for (i = 0; i < s->rowset_size; i++) {
14755         s->row_status0[i] = SQL_ROW_NOROW;
14756     }
14757     if (s->row_status) {
14758         memcpy(s->row_status, s->row_status0,
14759                sizeof (SQLUSMALLINT) * s->rowset_size);
14760     }
14761     s->row_count0 = 0;
14762     if (s->row_count) {
14763         *s->row_count = s->row_count0;
14764     }
14765     if (!s->bindcols) {
14766         for (i = 0; i < s->rowset_size; i++) {
14767             s->row_status0[i] = SQL_ROW_ERROR;
14768         }
14769         ret = SQL_ERROR;
14770         i = 0;
14771         goto done2;
14772     }
14773     if (s->isselect != 1 && s->isselect != -1) {
14774         setstat(s, -1, "no result set available", "24000");
14775         ret = SQL_ERROR;
14776         i = s->nrows;
14777         goto done2;
14778     }
14779     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
14780         setstat(s, -1, "wrong fetch direction", "01000");
14781         ret = SQL_ERROR;
14782         i = 0;
14783         goto done2;
14784     }
14785     ret = SQL_SUCCESS;
14786     i = 0;
14787     if (((DBC *) (s->dbc))->cur_s3stmt == s && s->s3stmt) {
14788         s->rowp = 0;
14789         for (; i < s->rowset_size; i++) {
14790             if (s->max_rows && s->s3stmt_rownum + 1 >= s->max_rows) {
14791                 ret = (i == 0) ? SQL_NO_DATA : SQL_SUCCESS;
14792                 break;
14793             }
14794             ret = s3stmt_step(s);
14795             if (ret != SQL_SUCCESS) {
14796                 s->row_status0[i] = SQL_ROW_ERROR;
14797                 break;
14798             }
14799             if (s->nrows < 1) {
14800                 break;
14801             }
14802             ret = dofetchbind(s, i);
14803             if (!SQL_SUCCEEDED(ret)) {
14804                 break;
14805             } else if (ret == SQL_SUCCESS_WITH_INFO) {
14806                 withinfo = 1;
14807             }
14808         }
14809     } else if (s->rows) {
14810         switch (orient) {
14811         case SQL_FETCH_NEXT:
14812             if (s->nrows < 1) {
14813                 return SQL_NO_DATA;
14814             }
14815             if (s->rowp < 0) {
14816                 s->rowp = -1;
14817             }
14818             if (s->rowp >= s->nrows) {
14819                 s->rowp = s->nrows;
14820                 return SQL_NO_DATA;
14821             }
14822             break;
14823         case SQL_FETCH_PRIOR:
14824             if (s->nrows < 1 || s->rowp <= 0) {
14825                 s->rowp = -1;
14826                 return SQL_NO_DATA;
14827             }
14828             s->rowp -= s->rowset_size + 1;
14829             if (s->rowp < -1) {
14830                 s->rowp = -1;
14831                 return SQL_NO_DATA;
14832             }
14833             break;
14834         case SQL_FETCH_FIRST:
14835             if (s->nrows < 1) {
14836                 return SQL_NO_DATA;
14837             }
14838             s->rowp = -1;
14839             break;
14840         case SQL_FETCH_LAST:
14841             if (s->nrows < 1) {
14842                 return SQL_NO_DATA;
14843             }
14844             s->rowp = s->nrows - s->rowset_size;
14845             if (--s->rowp < -1) {
14846                 s->rowp = -1;
14847             }
14848             break;
14849         case SQL_FETCH_ABSOLUTE:
14850             if (offset == 0) {
14851                 s->rowp = -1;
14852                 return SQL_NO_DATA;
14853             } else if (offset < 0) {
14854                 if (0 - offset <= s->nrows) {
14855                     s->rowp = s->nrows + offset - 1;
14856                     break;
14857                 }
14858                 s->rowp = -1;
14859                 return SQL_NO_DATA;
14860             } else if (offset > s->nrows) {
14861                 s->rowp = s->nrows;
14862                 return SQL_NO_DATA;
14863             }
14864             s->rowp = offset - 1 - 1;
14865             break;
14866         case SQL_FETCH_RELATIVE:
14867             if (offset >= 0) {
14868                 s->rowp += offset * s->rowset_size - 1;
14869                 if (s->rowp >= s->nrows) {
14870                     s->rowp = s->nrows;
14871                     return SQL_NO_DATA;
14872                 }
14873             } else {
14874                 s->rowp += offset * s->rowset_size - 1;
14875                 if (s->rowp < -1) {
14876                     s->rowp = -1;
14877                     return SQL_NO_DATA;
14878                 }
14879             }
14880             break;
14881         case SQL_FETCH_BOOKMARK:
14882             if (s->bkmrk) {
14883                 if (offset < 0 || offset >= s->nrows) {
14884                     return SQL_NO_DATA;
14885                 }
14886                 s->rowp = offset - 1;
14887                 break;
14888             }
14889             /* fall through */
14890         default:
14891             s->row_status0[0] = SQL_ROW_ERROR;
14892             ret = SQL_ERROR;
14893             goto done;
14894         }
14895         for (; i < s->rowset_size; i++) {
14896             ++s->rowp;
14897             if (s->rowp < 0 || s->rowp >= s->nrows) {
14898                 break;
14899             }
14900             ret = dofetchbind(s, i);
14901             if (!SQL_SUCCEEDED(ret)) {
14902                 break;
14903             } else if (ret == SQL_SUCCESS_WITH_INFO) {
14904                 withinfo = 1;
14905             }
14906         }
14907     }
14908 done:
14909     if (i == 0) {
14910         if (SQL_SUCCEEDED(ret)) {
14911             return SQL_NO_DATA;
14912         }
14913         return ret;
14914     }
14915     if (SQL_SUCCEEDED(ret)) {
14916         ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
14917     }
14918 done2:
14919     if (s->row_status) {
14920         memcpy(s->row_status, s->row_status0,
14921                sizeof (SQLUSMALLINT) * s->rowset_size);
14922     }
14923     s->row_count0 = i;
14924     if (s->row_count) {
14925         *s->row_count = s->row_count0;
14926     }
14927     return ret;
14928 }
14929 
14936 SQLRETURN SQL_API
14937 SQLFetch(SQLHSTMT stmt)
14938 {
14939     SQLRETURN ret;
14940 
14941     HSTMT_LOCK(stmt);
14942     ret = drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
14943     HSTMT_UNLOCK(stmt);
14944     return ret;
14945 }
14946 
14955 SQLRETURN SQL_API
14956 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLLEN offset)
14957 {
14958     SQLRETURN ret;
14959 
14960     HSTMT_LOCK(stmt);
14961     ret = drvfetchscroll(stmt, orient, offset);
14962     HSTMT_UNLOCK(stmt);
14963     return ret;
14964 }
14965 
14976 SQLRETURN SQL_API
14977 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLROWOFFSET offset,
14978                  SQLROWSETSIZE *rowcount, SQLUSMALLINT *rowstatus)
14979 {
14980     STMT *s;
14981     SQLRETURN ret;
14982     SQLUSMALLINT *rst;
14983 
14984     HSTMT_LOCK(stmt);
14985     if (stmt == SQL_NULL_HSTMT) {
14986         return SQL_INVALID_HANDLE;
14987     }
14988     s = (STMT *) stmt;
14989     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
14990     rst = s->row_status;
14991     s->row_status = 0;
14992     ret = drvfetchscroll(stmt, orient, offset);
14993     s->row_status = rst;
14994     if (rowstatus) {
14995         memcpy(rowstatus, s->row_status0,
14996                sizeof (SQLUSMALLINT) * s->rowset_size);
14997     }
14998     if (rowcount) {
14999         *rowcount = s->row_count0;
15000     }
15001     HSTMT_UNLOCK(stmt);
15002     return ret;
15003 }
15004 
15012 SQLRETURN SQL_API
15013 SQLRowCount(SQLHSTMT stmt, SQLLEN *nrows)
15014 {
15015     STMT *s;
15016 
15017     HSTMT_LOCK(stmt);
15018     if (stmt == SQL_NULL_HSTMT) {
15019         return SQL_INVALID_HANDLE;
15020     }
15021     s = (STMT *) stmt;
15022     if (nrows) {
15023         *nrows = s->isselect ? 0 : s->nrows;
15024     }
15025     HSTMT_UNLOCK(stmt);
15026     return SQL_SUCCESS;
15027 }
15028 
15036 SQLRETURN SQL_API
15037 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
15038 {
15039     STMT *s;
15040 
15041     HSTMT_LOCK(stmt);
15042     if (stmt == SQL_NULL_HSTMT) {
15043         return SQL_INVALID_HANDLE;
15044     }
15045     s = (STMT *) stmt;
15046     if (ncols) {
15047         *ncols = s->ncols;
15048     }
15049     HSTMT_UNLOCK(stmt);
15050     return SQL_SUCCESS;
15051 }
15052 
15067 static SQLRETURN
15068 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
15069                SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
15070                SQLSMALLINT *type, SQLULEN *size,
15071                SQLSMALLINT *digits, SQLSMALLINT *nullable)
15072 {
15073     STMT *s;
15074     COL *c;
15075     int didname = 0;
15076 
15077     if (stmt == SQL_NULL_HSTMT) {
15078         return SQL_INVALID_HANDLE;
15079     }
15080     s = (STMT *) stmt;
15081     if (!s->cols) {
15082         setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
15083         return SQL_ERROR;
15084     }
15085     if (col < 1 || col > s->ncols) {
15086         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
15087         return SQL_ERROR;
15088     }
15089     c = s->cols + col - 1;
15090     if (name && nameMax > 0) {
15091         strncpy((char *) name, c->column, nameMax);
15092         name[nameMax - 1] = '\0';
15093         didname = 1;
15094     }
15095     if (nameLen) {
15096         if (didname) {
15097             *nameLen = strlen((char *) name);
15098         } else {
15099             *nameLen = strlen(c->column);
15100         }
15101     }
15102     if (type) {
15103         *type = c->type;
15104 #ifdef WINTERFACE
15105         if (s->nowchar[0] || s->nowchar[1]) {
15106             switch (c->type) {
15107             case SQL_WCHAR:
15108                 *type = SQL_CHAR;
15109                 break;
15110             case SQL_WVARCHAR:
15111                 *type = SQL_VARCHAR;
15112                 break;
15113 #ifdef SQL_LONGVARCHAR
15114             case SQL_WLONGVARCHAR:
15115                 *type = SQL_LONGVARCHAR;
15116                 break;
15117 #endif
15118             }
15119         }
15120 #endif
15121     }
15122     if (size) {
15123         *size = c->size;
15124     }
15125     if (digits) {
15126         *digits = 0;
15127     }
15128     if (nullable) {
15129         *nullable = 1;
15130     }
15131     return SQL_SUCCESS;
15132 }
15133 
15134 #ifndef WINTERFACE
15135 
15149 SQLRETURN SQL_API
15150 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
15151                SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
15152                SQLSMALLINT *type, SQLULEN *size,
15153                SQLSMALLINT *digits, SQLSMALLINT *nullable)
15154 {
15155 #if defined(_WIN32) || defined(_WIN64)
15156     SQLSMALLINT len = 0;
15157 #endif
15158     SQLRETURN ret;
15159 
15160     HSTMT_LOCK(stmt);
15161 #if defined(_WIN32) || defined(_WIN64)
15162     if (!((STMT *) stmt)->oemcp[0]) {
15163         ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
15164                              type, size, digits, nullable);
15165         goto done;
15166     }
15167     ret = drvdescribecol(stmt, col, name, nameMax,
15168                          &len, type, size, digits, nullable);
15169     if (ret == SQL_SUCCESS) {
15170         if (name) {
15171             if (len > 0) {
15172                 SQLCHAR *n = NULL;
15173 
15174                 n = (SQLCHAR *) utf_to_wmb((char *) name, len);
15175                 if (n) {
15176                     strncpy((char *) name, (char *) n, nameMax);
15177                     n[len] = 0;
15178                     len = min(nameMax, strlen((char *) n));
15179                     uc_free(n);
15180                 } else {
15181                     len = 0;
15182                 }
15183             }
15184             if (len <= 0) {
15185                 len = 0;
15186                 if (nameMax > 0) {
15187                     name[0] = 0;
15188                 }
15189             }
15190         } else {
15191             STMT *s = (STMT *) stmt;
15192             COL *c = s->cols + col - 1;
15193 
15194             len = 0;
15195             if (c->column) {
15196                 len = strlen(c->column);
15197             }
15198         }
15199         if (nameLen) {
15200             *nameLen = len;
15201         }
15202     }
15203 done:
15204     ;
15205 #else
15206     ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
15207                          type, size, digits, nullable);
15208 #endif
15209     HSTMT_UNLOCK(stmt);
15210     return ret;
15211 }
15212 #endif
15213 
15214 #ifdef WINTERFACE
15215 
15229 SQLRETURN SQL_API
15230 SQLDescribeColW(SQLHSTMT stmt, SQLUSMALLINT col, SQLWCHAR *name,
15231                 SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
15232                 SQLSMALLINT *type, SQLULEN *size,
15233                 SQLSMALLINT *digits, SQLSMALLINT *nullable)
15234 {
15235     SQLRETURN ret;
15236     SQLSMALLINT len = 0;
15237 
15238     HSTMT_LOCK(stmt);
15239     ret = drvdescribecol(stmt, col, (SQLCHAR *) name,
15240                          (SQLSMALLINT) (nameMax * sizeof (SQLWCHAR)),
15241                          &len, type, size, digits, nullable);
15242     if (ret == SQL_SUCCESS) {
15243         if (name) {
15244             if (len > 0) {
15245                 SQLWCHAR *n = NULL;
15246 
15247                 n = uc_from_utf((SQLCHAR *) name, len);
15248                 if (n) {
15249                     uc_strncpy(name, n, nameMax);
15250                     n[len] = 0;
15251                     len = min(nameMax, uc_strlen(n));
15252                     uc_free(n);
15253                 } else {
15254                     len = 0;
15255                 }
15256             }
15257             if (len <= 0) {
15258                 len = 0;
15259                 if (nameMax > 0) {
15260                     name[0] = 0;
15261                 }
15262             }
15263         } else {
15264             STMT *s = (STMT *) stmt;
15265             COL *c = s->cols + col - 1;
15266 
15267             len = 0;
15268             if (c->column) {
15269                 len = strlen(c->column);
15270             }
15271         }
15272         if (nameLen) {
15273             *nameLen = len;
15274         }
15275     }
15276     HSTMT_UNLOCK(stmt);
15277     return ret;
15278 }
15279 #endif
15280 
15293 static SQLRETURN
15294 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
15295                  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
15296                  SQLLEN *val2)
15297 {
15298     STMT *s;
15299     COL *c;
15300     SQLSMALLINT dummy;
15301     char *valc = (char *) val;
15302 
15303     if (stmt == SQL_NULL_HSTMT) {
15304         return SQL_INVALID_HANDLE;
15305     }
15306     s = (STMT *) stmt;
15307     if (!s->cols) {
15308         return SQL_ERROR;
15309     }
15310     if (!valLen) {
15311         valLen = &dummy;
15312     }
15313     if (id == SQL_COLUMN_COUNT) {
15314         if (val2) {
15315             *val2 = s->ncols;
15316         }
15317         *valLen = sizeof (int);
15318         return SQL_SUCCESS;
15319     }
15320     if (id == SQL_COLUMN_TYPE && col == 0) {
15321         if (val2) {
15322             *val2 = SQL_INTEGER;
15323         }
15324         *valLen = sizeof (int);
15325         return SQL_SUCCESS;
15326     }
15327 #ifdef SQL_DESC_OCTET_LENGTH
15328     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
15329         if (val2) {
15330             *val2 = 4;
15331         }
15332         *valLen = sizeof (int);
15333         return SQL_SUCCESS;
15334     }
15335 #endif
15336     if (col < 1 || col > s->ncols) {
15337         setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
15338         return SQL_ERROR;
15339     }
15340     c = s->cols + col - 1;
15341 
15342     switch (id) {
15343     case SQL_COLUMN_LABEL:
15344         if (c->label) {
15345             if (valc && valMax > 0) {
15346                 strncpy(valc, c->label, valMax);
15347                 valc[valMax - 1] = '\0';
15348             }
15349             *valLen = strlen(c->label);
15350             goto checkLen;
15351         }
15352         /* fall through */
15353     case SQL_COLUMN_NAME:
15354     case SQL_DESC_NAME:
15355         if (valc && valMax > 0) {
15356             strncpy(valc, c->column, valMax);
15357             valc[valMax - 1] = '\0';
15358         }
15359         *valLen = strlen(c->column);
15360 checkLen:
15361         if (*valLen >= valMax) {
15362             setstat(s, -1, "data right truncated", "01004");
15363             return SQL_SUCCESS_WITH_INFO;
15364         }
15365         return SQL_SUCCESS;
15366 #ifdef SQL_DESC_BASE_COLUMN_NAME
15367         if (strchr(c->column, '(') || strchr(c->column, ')')) {
15368             valc[0] = '\0';
15369             *valLen = 0;
15370         } else if (valc && valMax > 0) {
15371             strncpy(valc, c->column, valMax);
15372             valc[valMax - 1] = '\0';
15373             *valLen = strlen(c->column);
15374         }
15375         goto checkLen;
15376 #endif
15377     case SQL_COLUMN_TYPE:
15378     case SQL_DESC_TYPE:
15379 #ifdef WINTERFACE
15380         {
15381             int type = c->type;
15382 
15383             if (s->nowchar[0] || s->nowchar[1]) {
15384                 switch (type) {
15385                 case SQL_WCHAR:
15386                     type = SQL_CHAR;
15387                     break;
15388                 case SQL_WVARCHAR:
15389                     type = SQL_VARCHAR;
15390                     break;
15391 #ifdef SQL_LONGVARCHAR
15392                 case SQL_WLONGVARCHAR:
15393                     type = SQL_LONGVARCHAR;
15394                     break;
15395                 }
15396             }
15397             if (val2) {
15398                 *val2 = type;
15399             }
15400 #endif
15401         }
15402 #else
15403         if (val2) {
15404             *val2 = c->type;
15405         }
15406 #endif
15407         *valLen = sizeof (int);
15408         return SQL_SUCCESS;
15409     case SQL_COLUMN_DISPLAY_SIZE:
15410         if (val2) {
15411             *val2 = c->size;
15412         }
15413         *valLen = sizeof (int);
15414         return SQL_SUCCESS;
15415     case SQL_COLUMN_UNSIGNED:
15416         if (val2) {
15417             *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
15418         }
15419         *valLen = sizeof (int);
15420         return SQL_SUCCESS;
15421     case SQL_COLUMN_SCALE:
15422     case SQL_DESC_SCALE:
15423         if (val2) {
15424             *val2 = c->scale;
15425         }
15426         *valLen = sizeof (int);
15427         return SQL_SUCCESS;
15428     case SQL_COLUMN_PRECISION:
15429     case SQL_DESC_PRECISION:
15430         if (val2) {
15431             switch (c->type) {
15432             case SQL_SMALLINT:
15433                 *val2 = 5;
15434                 break;
15435             case SQL_INTEGER:
15436                 *val2 = 10;
15437                 break;
15438             case SQL_FLOAT:
15439             case SQL_REAL:
15440             case SQL_DOUBLE:
15441                 *val2 = 15;
15442                 break;
15443             case SQL_DATE:
15444                 *val2 = 0;
15445                 break;
15446             case SQL_TIME:
15447                 *val2 = 0;
15448                 break;
15449 #ifdef SQL_TYPE_TIMESTAMP
15450             case SQL_TYPE_TIMESTAMP:
15451 #endif
15452             case SQL_TIMESTAMP:
15453                 *val2 = (c->prec >= 0 && c->prec <= 3) ? c->