Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

sqlite3odbc.c

Go to the documentation of this file.
00001 
00014 #include "sqlite3odbc.h"
00015 
00016 #ifndef WITHOUT_WINTERFACE
00017 #define WINTERFACE
00018 #endif
00019 
00020 #ifdef WINTERFACE
00021 #include <sqlucode.h>
00022 #endif
00023 
00024 #if defined(_WIN32) || defined(_WIN64)
00025 #include "resource3.h"
00026 #define ODBC_INI "ODBC.INI"
00027 #else
00028 #define ODBC_INI ".odbc.ini"
00029 #endif
00030 
00031 #ifndef DRIVER_VER_INFO
00032 #define DRIVER_VER_INFO "0.0"
00033 #endif
00034 
00035 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
00036 #ifdef _WIN64
00037 #define COLATTRIBUTE_LAST_ARG_TYPE SQLLEN *
00038 #else
00039 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
00040 #endif
00041 #endif
00042 
00043 #ifndef SETSTMTOPTION_LAST_ARG_TYPE
00044 #define SETSTMTOPTION_LAST_ARG_TYPE SQLROWCOUNT
00045 #endif
00046 
00047 #undef min
00048 #define min(a, b) ((a) < (b) ? (a) : (b))
00049 #undef max
00050 #define max(a, b) ((a) < (b) ? (b) : (a))
00051 
00052 #ifndef PTRDIFF_T
00053 #define PTRDIFF_T int
00054 #endif
00055 
00056 #define array_size(x) (sizeof (x) / sizeof (x[0]))
00057 
00058 #define stringify1(s) #s
00059 #define stringify(s) stringify1(s)
00060 
00061 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
00062 
00063 /* Column types for static string column descriptions (SQLTables etc.) */
00064 
00065 #if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
00066 #define SCOL_VARCHAR SQL_WVARCHAR
00067 #define SCOL_CHAR SQL_WCHAR
00068 #else
00069 #define SCOL_VARCHAR SQL_VARCHAR
00070 #define SCOL_CHAR SQL_CHAR
00071 #endif
00072 
00073 #define ENV_MAGIC  0x53544145
00074 #define DBC_MAGIC  0x53544144
00075 #define DEAD_MAGIC 0xdeadbeef
00076 
00077 static const char *xdigits = "0123456789ABCDEFabcdef";
00078 
00079 #ifdef MEMORY_DEBUG
00080 
00081 static void *
00082 xmalloc_(int n, char *file, int line)
00083 {
00084     int nn = n + 4 * sizeof (long);
00085     long *p;
00086 
00087     p = malloc(nn);
00088     if (!p) {
00089 #if (MEMORY_DEBUG > 1)
00090         fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
00091 #endif
00092         return NULL;
00093     }
00094     p[0] = 0xdead1234;
00095     nn = nn / sizeof (long) - 1;
00096     p[1] = n;
00097     p[nn] = 0xdead5678;
00098 #if (MEMORY_DEBUG > 1)
00099     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
00100 #endif
00101     return (void *) &p[2];
00102 }
00103 
00104 static void *
00105 xrealloc_(void *old, int n, char *file, int line)
00106 {
00107     int nn = n + 4 * sizeof (long), nnn;
00108     long *p, *pp;
00109 
00110     if (n == 0 || !old) {
00111         return xmalloc_(n, file, line);
00112     }
00113     p = &((long *) old)[-2];
00114     if (p[0] != 0xdead1234) {
00115         fprintf(stderr, "*** low end corruption @ %p\n", old);
00116         abort();
00117     }
00118     nnn = p[1] + 4 * sizeof (long);
00119     nnn = nnn / sizeof (long) - 1;
00120     if (p[nnn] != 0xdead5678) {
00121         fprintf(stderr, "*** high end corruption @ %p\n", old);
00122         abort();
00123     }
00124     pp = realloc(p, nn);
00125     if (!pp) {
00126 #if (MEMORY_DEBUG > 1)
00127         fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
00128 #endif
00129         return NULL;
00130     }
00131 #if (MEMORY_DEBUG > 1)
00132     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
00133 #endif
00134     p = pp;
00135     p[1] = n;
00136     nn = nn / sizeof (long) - 1;
00137     p[nn] = 0xdead5678;
00138     return (void *) &p[2];
00139 }
00140 
00141 static void
00142 xfree_(void *x, char *file, int line)
00143 {
00144     long *p;
00145     int n;
00146 
00147     if (!x) {
00148         return;
00149     }
00150     p = &((long *) x)[-2];
00151     if (p[0] != 0xdead1234) {
00152         fprintf(stderr, "*** low end corruption @ %p\n", x);
00153         abort();
00154     }
00155     n = p[1] + 4 * sizeof (long);
00156     n = n / sizeof (long) - 1;
00157     if (p[n] != 0xdead5678) {
00158         fprintf(stderr, "*** high end corruption @ %p\n", x);
00159         abort();
00160     }
00161 #if (MEMORY_DEBUG > 1)
00162     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
00163 #endif
00164     free(p);
00165 }
00166 
00167 static void
00168 xfree__(void *x)
00169 {
00170     xfree_(x, "unknown location", 0);
00171 }
00172 
00173 static char *
00174 xstrdup_(const char *str, char *file, int line)
00175 {
00176     char *p;
00177 
00178     if (!str) {
00179 #if (MEMORY_DEBUG > 1)
00180         fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
00181 #endif
00182         return NULL;
00183     }
00184     p = xmalloc_(strlen(str) + 1, file, line);
00185     if (p) {
00186         strcpy(p, str);
00187     }
00188 #if (MEMORY_DEBUG > 1)
00189     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
00190 #endif
00191     return p;
00192 }
00193 
00194 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
00195 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
00196 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
00197 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
00198 
00199 #else
00200 
00201 #define xmalloc(x)    malloc(x)
00202 #define xrealloc(x,y) realloc(x, y)
00203 #define xfree(x)      free(x)
00204 #define xstrdup(x)    strdup_(x)
00205 
00206 #endif
00207 
00208 #if defined(_WIN32) || defined(_WIN64)
00209 
00210 #define vsnprintf   _vsnprintf
00211 #define snprintf    _snprintf
00212 #define strcasecmp  _stricmp
00213 #define strncasecmp _strnicmp
00214 
00215 static HINSTANCE NEAR hModule;  /* Saved module handle for resources */
00216 
00217 #endif
00218 
00219 #if defined(_WIN32) || defined(_WIN64)
00220 
00221 /*
00222  * SQLHENV, SQLHDBC, and SQLHSTMT synchronization
00223  * is done using a critical section in ENV structure.
00224  */
00225 
00226 #define HDBC_LOCK(hdbc)                         \
00227 {                                               \
00228     DBC *d;                                     \
00229                                                 \
00230     if ((hdbc) == SQL_NULL_HDBC) {              \
00231         return SQL_INVALID_HANDLE;              \
00232     }                                           \
00233     d = (DBC *) (hdbc);                         \
00234     if (d->magic != DBC_MAGIC || !d->env) {     \
00235         return SQL_INVALID_HANDLE;              \
00236     }                                           \
00237     if (d->env->magic != ENV_MAGIC) {           \
00238         return SQL_INVALID_HANDLE;              \
00239     }                                           \
00240     EnterCriticalSection(&d->env->cs);          \
00241     d->env->owner = GetCurrentThreadId();       \
00242 }
00243 
00244 #define HDBC_UNLOCK(hdbc)                       \
00245     if ((hdbc) != SQL_NULL_HDBC) {              \
00246         DBC *d;                                 \
00247                                                 \
00248         d = (DBC *) (hdbc);                     \
00249         if (d->magic == DBC_MAGIC && d->env &&  \
00250             d->env->magic == ENV_MAGIC) {       \
00251             d->env->owner = 0;                  \
00252             LeaveCriticalSection(&d->env->cs);  \
00253         }                                       \
00254     }
00255 
00256 #define HSTMT_LOCK(hstmt)                       \
00257 {                                               \
00258     DBC *d;                                     \
00259                                                 \
00260     if ((hstmt) == SQL_NULL_HSTMT) {            \
00261         return SQL_INVALID_HANDLE;              \
00262     }                                           \
00263     d = (DBC *) ((STMT *) (hstmt))->dbc;        \
00264     if (d->magic != DBC_MAGIC || !d->env) {     \
00265         return SQL_INVALID_HANDLE;              \
00266     }                                           \
00267     if (d->env->magic != ENV_MAGIC) {           \
00268         return SQL_INVALID_HANDLE;              \
00269     }                                           \
00270     EnterCriticalSection(&d->env->cs);          \
00271     d->env->owner = GetCurrentThreadId();       \
00272 }
00273 
00274 #define HSTMT_UNLOCK(hstmt)                     \
00275     if ((hstmt) != SQL_NULL_HSTMT) {            \
00276         DBC *d;                                 \
00277                                                 \
00278         d = (DBC *) ((STMT *) (hstmt))->dbc;    \
00279         if (d->magic == DBC_MAGIC && d->env &&  \
00280             d->env->magic == ENV_MAGIC) {       \
00281             d->env->owner = 0;                  \
00282             LeaveCriticalSection(&d->env->cs);  \
00283         }                                       \
00284     }
00285 
00286 #else
00287 
00288 /*
00289  * On UN*X assume that we are single-threaded or
00290  * the driver manager provides serialization for us.
00291  *
00292  * In iODBC (3.52.x) serialization can be turned
00293  * on using the DSN property "ThreadManager=yes".
00294  *
00295  * In unixODBC that property is named
00296  * "Threading=0-3" and takes one of these values:
00297  *
00298  *   0 - no protection
00299  *   1 - statement level protection
00300  *   2 - connection level protection
00301  *   3 - environment level protection
00302  *
00303  * unixODBC 2.2.11 uses environment level protection
00304  * by default when it has been built with pthread
00305  * support.
00306  */
00307 
00308 #define HDBC_LOCK(hdbc)
00309 #define HDBC_UNLOCK(hdbc)
00310 #define HSTMT_LOCK(hdbc)
00311 #define HSTMT_UNLOCK(hdbc)
00312 
00313 #endif
00314 
00315 #if defined(ENABLE_NVFS) && ENABLE_NVFS
00316 extern void nvfs_init(void);
00317 extern const char *nvfs_makevfs(const char *);
00318 #endif
00319 
00320 /*
00321  * tolower() replacement w/o locale
00322  */
00323 
00324 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00325 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
00326 
00327 static int
00328 TOLOWER(int c)
00329 {
00330     if (c) {
00331         char *p = strchr(upper_chars, c);
00332 
00333         if (p) {
00334             c = lower_chars[p - upper_chars];
00335         }
00336     }
00337     return c;
00338 }
00339 
00340 /*
00341  * isdigit() replacement w/o ctype.h
00342  */
00343 
00344 static const char digit_chars[] = "0123456789";
00345 
00346 #define ISDIGIT(c) \
00347     ((c) && strchr(digit_chars, (c)) != NULL)
00348 
00349 /*
00350  * isspace() replacement w/o ctype.h
00351  */
00352 
00353 static const char space_chars[] = " \f\n\r\t\v";
00354 
00355 #define ISSPACE(c) \
00356     ((c) && strchr(space_chars, (c)) != NULL)
00357 
00358 
00359 /*
00360  * Forward declarations of static functions.
00361  */
00362 
00363 static void dbtraceapi(DBC *d, char *fn, const char *sql);
00364 static void freedyncols(STMT *s);
00365 static void freeresult(STMT *s, int clrcols);
00366 static void freerows(char **rowp);
00367 static void unbindcols(STMT *s);
00368 static void s3stmt_drop(STMT *s);
00369 
00370 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
00371 static SQLRETURN freestmt(HSTMT stmt);
00372 static SQLRETURN mkbindcols(STMT *s, int ncols);
00373 static SQLRETURN setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp);
00374 static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
00375 static SQLRETURN starttran(STMT *s);
00376 static SQLRETURN setupparam(STMT *s, char *sql, int pnum);
00377 
00378 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
00379 /* MS Access hack part 1 (reserved error -7748) */
00380 static COL *statSpec2P, *statSpec3P;
00381 #endif
00382 
00383 #if (MEMORY_DEBUG < 1)
00384 
00390 static char *
00391 strdup_(const char *str)
00392 {
00393     char *p = NULL;
00394 
00395     if (str) {
00396         p = xmalloc(strlen(str) + 1);
00397         if (p) {
00398             strcpy(p, str);
00399         }
00400     }
00401     return p;
00402 }
00403 #endif
00404 
00405 #ifdef WINTERFACE
00406 
00413 static int
00414 uc_strlen(SQLWCHAR *str)
00415 {
00416     int len = 0;
00417 
00418     if (str) {
00419         while (*str) {
00420             ++len;
00421             ++str;
00422         }
00423     }
00424     return len;
00425 }
00426 
00435 static SQLWCHAR *
00436 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
00437 {
00438     int i = 0;
00439 
00440     while (i < len) {
00441         if (!src[i]) {
00442             break;
00443         }
00444         dest[i] = src[i];
00445         ++i;
00446     }
00447     if (i < len) {
00448         dest[i] = 0;
00449     }
00450     return dest;
00451 }
00452 
00461 static void
00462 uc_from_utf_buf(unsigned char *str, int len, SQLWCHAR *uc, int ucLen)
00463 {
00464     ucLen = ucLen / sizeof (SQLWCHAR);
00465     if (!uc || ucLen < 0) {
00466         return;
00467     }
00468     if (len < 0) {
00469         len = ucLen * 5;
00470     }
00471     uc[0] = 0;
00472     if (str) {
00473         int i = 0;
00474 
00475         while (i < len && *str && i < ucLen) {
00476             unsigned char c = str[0];
00477 
00478             if (c < 0xc0) {
00479                 uc[i++] = c;
00480                 ++str;
00481             } else if (c < 0xe0) {
00482                 if ((str[1] & 0xc0) == 0x80) {
00483                     unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
00484 
00485                     uc[i++] = t;
00486                     str += 2;
00487                 } else {
00488                     uc[i++] = c;
00489                     ++str;
00490                 }
00491             } else if (c < 0xf0) {
00492                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
00493                     unsigned long t = ((c & 0x0f) << 12) |
00494                         ((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
00495 
00496                     uc[i++] = t;
00497                     str += 3;
00498                 } else {
00499                     uc[i++] = c;
00500                     ++str;
00501                 }
00502             } else if (c < 0xf8) {
00503                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
00504                     (str[3] & 0xc0) == 0x80) {
00505                     unsigned long t = ((c & 0x03) << 18) |
00506                         ((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
00507                         (str[4] & 0x3f);
00508 
00509                     if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
00510                         t >= 0x10000) {
00511                         t -= 0x10000;
00512                         uc[i++] = 0xd800 | (t & 0x3ff);
00513                         if (i >= ucLen) {
00514                             break;
00515                         }
00516                         t = 0xdc00 | ((t >> 10) & 0x3ff);
00517                     }
00518                     uc[i++] = t;
00519                     str += 4;
00520                 } else {
00521                     uc[i++] = c;
00522                     ++str;
00523                 }
00524             } else if (c < 0xfc) {
00525                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
00526                     (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80) {
00527                     unsigned long t = ((c & 0x01) << 24) |
00528                         ((str[1] & 0x3f) << 18) | ((str[2] & 0x3f) << 12) |
00529                         ((str[4] & 0x3f) << 6) | (str[5] & 0x3f);
00530 
00531                     if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
00532                         t >= 0x10000) {
00533                         t -= 0x10000;
00534                         uc[i++] = 0xd800 | (t & 0x3ff);
00535                         if (i >= ucLen) {
00536                             break;
00537                         }
00538                         t = 0xdc00 | ((t >> 10) & 0x3ff);
00539                     }
00540                     uc[i++] = t;
00541                     str += 5;
00542                 } else {
00543                     uc[i++] = c;
00544                     ++str;
00545                 }
00546             } else {
00547                 /* ignore */
00548                 ++str;
00549             }
00550         }
00551         if (i < ucLen) {
00552             uc[i] = 0;
00553         }
00554     }
00555 }
00556 
00564 static SQLWCHAR *
00565 uc_from_utf(unsigned char *str, int len)
00566 {
00567     SQLWCHAR *uc = NULL;
00568     int ucLen;
00569 
00570     if (str) {
00571         if (len == SQL_NTS) {
00572             len = strlen((char *) str);
00573         }
00574         ucLen = sizeof (SQLWCHAR) * (len + 1);
00575         uc = xmalloc(ucLen);
00576         if (uc) {
00577             uc_from_utf_buf(str, len, uc, ucLen);
00578         }
00579     }
00580     return uc;
00581 }
00582 
00590 static char *
00591 uc_to_utf(SQLWCHAR *str, int len)
00592 {
00593     int i;
00594     char *cp, *ret = NULL;
00595 
00596     if (!str) {
00597         return ret;
00598     }
00599     if (len == SQL_NTS) {
00600         len = uc_strlen(str);
00601     } else {
00602         len = len / sizeof (SQLWCHAR);
00603     }
00604     cp = xmalloc(len * 6 + 1);
00605     if (!cp) {
00606         return ret;
00607     }
00608     ret = cp;
00609     for (i = 0; i < len; i++) {
00610         unsigned long c = str[i];
00611 
00612         if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
00613             c &= 0xffff;
00614         }
00615         if (c < 0xc0) {
00616             *cp++ = c;
00617         } else if (c < 0x800) {
00618             *cp++ = 0xc0 | ((c >> 6) & 0x1f);
00619             *cp++ = 0x80 | (c & 0x3f);
00620         } else if (c < 0x10000) {
00621             if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
00622                 c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
00623                 unsigned long c2 = str[i + 1] & 0xffff;
00624 
00625                 if (c2 >= 0xdc00 && c <= 0xdfff) {
00626                     c = ((c & 0x3ff) | ((c2 & 0x3ff) << 10)) + 0x10000;
00627                     *cp++ = 0xf0 | ((c >> 18) & 0x07);
00628                     *cp++ = 0x80 | ((c >> 12) & 0x3f);
00629                     *cp++ = 0x80 | ((c >> 6) & 0x3f);
00630                     *cp++ = 0x80 | (c & 0x3f);
00631                     ++i;
00632                     continue;
00633                 }
00634             }
00635             *cp++ = 0xe0 | ((c >> 12) & 0x0f);
00636             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00637             *cp++ = 0x80 | (c & 0x3f);
00638         } else if (c < 0x200000) {
00639             *cp++ = 0xf0 | ((c >> 18) & 0x07);
00640             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00641             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00642             *cp++ = 0x80 | (c & 0x3f);
00643         } else if (c < 0x4000000) {
00644             *cp++ = 0xf8 | ((c >> 24) & 0x03);
00645             *cp++ = 0x80 | ((c >> 18) & 0x3f);
00646             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00647             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00648             *cp++ = 0x80 | (c & 0x3f);
00649         } else if (c < 0x80000000) {
00650             *cp++ = 0xfc | ((c >> 31) & 0x01);
00651             *cp++ = 0x80 | ((c >> 24) & 0x3f);
00652             *cp++ = 0x80 | ((c >> 18) & 0x3f);
00653             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00654             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00655             *cp++ = 0x80 | (c & 0x3f);
00656         }
00657     }
00658     *cp = '\0';
00659     return ret;
00660 }
00661 
00669 static char *
00670 uc_to_utf_c(SQLWCHAR *str, int len)
00671 {
00672     if (len != SQL_NTS) {
00673         len = len * sizeof (SQLWCHAR);
00674     }
00675     return uc_to_utf(str, len);
00676 }
00677 
00678 #endif /* WINTERFACE */
00679 
00680 #if defined(WINTERFACE) || defined(_WIN32) || defined(_WIN64)
00681 
00687 static void
00688 uc_free(void *str)
00689 {
00690     if (str) {
00691         xfree(str);
00692     }
00693 }
00694 
00695 #endif
00696 
00697 #if defined(_WIN32) || defined(_WIN64)
00698 
00706 static char *
00707 wmb_to_utf(char *str, int len)
00708 {
00709     WCHAR *wstr;
00710     OSVERSIONINFO ovi;
00711     int nchar, is2k, cp = CP_OEMCP;
00712 
00713     ovi.dwOSVersionInfoSize = sizeof (ovi);
00714     GetVersionEx(&ovi);
00715     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
00716     if (AreFileApisANSI()) {
00717         cp = is2k ? CP_THREAD_ACP : CP_ACP;
00718     }
00719     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
00720     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
00721     if (!wstr) {
00722         return NULL;
00723     }
00724     wstr[0] = 0;
00725     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
00726     wstr[nchar] = 0;
00727     str = xmalloc((nchar + 1) * 7);
00728     if (!str) {
00729         xfree(wstr);
00730         return NULL;
00731     }
00732     str[0] = '\0';
00733     nchar = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, nchar * 7, 0, 0);
00734     str[nchar] = '\0';
00735     xfree(wstr);
00736     return str;
00737 }
00738 
00746 static char *
00747 utf_to_wmb(char *str, int len)
00748 {
00749     WCHAR *wstr;
00750     OSVERSIONINFO ovi;
00751     int nchar, is2k, cp = CP_OEMCP;
00752 
00753     ovi.dwOSVersionInfoSize = sizeof (ovi);
00754     GetVersionEx(&ovi);
00755     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
00756     if (AreFileApisANSI()) {
00757         cp = is2k ? CP_THREAD_ACP : CP_ACP;
00758     }
00759     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
00760     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
00761     if (!wstr) {
00762         return NULL;
00763     }
00764     wstr[0] = 0;
00765     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, nchar);
00766     wstr[nchar] = 0;
00767     str = xmalloc((nchar + 1) * 7);
00768     if (!str) {
00769         xfree(wstr);
00770         return NULL;
00771     }
00772     str[0] = '\0';
00773     nchar = WideCharToMultiByte(cp, 0, wstr, -1, str, nchar * 7, 0, 0);
00774     str[nchar] = '\0';
00775     xfree(wstr);
00776     return str;
00777 }
00778 
00779 #ifdef WINTERFACE
00780 
00788 static WCHAR *
00789 wmb_to_uc(char *str, int len)
00790 {
00791     WCHAR *wstr;
00792     OSVERSIONINFO ovi;
00793     int nchar, is2k, cp = CP_OEMCP;
00794 
00795     ovi.dwOSVersionInfoSize = sizeof (ovi);
00796     GetVersionEx(&ovi);
00797     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
00798     if (AreFileApisANSI()) {
00799         cp = is2k ? CP_THREAD_ACP : CP_ACP;
00800     }
00801     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
00802     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
00803     if (!wstr) {
00804         return NULL;
00805     }
00806     wstr[0] = 0;
00807     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
00808     wstr[nchar] = 0;
00809     return wstr;
00810 }
00811 
00819 static char *
00820 uc_to_wmb(WCHAR *wstr, int len)
00821 {
00822     char *str;
00823     OSVERSIONINFO ovi;
00824     int nchar, is2k, cp = CP_OEMCP;
00825 
00826     ovi.dwOSVersionInfoSize = sizeof (ovi);
00827     GetVersionEx(&ovi);
00828     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
00829     if (AreFileApisANSI()) {
00830         cp = is2k ? CP_THREAD_ACP : CP_ACP;
00831     }
00832     nchar = WideCharToMultiByte(cp, 0, wstr, len, NULL, 0, 0, 0);
00833     str = xmalloc((nchar + 1) * 2);
00834     if (!str) {
00835         return NULL;
00836     }
00837     str[0] = '\0';
00838     nchar = WideCharToMultiByte(cp, 0, wstr, len, str, nchar * 2, 0, 0);
00839     str[nchar] = '\0';
00840     return str;
00841 }
00842 
00843 #endif /* WINTERFACE */
00844 
00845 #endif /* _WIN32 || _WIN64 */
00846 
00847 
00848 #ifdef USE_DLOPEN_FOR_GPPS
00849 
00850 #include <dlfcn.h>
00851 
00852 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
00853 
00854 /*
00855  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
00856  * dlopen(), in theory this makes the driver independent from the
00857  * driver manager, i.e. the same driver binary can run with iODBC
00858  * and unixODBC.
00859  */
00860 
00861 static void
00862 drvgetgpps(DBC *d)
00863 {
00864     void *lib;
00865     int (*gpps)();
00866 
00867     lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
00868     if (!lib) {
00869         lib = dlopen("libodbcinst.so", RTLD_LAZY);
00870     }
00871     if (!lib) {
00872         lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
00873     }
00874     if (!lib) {
00875         lib = dlopen("libiodbcinst.so", RTLD_LAZY);
00876     }
00877     if (lib) {
00878         gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
00879         if (!gpps) {
00880             dlclose(lib);
00881             return;
00882         }
00883         d->instlib = lib;
00884         d->gpps = gpps;
00885     }
00886 }
00887 
00888 static void
00889 drvrelgpps(DBC *d)
00890 {
00891     if (d->instlib) {
00892         dlclose(d->instlib);
00893         d->instlib = 0;
00894     }
00895 }
00896 
00897 static int
00898 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
00899         int bufsiz, char *fname)
00900 {
00901     if (d->gpps) {
00902         return d->gpps(sect, ent, def, buf, bufsiz, fname);
00903     }
00904     strncpy(buf, def, bufsiz);
00905     buf[bufsiz - 1] = '\0';
00906     return 1;
00907 }
00908 #else
00909 #include <odbcinst.h>
00910 #define drvgetgpps(d)
00911 #define drvrelgpps(d)
00912 #endif
00913 
00914 /*
00915  * Internal function to bind SQLite3 parameters.
00916  */
00917 
00918 static void
00919 s3bind(DBC *d, sqlite3_stmt *stmt, int nparams, BINDPARM *p)
00920 {
00921     int i;
00922 
00923     if (stmt && p && nparams > 0) {
00924         for (i = 0; i < nparams; i++, p++) {
00925             switch (p->s3type) {
00926             default:
00927             case SQLITE_NULL:
00928                 sqlite3_bind_null(stmt, i + 1);
00929                 if (d->trace) {
00930                     fprintf(d->trace, "-- parameter %d: NULL\n", i + 1);
00931                     fflush(d->trace);
00932                 }
00933                 break;
00934             case SQLITE_TEXT:
00935                 sqlite3_bind_text(stmt, i + 1, p->s3val, p->s3size,
00936                                   SQLITE_STATIC);
00937                 if (d->trace) {
00938                     fprintf(d->trace, "-- parameter %d: '%*s'\n", i + 1,
00939                             p->s3size, (char *) p->s3val);
00940                     fflush(d->trace);
00941                 }
00942                 break;
00943             case SQLITE_BLOB:
00944                 sqlite3_bind_blob(stmt, i + 1, p->s3val, p->s3size,
00945                                   SQLITE_STATIC);
00946                 if (d->trace) {
00947                     fprintf(d->trace, "-- parameter %d: [BLOB]'\n", i + 1);
00948                     fflush(d->trace);
00949                 }
00950                 break;
00951             case SQLITE_FLOAT:
00952                 sqlite3_bind_double(stmt, i + 1, p->s3dval);
00953                 if (d->trace) {
00954                     fprintf(d->trace, "-- parameter %d: %g\n",
00955                             i + 1, p->s3dval);
00956                     fflush(d->trace);
00957                 }
00958                 break;
00959             case SQLITE_INTEGER:
00960                 if (p->s3size > sizeof (int)) {
00961                     sqlite3_bind_int64(stmt, i + 1, p->s3lival);
00962                     if (d->trace) {
00963                         fprintf(d->trace,
00964 #ifdef _WIN32
00965                                 "-- parameter %d: %I64d\n",
00966 #else
00967                                 "-- parameter %d: %lld\n",
00968 #endif
00969                                 i + 1, p->s3lival);
00970                         fflush(d->trace);
00971                     }
00972                 } else {
00973                     sqlite3_bind_int(stmt, i + 1, p->s3ival);
00974                     if (d->trace) {
00975                         fprintf(d->trace, "-- parameter %d: %d\n",
00976                                 i + 1, p->s3ival);
00977                         fflush(d->trace);
00978                     }
00979                 }
00980                 break;
00981             }
00982         }
00983     }
00984 }
00985 
00986 /*
00987  * Internal structure for managing driver's
00988  * sqlite3_get_table() implementation.
00989  */
00990 
00991 typedef struct tblres {
00992     char **resarr;
00993     char *errmsg;
00994     sqlite3_stmt *stmt;
00995     STMT *s;
00996     int nres;
00997     int nalloc;
00998     int nrow;
00999     int ncol;
01000     PTRDIFF_T ndata;
01001     int rc;
01002 } TBLRES;
01003 
01004 /*
01005  * Driver's version of sqlite3_get_table() and friends which are
01006  * capable of dealing with blobs.
01007  */
01008 
01009 static int
01010 drvgettable_row(TBLRES *t, int ncol, int rc)
01011 {
01012     int need;
01013     int i;
01014     char *p;
01015 
01016     if (t->nrow == 0 && rc == SQLITE_ROW) {
01017         need = ncol * 2;
01018     } else {
01019         need = ncol;
01020     }
01021     if (t->ndata + need >= t->nalloc) {
01022         char **resnew;
01023         int nalloc = t->nalloc * 2 + need + 1;
01024 
01025         resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
01026         if (!resnew) {
01027 nomem:
01028             t->rc = SQLITE_NOMEM;
01029             return 1;
01030         }
01031         t->nalloc = nalloc;
01032         t->resarr = resnew;
01033     }
01034     /* column names when first row */
01035     if (t->nrow == 0) {
01036         t->ncol = ncol;
01037         for (i = 0; i < ncol; i++) {
01038             p = (char *) sqlite3_column_name(t->stmt, i);
01039             if (p) {
01040                 char *q = xmalloc(strlen(p) + 1);
01041 
01042                 if (!q) {
01043                     goto nomem;
01044                 }
01045                 strcpy(q, p);
01046                 p = q;
01047             }
01048             t->resarr[t->ndata++] = p;
01049         }
01050         if (t->s && t->s->guessed_types) {
01051             int ncol2 = ncol;
01052 
01053             setupdyncols(t->s, t->stmt, &ncol2);
01054             t->s->guessed_types = 0;
01055             t->s->ncols = ncol;
01056         }
01057     } else if (t->ncol != ncol) {
01058         t->errmsg = sqlite3_mprintf("drvgettable() called with two or"
01059                                     " more incompatible queries");
01060         t->rc = SQLITE_ERROR;
01061         return 1;
01062     }
01063     /* copy row data */
01064     if (rc == SQLITE_ROW) {
01065         for (i = 0; i < ncol; i++) {
01066             int coltype = sqlite3_column_type(t->stmt, i);
01067 
01068             p = NULL;
01069             if (coltype == SQLITE_BLOB) {
01070                 int k, nbytes = sqlite3_column_bytes(t->stmt, i);
01071                 char *qp;
01072                 unsigned const char *bp;
01073 
01074                 bp = sqlite3_column_blob(t->stmt, i);
01075                 qp = xmalloc(nbytes * 2 + 4);
01076                 if (!qp) {
01077                     goto nomem;
01078                 }
01079                 p = qp;
01080                 *qp++ = 'X';
01081                 *qp++ = '\'';
01082                 for (k = 0; k < nbytes; k++) {
01083                     *qp++ = xdigits[(bp[k] >> 4)];
01084                     *qp++ = xdigits[(bp[k] & 0xF)];
01085                 }
01086                 *qp++ = '\'';
01087                 *qp = '\0';
01088             } else if (coltype != SQLITE_NULL) {
01089                 p = xstrdup((char *) sqlite3_column_text(t->stmt, i));
01090                 if (!p) {
01091                     goto nomem;
01092                 }
01093             }
01094             t->resarr[t->ndata++] = p;
01095         }
01096         t->nrow++;
01097     }
01098     return 0;
01099 }
01100 
01101 static int
01102 drvgettable(STMT *s, const char *sql, char ***resp, int *nrowp,
01103             int *ncolp, char **errp, int nparam, BINDPARM *p)
01104 {
01105     DBC *d = (DBC *) s->dbc;
01106     int rc = SQLITE_OK, keep = sql == NULL;
01107     TBLRES tres;
01108     const char *sqlleft = 0;
01109     int nretry = 0, haveerr = 0;
01110 
01111     if (!resp) {
01112         return SQLITE_ERROR;
01113     }
01114     *resp = NULL;
01115     if (nrowp) {
01116         *nrowp = 0;
01117     }
01118     if (ncolp) {
01119         *ncolp = 0;
01120     }
01121     tres.errmsg = NULL;
01122     tres.nres = 0;
01123     tres.nrow = 0;
01124     tres.ncol = 0;
01125     tres.ndata = 1;
01126     tres.nalloc = 20;
01127     tres.rc = SQLITE_OK;
01128     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
01129     tres.stmt = NULL;
01130     tres.s = s;
01131     if (!tres.resarr) {
01132         return SQLITE_NOMEM;
01133     }
01134     tres.resarr[0] = 0;
01135     if (sql == NULL) {
01136         tres.stmt = s->s3stmt;
01137         if (tres.stmt == NULL) {
01138             return SQLITE_NOMEM;
01139         }
01140         goto retrieve;
01141     }
01142     while (sql && *sql && (rc == SQLITE_OK ||
01143                            (rc == SQLITE_SCHEMA && (++nretry) < 2))) {
01144         int ncol;
01145 
01146         tres.stmt = NULL;
01147 #if defined(HAVE_SQLITE3PREPAREV2) && HAVE_SQLITE3PREPAREV2
01148         dbtraceapi(d, "sqlite3_prepare_v2", sql);
01149         rc = sqlite3_prepare_v2(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
01150 #else
01151         dbtraceapi(d, "sqlite3_prepare", sql);
01152         rc = sqlite3_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
01153 #endif
01154         if (rc != SQLITE_OK) {
01155             if (tres.stmt) {
01156                 dbtraceapi(d, "sqlite3_finalize", 0);
01157                 sqlite3_finalize(tres.stmt);
01158                 tres.stmt = NULL;
01159             }
01160             continue;
01161         }
01162         if (!tres.stmt) {
01163             /* this happens for a comment or white-space */
01164             sql = sqlleft;
01165             continue;
01166         }
01167 retrieve:
01168         if (sqlite3_bind_parameter_count(tres.stmt) != nparam) {
01169             if (errp) {
01170                 *errp =
01171                     sqlite3_mprintf("%s", "parameter marker count incorrect");
01172             }
01173             haveerr = 1;
01174             rc = SQLITE_ERROR;
01175             goto tbldone;
01176         }
01177         s3bind(d, tres.stmt, nparam, p);
01178         ncol = sqlite3_column_count(tres.stmt);
01179         while (1) {
01180             if (s->max_rows && tres.nrow >= s->max_rows) {
01181                 rc = SQLITE_OK;
01182                 break;
01183             }
01184             rc = sqlite3_step(tres.stmt);
01185             if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
01186                 if (drvgettable_row(&tres, ncol, rc)) {
01187                     rc = SQLITE_ABORT;
01188                     goto tbldone;
01189                 }
01190             }
01191             if (rc != SQLITE_ROW) {
01192                 if (keep) {
01193                     dbtraceapi(d, "sqlite3_reset", 0);
01194                     rc = sqlite3_reset(tres.stmt);
01195                     s->s3stmt_noreset = 1;
01196                 } else {
01197                     dbtraceapi(d, "sqlite3_finalize", 0);
01198                     rc = sqlite3_finalize(tres.stmt);
01199                 }
01200                 tres.stmt = 0;
01201                 if (rc != SQLITE_SCHEMA) {
01202                     nretry = 0;
01203                     sql = sqlleft;
01204                     while (sql && ISSPACE(*sql)) {
01205                         sql++;
01206                     }
01207                 }
01208                 if (rc == SQLITE_DONE) {
01209                     rc = SQLITE_OK;
01210                 }
01211                 break;
01212             }
01213         }
01214     }
01215 tbldone:
01216     if (tres.stmt) {
01217         if (keep) {
01218             if (!s->s3stmt_noreset) {
01219                 dbtraceapi(d, "sqlite3_reset", 0);
01220                 sqlite3_reset(tres.stmt);
01221                 s->s3stmt_noreset = 1;
01222             }
01223         } else {
01224             dbtraceapi(d, "sqlite3_finalize", 0);
01225             sqlite3_finalize(tres.stmt);
01226         }
01227     }
01228     if (haveerr) {
01229         /* message already in *errp if any */
01230     } else if (rc != SQLITE_OK && rc == sqlite3_errcode(d->sqlite) && errp) {
01231         *errp = sqlite3_mprintf("%s", sqlite3_errmsg(d->sqlite));
01232     } else if (errp) {
01233         *errp = NULL;
01234     }
01235     if (tres.resarr) {
01236         tres.resarr[0] = (char *) (tres.ndata - 1);
01237     }
01238     if (rc == SQLITE_ABORT) {
01239         freerows(&tres.resarr[1]);
01240         if (tres.errmsg) {
01241             if (errp) {
01242                 if (*errp) {
01243                     sqlite3_free(*errp);
01244                 }
01245                 *errp = tres.errmsg;
01246             } else {
01247                 sqlite3_free(tres.errmsg);
01248             }
01249         }
01250         return tres.rc;
01251     }
01252     sqlite3_free(tres.errmsg);
01253     if (rc != SQLITE_OK) {
01254         freerows(&tres.resarr[1]);
01255         return rc;
01256     }
01257     *resp = &tres.resarr[1];
01258     if (ncolp) {
01259         *ncolp = tres.ncol;
01260     }
01261     if (nrowp) {
01262         *nrowp = tres.nrow;
01263     }
01264     return rc;
01265 }
01266 
01275 #if defined(__GNUC__) && (__GNUC__ >= 2)
01276 static void setstatd(DBC *, int, char *, char *, ...)
01277     __attribute__((format (printf, 3, 5)));
01278 #endif
01279 
01280 static void
01281 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
01282 {
01283     va_list ap;
01284 
01285     if (!d) {
01286         return;
01287     }
01288     d->naterr = naterr;
01289     d->logmsg[0] = '\0';
01290     if (msg) {
01291         int count;
01292 
01293         va_start(ap, st);
01294         count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
01295         va_end(ap);
01296         if (count < 0) {
01297             d->logmsg[sizeof (d->logmsg) - 1] = '\0';
01298         }
01299     }
01300     if (!st) {
01301         st = "?????";
01302     }
01303     strncpy(d->sqlstate, st, 5);
01304     d->sqlstate[5] = '\0';
01305 }
01306 
01315 #if defined(__GNUC__) && (__GNUC__ >= 2)
01316 static void setstat(STMT *, int, char *, char *, ...)
01317     __attribute__((format (printf, 3, 5)));
01318 #endif
01319 
01320 static void
01321 setstat(STMT *s, int naterr, char *msg, char *st, ...)
01322 {
01323     va_list ap;
01324 
01325     if (!s) {
01326         return;
01327     }
01328     s->naterr = naterr;
01329     s->logmsg[0] = '\0';
01330     if (msg) {
01331         int count;
01332 
01333         va_start(ap, st);
01334         count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
01335         va_end(ap);
01336         if (count < 0) {
01337             s->logmsg[sizeof (s->logmsg) - 1] = '\0';
01338         }
01339     }
01340     if (!st) {
01341         st = "?????";
01342     }
01343     strncpy(s->sqlstate, st, 5);
01344     s->sqlstate[5] = '\0';
01345 }
01346 
01353 static SQLRETURN
01354 drvunimpldbc(HDBC dbc)
01355 {
01356     DBC *d;
01357 
01358     if (dbc == SQL_NULL_HDBC) {
01359         return SQL_INVALID_HANDLE;
01360     }
01361     d = (DBC *) dbc;
01362     setstatd(d, -1, "not supported", "IM001");
01363     return SQL_ERROR;
01364 }
01365 
01372 static SQLRETURN
01373 drvunimplstmt(HSTMT stmt)
01374 {
01375     STMT *s;
01376 
01377     if (stmt == SQL_NULL_HSTMT) {
01378         return SQL_INVALID_HANDLE;
01379     }
01380     s = (STMT *) stmt;
01381     setstat(s, -1, "not supported", "IM001");
01382     return SQL_ERROR;
01383 }
01384 
01390 static void
01391 freep(void *x)
01392 {
01393     if (x && ((char **) x)[0]) {
01394         xfree(((char **) x)[0]);
01395         ((char **) x)[0] = NULL;
01396     }
01397 }
01398 
01405 static SQLRETURN
01406 nomem(STMT *s)
01407 {
01408     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
01409     return SQL_ERROR;
01410 }
01411 
01418 static SQLRETURN
01419 noconn(STMT *s)
01420 {
01421     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
01422     return SQL_ERROR;
01423 }
01424 
01432 static double
01433 ln_strtod(const char *data, char **endp)
01434 {
01435 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
01436     struct lconv *lc;
01437     char buf[128], *p, *end;
01438     double value;
01439 
01440     lc = localeconv();
01441     if (lc && lc->decimal_point && lc->decimal_point[0] &&
01442         lc->decimal_point[0] != '.') {
01443         strncpy(buf, data, sizeof (buf) - 1);
01444         buf[sizeof (buf) - 1] = '\0';
01445         p = strchr(buf, '.');
01446         if (p) {
01447             *p = lc->decimal_point[0];
01448         }
01449         p = buf;
01450     } else {
01451         p = (char *) data;
01452     }
01453     value = strtod(p, &end);
01454     end = (char *) data + (end - p);
01455     if (endp) {
01456         *endp = end;
01457     }
01458     return value;
01459 #else
01460     return strtod(data, endp);
01461 #endif
01462 }
01463 
01469 static char *
01470 unquote(char *str)
01471 {
01472     if (str) {
01473         int len = strlen(str);
01474 
01475         if (len > 1) {
01476             if ((str[0] == '\'' && str[len - 1] == '\'') ||
01477                 (str[0] == '"' && str[len - 1] == '"') ||
01478                 (str[0] == '[' && str[len - 1] == ']')) {
01479                 str[len - 1] = '\0';
01480                 strcpy(str, str + 1);
01481             }
01482         }
01483     }
01484     return str;
01485 }
01486 
01494 static int
01495 unescpat(char *str)
01496 {
01497     char *p, *q;
01498     int count = 0;
01499 
01500     p = str;
01501     while ((q = strchr(p, '_')) != NULL) {
01502         if (q == str || q[-1] != '\\') {
01503             count++;
01504         }
01505         p = q + 1;
01506     }
01507     p = str;
01508     while ((q = strchr(p, '%')) != NULL) {
01509         if (q == str || q[-1] != '\\') {
01510             count++;
01511         }
01512         p = q + 1;
01513     }
01514     p = str;
01515     while ((q = strchr(p, '\\')) != NULL) {
01516         if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
01517             strcpy(q, q + 1);
01518         }
01519         p = q + 1;
01520     }
01521     return count;
01522 }
01523 
01532 static int
01533 namematch(char *str, char *pat, int esc)
01534 {
01535     int cp, ch;
01536 
01537     while (1) {
01538         cp = TOLOWER(*pat);
01539         if (cp == '\0') {
01540             if (*str != '\0') {
01541                 goto nomatch;
01542             }
01543             break;
01544         }
01545         if (*str == '\0' && cp != '%') {
01546             goto nomatch;
01547         }
01548         if (cp == '%') {
01549             while (*pat == '%') {
01550                 ++pat;
01551             }
01552             cp = TOLOWER(*pat);
01553             if (cp == '\0') {
01554                 break;
01555             }
01556             while (1) {
01557                 if (cp != '_' && cp != '\\') {
01558                     while (*str) {
01559                         ch = TOLOWER(*str);
01560                         if (ch == cp) {
01561                             break;
01562                         }
01563                         ++str;
01564                     }
01565                 }
01566                 if (namematch(str, pat, esc)) {
01567                     goto match;
01568                 }
01569                 if (*str == '\0') {
01570                     goto nomatch;
01571                 }
01572                 ch = TOLOWER(*str);
01573                 ++str;
01574             }
01575         }
01576         if (cp == '_') {
01577             pat++;
01578             str++;
01579             continue;
01580         }
01581         if (esc && cp == '\\' &&
01582             (pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
01583             ++pat;
01584             cp = TOLOWER(*pat);
01585         }
01586         ch = TOLOWER(*str++);
01587         ++pat;
01588         if (ch != cp) {
01589             goto nomatch;
01590         }
01591     }
01592 match:
01593     return 1;
01594 nomatch:
01595     return 0;
01596 }
01597 
01605 static int
01606 busy_handler(void *udata, int count)
01607 {
01608     DBC *d = (DBC *) udata;
01609     long t1;
01610     int ret = 0;
01611 #if !defined(_WIN32) && !defined(_WIN64)
01612     struct timeval tv;
01613 #endif
01614 
01615     if (d->busyint) {
01616         d->busyint = 0;
01617         return ret;
01618     }
01619     if (d->timeout <= 0) {
01620         return ret;
01621     }
01622     if (count <= 1) {
01623 #if defined(_WIN32) || defined(_WIN64)
01624         d->t0 = GetTickCount();
01625 #else
01626         gettimeofday(&tv, NULL);
01627         d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
01628 #endif
01629     }
01630 #if defined(_WIN32) || defined(_WIN64)
01631     t1 = GetTickCount();
01632 #else
01633     gettimeofday(&tv, NULL);
01634     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
01635 #endif
01636     if (t1 - d->t0 > d->timeout) {
01637         goto done;
01638     }
01639 #if defined(_WIN32) || defined(_WIN64)
01640     Sleep(10);
01641 #else
01642 #ifdef HAVE_USLEEP
01643     usleep(10000);
01644 #else
01645     tv.tv_sec = 0;
01646     tv.tv_usec = 10000;
01647     select(0, NULL, NULL, NULL, &tv);
01648 #endif
01649 #endif
01650     ret = 1;
01651 done:
01652     return ret;
01653 }
01654 
01666 static int
01667 setsqliteopts(sqlite3 *x, DBC *d)
01668 {
01669     int count = 0, step = 0, max, rc = SQLITE_ERROR;
01670 
01671 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
01672     max = d->longnames ? 3 : 1;
01673 #else
01674     max = 3;
01675 #endif
01676     if (d->shortnames) {
01677         max = 3;
01678     }
01679     while (step < max) {
01680         if (step < 1) {
01681             rc = sqlite3_exec(x, "PRAGMA empty_result_callbacks = on;",
01682                               NULL, NULL, NULL);
01683         } else if (step < 2) {
01684             rc = sqlite3_exec(x, d->shortnames ?
01685                               "PRAGMA full_column_names = off;" :
01686                               "PRAGMA full_column_names = on;",
01687                               NULL, NULL, NULL);
01688         } else if (step < 3) {
01689             rc = sqlite3_exec(x, d->shortnames ?
01690                               "PRAGMA short_column_names = on;" :
01691                               "PRAGMA short_column_names = off;",
01692                               NULL, NULL, NULL);
01693         }
01694         if (rc != SQLITE_OK) {
01695             if (rc != SQLITE_BUSY ||
01696                 !busy_handler((void *) d, ++count)) {
01697                 return rc;
01698             }
01699             continue;
01700         }
01701         count = 0;
01702         ++step;
01703     }
01704     sqlite3_busy_handler(x, busy_handler, (void *) d);
01705     return SQLITE_OK;
01706 }
01707 
01717 static void
01718 freerows(char **rowp)
01719 {
01720     PTRDIFF_T size, i;
01721 
01722     if (!rowp) {
01723         return;
01724     }
01725     --rowp;
01726     size = (PTRDIFF_T) rowp[0];
01727     for (i = 1; i <= size; i++) {
01728         freep(&rowp[i]);
01729     }
01730     freep(&rowp);
01731 }
01732 
01742 static int
01743 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar)
01744 {
01745     char *p, *q;
01746     int testsign = 0, result;
01747 
01748 #ifdef WINTERFACE
01749     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
01750 #else
01751     result = SQL_VARCHAR;
01752 #endif
01753     if (!typename) {
01754         return result;
01755     }
01756     q = p = xmalloc(strlen(typename) + 1);
01757     if (!p) {
01758         return result;
01759     }
01760     strcpy(p, typename);
01761     while (*q) {
01762         *q = TOLOWER(*q);
01763         ++q;
01764     }
01765     if (strncmp(p, "inter", 5) == 0) {
01766     } else if (strncmp(p, "int", 3) == 0 ||
01767         strncmp(p, "mediumint", 9) == 0) {
01768         testsign = 1;
01769         result = SQL_INTEGER;
01770     } else if (strncmp(p, "numeric", 7) == 0) {
01771         result = SQL_DOUBLE;
01772     } else if (strncmp(p, "tinyint", 7) == 0) {
01773         testsign = 1;
01774         result = SQL_TINYINT;
01775     } else if (strncmp(p, "smallint", 8) == 0) {
01776         testsign = 1;
01777         result = SQL_SMALLINT;
01778     } else if (strncmp(p, "float", 5) == 0) {
01779         result = SQL_DOUBLE;
01780     } else if (strncmp(p, "double", 6) == 0 ||
01781         strncmp(p, "real", 4) == 0) {
01782         result = SQL_DOUBLE;
01783     } else if (strncmp(p, "timestamp", 9) == 0) {
01784 #ifdef SQL_TYPE_TIMESTAMP
01785         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
01786 #else
01787         result = SQL_TIMESTAMP;
01788 #endif
01789     } else if (strncmp(p, "datetime", 8) == 0) {
01790 #ifdef SQL_TYPE_TIMESTAMP
01791         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
01792 #else
01793         result = SQL_TIMESTAMP;
01794 #endif
01795     } else if (strncmp(p, "time", 4) == 0) {
01796 #ifdef SQL_TYPE_TIME
01797         result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
01798 #else
01799         result = SQL_TIME;
01800 #endif
01801     } else if (strncmp(p, "date", 4) == 0) {
01802 #ifdef SQL_TYPE_DATE
01803         result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
01804 #else
01805         result = SQL_DATE;
01806 #endif
01807 #ifdef SQL_LONGVARCHAR
01808     } else if (strncmp(p, "text", 4) == 0 ||
01809                strncmp(p, "memo", 4) == 0) {
01810 #ifdef WINTERFACE
01811         result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
01812 #else
01813         result = SQL_LONGVARCHAR;
01814 #endif
01815 #ifdef WINTERFACE
01816     } else if (strncmp(p, "wtext", 5) == 0 ||
01817                strncmp(p, "wvarchar", 8) == 0 ||
01818                strncmp(p, "longwvarchar", 12) == 0) {
01819         result = SQL_WLONGVARCHAR;
01820 #endif
01821 #endif
01822 #ifdef SQL_BIT
01823     } else if (strncmp(p, "bool", 4) == 0 ||
01824                strncmp(p, "bit", 3) == 0) {
01825         result = SQL_BIT;
01826 #endif
01827 #ifdef SQL_BIGINT
01828     } else if (strncmp(p, "bigint", 6) == 0) {
01829         result = SQL_BIGINT;
01830 #endif
01831     } else if (strncmp(p, "blob", 4) == 0) {
01832         result = SQL_BINARY;
01833     } else if (strncmp(p, "varbinary", 9) == 0) {
01834         result = SQL_VARBINARY;
01835     } else if (strncmp(p, "longvarbinary", 13) == 0) {
01836         result = SQL_LONGVARBINARY;
01837     }
01838     if (nosign) {
01839         if (testsign) {
01840             *nosign = strstr(p, "unsigned") != NULL;
01841         } else {
01842             *nosign = 1;
01843         }
01844     }
01845     xfree(p);
01846     return result;
01847 }
01848 
01858 static void
01859 getmd(const char *typename, int sqltype, int *mp, int *dp)
01860 {
01861     int m = 0, d = 0;
01862 
01863     switch (sqltype) {
01864     case SQL_INTEGER:       m = 10; d = 9; break;
01865     case SQL_TINYINT:       m = 4; d = 3; break;
01866     case SQL_SMALLINT:      m = 6; d = 5; break;
01867     case SQL_FLOAT:         m = 25; d = 24; break;
01868     case SQL_DOUBLE:        m = 54; d = 53; break;
01869     case SQL_VARCHAR:       m = 255; d = 0; break;
01870 #ifdef WINTERFACE
01871 #ifdef SQL_WVARCHAR
01872     case SQL_WVARCHAR:      m = 255; d = 0; break;
01873 #endif
01874 #endif
01875 #ifdef SQL_TYPE_DATE
01876     case SQL_TYPE_DATE:
01877 #endif
01878     case SQL_DATE:          m = 10; d = 0; break;
01879 #ifdef SQL_TYPE_TIME
01880     case SQL_TYPE_TIME:
01881 #endif
01882     case SQL_TIME:          m = 8; d = 0; break;
01883 #ifdef SQL_TYPE_TIMESTAMP
01884     case SQL_TYPE_TIMESTAMP:
01885 #endif
01886     case SQL_TIMESTAMP:     m = 32; d = 0; break;
01887 #ifdef SQL_LONGVARCHAR
01888     case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
01889 #endif
01890 #ifdef WINTERFACE
01891 #ifdef SQL_WLONGVARCHAR
01892     case SQL_WLONGVARCHAR:  m = 65536; d = 0; break;
01893 #endif
01894 #endif
01895     case SQL_VARBINARY:     m = 255; d = 0; break;
01896     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
01897 #ifdef SQL_BIGINT
01898     case SQL_BIGINT:        m = 20; d = 19; break;
01899 #endif
01900 #ifdef SQL_BIT
01901     case SQL_BIT:           m = 1; d = 1; break;
01902 #endif
01903     }
01904     if (m && typename) {
01905         int mm, dd;
01906 
01907         if (sscanf(typename, "%*[^(](%d)", &mm) == 1) {
01908             m = d = mm;
01909         } else if (sscanf(typename, "%*[^(](%d,%d)", &mm, &dd) == 2) {
01910             m = mm;
01911             d = dd;
01912         }
01913     }
01914     if (mp) {
01915         *mp = m;
01916     }
01917     if (dp) {
01918         *dp = d;
01919     }
01920 }
01921 
01931 static int
01932 mapdeftype(int type, int stype, int nosign, int nowchar)
01933 {
01934     if (type == SQL_C_DEFAULT) {
01935         switch (stype) {
01936         case SQL_INTEGER:
01937             type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
01938             break;
01939         case SQL_TINYINT:
01940             type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
01941             break;
01942         case SQL_SMALLINT:
01943             type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
01944             break;
01945         case SQL_FLOAT:
01946             type = SQL_C_FLOAT;
01947             break;
01948         case SQL_DOUBLE:
01949             type = SQL_C_DOUBLE;
01950             break;
01951         case SQL_TIMESTAMP:
01952             type = SQL_C_TIMESTAMP;
01953             break;
01954         case SQL_TIME:
01955             type = SQL_C_TIME;
01956             break;
01957         case SQL_DATE:
01958             type = SQL_C_DATE;
01959             break;
01960 #ifdef SQL_C_TYPE_TIMESTAMP
01961         case SQL_TYPE_TIMESTAMP:
01962             type = SQL_C_TYPE_TIMESTAMP;
01963             break;
01964 #endif
01965 #ifdef SQL_C_TYPE_TIME
01966         case SQL_TYPE_TIME:
01967             type = SQL_C_TYPE_TIME;
01968             break;
01969 #endif
01970 #ifdef SQL_C_TYPE_DATE
01971         case SQL_TYPE_DATE:
01972             type = SQL_C_TYPE_DATE;
01973             break;
01974 #endif
01975 #ifdef WINTERFACE
01976         case SQL_WVARCHAR:
01977         case SQL_WCHAR:
01978 #ifdef SQL_WLONGVARCHAR
01979         case SQL_WLONGVARCHAR:
01980 #endif
01981             type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
01982             break;
01983 #endif
01984         case SQL_BINARY:
01985         case SQL_VARBINARY:
01986         case SQL_LONGVARBINARY:
01987             type = SQL_C_BINARY;
01988             break;
01989 #ifdef SQL_BIT
01990         case SQL_BIT:
01991             type = SQL_C_BIT;
01992             break;
01993 #endif
01994 #ifdef SQL_BIGINT
01995         case SQL_BIGINT:
01996             type = (nosign > 0) ? SQL_C_UBIGINT : SQL_C_SBIGINT;
01997             break;
01998 #endif
01999         default:
02000 #ifdef WINTERFACE
02001             type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
02002 #else
02003             type = SQL_C_CHAR;
02004 #endif
02005             break;
02006         }
02007     }
02008     return type;
02009 }
02010 
02021 static char *
02022 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg)
02023 {
02024     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
02025     int np = 0, isddl = -1, size;
02026 
02027     *errmsg = NULL;
02028     if (sqlLen != SQL_NTS) {
02029         qz = q = xmalloc(sqlLen + 1);
02030         if (!qz) {
02031             return NULL;
02032         }
02033         memcpy(q, sql, sqlLen);
02034         q[sqlLen] = '\0';
02035         size = sqlLen * 4;
02036     } else {
02037         size = strlen(sql) * 4;
02038     }
02039     size += sizeof (char *) - 1;
02040     size &= ~(sizeof (char *) - 1);
02041     p = xmalloc(size);
02042     if (!p) {
02043 errout:
02044         freep(&qz);
02045         return NULL;
02046     }
02047     memset(p, 0, size);
02048     out = p;
02049     while (*q) {
02050         switch (*q) {
02051         case '\'':
02052         case '\"':
02053             if (q == inq) {
02054                 inq = NULL;
02055             } else if (!inq) {
02056                 inq = q + 1;
02057 
02058                 while (*inq) {
02059                     if (*inq == *q) {
02060                         if (inq[1] == *q) {
02061                             inq++;
02062                         } else {
02063                             break;
02064                         }
02065                     }
02066                     inq++;
02067                 }
02068             }
02069             *p++ = *q;
02070             break;
02071         case '?':
02072             *p++ = *q;
02073             if (!inq) {
02074                 np++;
02075             }
02076             break;
02077         case ';':
02078             if (!inq) {
02079                 if (isddl < 0) {
02080                     char *qq = out;
02081 
02082                     while (*qq && ISSPACE(*qq)) {
02083                         ++qq;
02084                     }
02085                     if (*qq && *qq != ';') {
02086                         size = strlen(qq);
02087                         if ((size >= 5) &&
02088                             (strncasecmp(qq, "create", 5) == 0)) {
02089                             isddl = 1;
02090                         } else if ((size >= 4) &&
02091                                    (strncasecmp(qq, "drop", 4) == 0)) {
02092                             isddl = 1;
02093                         } else {
02094                             isddl = 0;
02095                         }
02096                     }
02097                 }
02098                 if (isddl == 0) {
02099                     char *qq = q;
02100 
02101                     do {
02102                         ++qq;
02103                     } while (*qq && ISSPACE(*qq));
02104                     if (*qq && *qq != ';') {
02105                         freep(&out);
02106                         *errmsg = "only one SQL statement allowed";
02107                         goto errout;
02108                     }
02109                 }
02110             }
02111             *p++ = *q;
02112             break;
02113         case '{':
02114             /* deal with {d 'YYYY-MM-DD'}, {t ...}, and {ts ...} */
02115             if (!inq) {
02116                 char *end = q + 1;
02117 
02118                 while (*end && *end != '}') {
02119                     ++end;
02120                 }
02121                 if (*end == '}') {
02122                     char *start = q + 1;
02123                     char *end2 = end - 1;
02124 
02125                     while (start < end2 && *start != '\'') {
02126                         ++start;
02127                     }
02128                     while (end2 > start && *end2 != '\'') {
02129                         --end2;
02130                     }
02131                     if (*start == '\'' && *end2 == '\'') {
02132                         while (start <= end2) {
02133                             *p++ = *start;
02134                             ++start;
02135                         }
02136                         q = end;
02137                         break;
02138                     }
02139                 }
02140             }
02141             /* FALL THROUGH */
02142         default:
02143             *p++ = *q;
02144         }
02145         ++q;
02146     }
02147     freep(&qz);
02148     *p = '\0';
02149     if (nparam) {
02150         *nparam = np;
02151     }
02152     if (isselect) {
02153         if (isddl > 0) {
02154             *isselect = 0;
02155         } else {
02156             p = out;
02157             while (*p && ISSPACE(*p)) {
02158                 ++p;
02159             }
02160             size = strlen(p);
02161             *isselect = (size >= 6) && (strncasecmp(p, "select", 6) == 0);
02162         }
02163     }
02164     return out;
02165 }
02166 
02175 static int
02176 findcol(char **cols, int ncols, char *name)
02177 {
02178     int i;
02179 
02180     if (cols) {
02181         for (i = 0; i < ncols; i++) {
02182             if (strcmp(cols[i], name) == 0) {
02183                 return i;
02184             }
02185         }
02186     }
02187     return -1;
02188 }
02189 
02206 static void
02207 fixupdyncols(STMT *s, DBC *d)
02208 {
02209     int i, k;
02210 #if !defined(HAVE_SQLITE3TABLECOLUMNMETADATA) || !HAVE_SQLITE3TABLECOLUMNMETADATA
02211     int pk, nn, t, r, nrows, ncols;
02212     char **rowp, *flagp, flags[128];
02213 #endif
02214 
02215     if (!s->dyncols) {
02216         return;
02217     }
02218     /* fixup labels */
02219     if (!s->longnames) {
02220         if (s->dcols > 1) {
02221             char *table = s->dyncols[0].table;
02222 
02223             for (i = 1; table[0] && i < s->dcols; i++) {
02224                 if (strcmp(s->dyncols[i].table, table)) {
02225                     break;
02226                 }
02227             }
02228             if (i >= s->dcols) {
02229                 for (i = 0; i < s->dcols; i++) {
02230                     s->dyncols[i].label = s->dyncols[i].column;
02231                 }
02232             }
02233         } else if (s->dcols == 1) {
02234             s->dyncols[0].label = s->dyncols[0].column;
02235         }
02236     }
02237     for (i = 0; i < s->dcols; i++) {
02238         s->dyncols[i].type =
02239             mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3,
02240                        s->nowchar[0] || s->nowchar[1]);
02241         getmd(s->dyncols[i].typename, s->dyncols[i].type,
02242               &s->dyncols[i].size, NULL);
02243 #ifdef SQL_LONGVARCHAR
02244         if (s->dyncols[i].type == SQL_VARCHAR &&
02245             s->dyncols[i].size > 255) {
02246             s->dyncols[i].type = SQL_LONGVARCHAR;
02247         }
02248 #endif
02249 #ifdef WINTERFACE
02250 #ifdef SQL_WLONGVARCHAR
02251         if (s->dyncols[i].type == SQL_WVARCHAR &&
02252             s->dyncols[i].size > 255) {
02253             s->dyncols[i].type = SQL_WLONGVARCHAR;
02254         }
02255 #endif
02256 #endif
02257         if (s->dyncols[i].type == SQL_VARBINARY &&
02258             s->dyncols[i].size > 255) {
02259             s->dyncols[i].type = SQL_LONGVARBINARY;
02260         }
02261     }
02262 #if !defined(HAVE_SQLITE3TABLECOLUMNMETADATA) || !HAVE_SQLITE3TABLECOLUMNMETADATA
02263     if (s->dcols > array_size(flags)) {
02264         flagp = xmalloc(sizeof (flags[0]) * s->dcols);
02265         if (flagp == NULL) {
02266             return;
02267         }
02268     } else {
02269         flagp = flags;
02270     }
02271     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
02272     for (i = 0; i < s->dcols; i++) {
02273         s->dyncols[i].autoinc = SQL_FALSE;
02274         s->dyncols[i].notnull = SQL_NULLABLE;
02275     }
02276     for (i = 0; i < s->dcols; i++) {
02277         int ret, lastpk = -1, autoinccount = 0;
02278         char *sql;
02279 
02280         if (!s->dyncols[i].table[0]) {
02281             continue;
02282         }
02283         if (flagp[i]) {
02284             continue;
02285         }
02286         sql = sqlite3_mprintf("PRAGMA table_info(%Q)", s->dyncols[i].table);
02287         if (!sql) {
02288             continue;
02289         }
02290         dbtraceapi(d, "sqlite3_get_table", sql);
02291         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, NULL);
02292         sqlite3_free(sql);
02293         if (ret != SQLITE_OK) {
02294             continue;
02295         }
02296         k = findcol(rowp, ncols, "name");
02297         t = findcol(rowp, ncols, "type");
02298         pk = findcol(rowp, ncols, "pk");
02299         nn = findcol(rowp, ncols, "notnull");
02300         if (k < 0 || t < 0) {
02301             goto freet;
02302         }
02303         for (r = 1; r <= nrows; r++) {
02304             int m;
02305 
02306             for (m = i; m < s->dcols; m++) {
02307                 char *colname = s->dyncols[m].column;
02308 
02309                 if (s->longnames) {
02310                     char *dotp = strchr(colname, '.');
02311 
02312                     if (dotp) {
02313                         colname = dotp + 1;
02314                     }
02315                 }
02316                 if (!flagp[m] &&
02317                     strcmp(colname, rowp[r * ncols + k]) == 0 &&
02318                     strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
02319                     char *typename = rowp[r * ncols + t];
02320 
02321                     flagp[m] = 1;
02322                     freep(&s->dyncols[m].typename);
02323                     s->dyncols[m].typename = xstrdup(typename);
02324                     s->dyncols[m].type =
02325                         mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
02326                                    s->nowchar[0] || s->nowchar[1]);
02327                     getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
02328                           NULL);
02329 #ifdef SQL_LONGVARCHAR
02330                     if (s->dyncols[m].type == SQL_VARCHAR &&
02331                         s->dyncols[m].size > 255) {
02332                         s->dyncols[m].type = SQL_LONGVARCHAR;
02333                     }
02334 #endif
02335 #ifdef WINTERFACE
02336 #ifdef SQL_WLONGVARCHAR
02337                     if (s->dyncols[i].type == SQL_WVARCHAR &&
02338                         s->dyncols[i].size > 255) {
02339                         s->dyncols[i].type = SQL_WLONGVARCHAR;
02340                     }
02341 #endif
02342 #endif
02343                     if (s->dyncols[i].type == SQL_VARBINARY &&
02344                         s->dyncols[i].size > 255) {
02345                         s->dyncols[i].type = SQL_LONGVARBINARY;
02346                     }
02347                     if (pk >= 0 && strcmp(rowp[r * ncols + pk], "1") == 0) {
02348                         if (++autoinccount > 1) {
02349                             if (lastpk >= 0) {
02350                                 s->dyncols[lastpk].autoinc = SQL_FALSE;
02351                                 lastpk = -1;
02352                             }
02353                         } else {
02354                             lastpk = m;
02355                             if (strlen(typename) == 7 &&
02356                                 strncasecmp(typename, "integer", 7) == 0) {
02357                                 s->dyncols[m].autoinc = SQL_TRUE;
02358                             }
02359                         }
02360                     }
02361                     if (nn >= 0 && rowp[r * ncols + nn][0] != '0') {
02362                         s->dyncols[m].notnull = SQL_NO_NULLS;
02363                     }
02364                 }
02365             }
02366         }
02367 freet:
02368         sqlite3_free_table(rowp);
02369     }
02370     if (flagp != flags) {
02371         freep(&flagp);
02372     }
02373 #endif
02374 }
02375 
02383 static int
02384 getmdays(int year, int month)
02385 {
02386     static const int mdays[] = {
02387         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
02388     };
02389     int mday;
02390 
02391     if (month < 1) {
02392         return 0;
02393     }
02394     mday = mdays[(month - 1) % 12];
02395     if (mday == 28 && year % 4 == 0 &&
02396         (!(year % 100 == 0) || year % 400 == 0)) {
02397         mday++;
02398     }
02399     return mday;
02400 }
02401 
02412 static int
02413 str2date(char *str, DATE_STRUCT *ds)
02414 {
02415     int i, err = 0;
02416     char *p, *q;
02417 
02418     ds->year = ds->month = ds->day = 0;
02419     p = str;
02420     while (*p && !ISDIGIT(*p)) {
02421         ++p;
02422     }
02423     q = p;
02424     i = 0;
02425     while (*q && !ISDIGIT(*q)) {
02426         ++i;
02427         ++q;
02428     }
02429     if (i >= 8) {
02430         char buf[8];
02431 
02432         strncpy(buf, p + 0, 4); buf[4] = '\0';
02433         ds->year = strtol(buf, NULL, 10);
02434         strncpy(buf, p + 4, 2); buf[2] = '\0';
02435         ds->month = strtol(buf, NULL, 10);
02436         strncpy(buf, p + 6, 2); buf[2] = '\0';
02437         ds->day = strtol(buf, NULL, 10);
02438         goto done;
02439     }
02440     i = 0;
02441     while (i < 3) {
02442         int n;
02443 
02444         q = NULL; 
02445         n = strtol(p, &q, 10);
02446         if (!q || q == p) {
02447             if (*q == '\0') {
02448                 if (i == 0) {
02449                     err = 1;
02450                 }
02451                 goto done;
02452             }
02453         }
02454         if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
02455             switch (i) {
02456             case 0: ds->year = n; break;
02457             case 1: ds->month = n; break;
02458             case 2: ds->day = n; break;
02459             }
02460             ++i;
02461             if (*q) {
02462                 ++q;
02463             }
02464         } else {
02465             i = 0;
02466             while (*q && !ISDIGIT(*q)) {
02467                 ++q;
02468             }
02469         }
02470         p = q;
02471     }
02472 done:
02473     /* final check for overflow */
02474     if (err ||
02475         ds->month < 1 || ds->month > 12 ||
02476         ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
02477         return -1;
02478     }
02479     return 0;
02480 }
02481 
02492 static int
02493 str2time(char *str, TIME_STRUCT *ts)
02494 {
02495     int i, err = 0;
02496     char *p, *q;
02497 
02498     ts->hour = ts->minute = ts->second = 0;
02499     p = str;
02500     while (*p && !ISDIGIT(*p)) {
02501         ++p;
02502     }
02503     q = p;
02504     i = 0;
02505     while (*q && ISDIGIT(*q)) {
02506         ++i;
02507         ++q;
02508     }
02509     if (i >= 6) {
02510         char buf[4];
02511 
02512         strncpy(buf, p + 0, 2); buf[2] = '\0';
02513         ts->hour = strtol(buf, NULL, 10);
02514         strncpy(buf, p + 2, 2); buf[2] = '\0';
02515         ts->minute = strtol(buf, NULL, 10);
02516         strncpy(buf, p + 4, 2); buf[2] = '\0';
02517         ts->second = strtol(buf, NULL, 10);
02518         goto done;
02519     }
02520     i = 0;
02521     while (i < 3) {
02522         int n;
02523 
02524         q = NULL; 
02525         n = strtol(p, &q, 10);
02526         if (!q || q == p) {
02527             if (*q == '\0') {
02528                 if (i == 0) {
02529                     err = 1;
02530                 }
02531                 goto done;
02532             }
02533         }
02534         if (*q == ':' || *q == '\0' || i == 2) {
02535             switch (i) {
02536             case 0: ts->hour = n; break;
02537             case 1: ts->minute = n; break;
02538             case 2: ts->second = n; break;
02539             }
02540             ++i;
02541             if (*q) {
02542                 ++q;
02543             }
02544         } else {
02545             i = 0;
02546             while (*q && !ISDIGIT(*q)) {
02547                 ++q;
02548             }
02549         }
02550         p = q;
02551     }
02552 done:
02553     /* final check for overflow */
02554     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
02555         return -1;
02556     }
02557     return 0;
02558 }
02559 
02575 static int
02576 str2timestamp(char *str, TIMESTAMP_STRUCT *tss)
02577 {
02578     int i, m, n, err = 0;
02579     char *p, *q, in = '\0';
02580 
02581     tss->year = tss->month = tss->day = 0;
02582     tss->hour = tss->minute = tss->second = 0;
02583     tss->fraction = 0;
02584     p = str;
02585     while (*p && !ISDIGIT(*p)) {
02586         ++p;
02587     }
02588     q = p;
02589     i = 0;
02590     while (*q && ISDIGIT(*q)) {
02591         ++i;
02592         ++q;
02593     }
02594     if (i >= 14) {
02595         char buf[16];
02596 
02597         strncpy(buf, p + 0, 4); buf[4] = '\0';
02598         tss->year = strtol(buf, NULL, 10);
02599         strncpy(buf, p + 4, 2); buf[2] = '\0';
02600         tss->month = strtol(buf, NULL, 10);
02601         strncpy(buf, p + 6, 2); buf[2] = '\0';
02602         tss->day = strtol(buf, NULL, 10);
02603         strncpy(buf, p + 8, 2); buf[2] = '\0';
02604         tss->hour = strtol(buf, NULL, 10);
02605         strncpy(buf, p + 10, 2); buf[2] = '\0';
02606         tss->minute = strtol(buf, NULL, 10);
02607         strncpy(buf, p + 12, 2); buf[2] = '\0';
02608         tss->second = strtol(buf, NULL, 10);
02609         if (i > 14) {
02610             m = i - 14;
02611             strncpy(buf, p + 14, m);
02612             while (m < 9) {
02613                 buf[m] = '0';
02614                 ++m;
02615             }
02616             buf[m] = '\0';
02617             tss->fraction = strtol(buf, NULL, 0);
02618         }
02619         m = 7;
02620         goto done;
02621     }
02622     m = i = 0;
02623     while ((m & 7) != 7) {
02624         q = NULL; 
02625         n = strtol(p, &q, 10);
02626         if (!q || q == p) {
02627             if (*q == '\0') {
02628                 if (m < 1) {
02629                     err = 1;
02630                 }
02631                 goto done;
02632             }
02633         }
02634         if (in == '\0') {
02635             switch (*q) {
02636             case '-':
02637             case '/':
02638                 if ((m & 1) == 0) {
02639                     in = *q;
02640                     i = 0;
02641                 }
02642                 break;
02643             case ':':
02644                 if ((m & 2) == 0) {
02645                     in = *q;
02646                     i = 0;
02647                 }
02648                 break;
02649             case ' ':
02650             case '.':
02651                 break;
02652             default:
02653                 in = '\0';
02654                 i = 0;
02655                 break;
02656             }
02657         }
02658         switch (in) {
02659         case '-':
02660         case '/':
02661             switch (i) {
02662             case 0: tss->year = n; break;
02663             case 1: tss->month = n; break;
02664             case 2: tss->day = n; break;
02665             }
02666             if (++i >= 3) {
02667                 i = 0;
02668                 m |= 1;
02669                 if (!(m & 2)) {
02670                     m |= 8;
02671                 }
02672                 goto skip;
02673             } else {
02674                 ++q;
02675             }
02676             break;
02677         case ':':
02678             switch (i) {
02679             case 0: tss->hour = n; break;
02680             case 1: tss->minute = n; break;
02681             case 2: tss->second = n; break;
02682             }
02683             if (++i >= 3) {
02684                 i = 0;
02685                 m |= 2;
02686                 if (*q == '.') {
02687                     in = '.';
02688                     goto skip2;
02689                 }
02690                 if (*q == ' ') {
02691                     if ((m & 1) == 0) {
02692                         char *e = NULL;
02693                         int dummy;
02694 
02695                         dummy = strtol(q + 1, &e, 10);
02696                         if (e && *e == '-') {
02697                             goto skip;
02698                         }
02699                     }
02700                     in = '.';
02701                     goto skip2;
02702                 }
02703                 goto skip;
02704             } else {
02705                 ++q;
02706             }
02707             break;
02708         case '.':
02709             if (++i >= 1) {
02710                 int ndig = q - p;
02711 
02712                 if (p[0] == '+' || p[0] == '-') {
02713                     ndig--;
02714                 }
02715                 while (ndig < 9) {
02716                     n = n * 10;
02717                     ++ndig;
02718                 }
02719                 tss->fraction = n;
02720                 m |= 4;
02721                 i = 0;
02722             }
02723         default:
02724         skip:
02725             in = '\0';
02726         skip2:
02727             while (*q && !ISDIGIT(*q)) {
02728                 ++q;
02729             }
02730         }
02731         p = q;
02732     }
02733     if ((m & 7) > 1 && (m & 8)) {
02734         /* ISO8601 timezone */
02735         if (p > str && ISDIGIT(*p)) {
02736             int nn, sign;
02737 
02738             q = p - 1;
02739             if (*q != '+' && *q != '-') {
02740                 goto done;
02741             }
02742             sign = (*q == '+') ? -1 : 1;
02743             q = NULL;
02744             n = strtol(p, &q, 10);
02745             if (!q || *q++ != ':' || !ISDIGIT(*q)) {
02746                 goto done;
02747             }
02748             p = q;
02749             q = NULL;
02750             nn = strtol(p, &q, 0);
02751             tss->minute += nn * sign;
02752             if ((SQLSMALLINT) tss->minute < 0) {
02753                 tss->hour -= 1;
02754                 tss->minute += 60;
02755             } else if (tss->minute >= 60) {
02756                 tss->hour += 1;
02757                 tss->minute -= 60;
02758             }
02759             tss->hour += n * sign;
02760             if ((SQLSMALLINT) tss->hour < 0) {
02761                 tss->day -= 1;
02762                 tss->hour += 24;
02763             } else if (tss->hour >= 24) {
02764                 tss->day += 1;
02765                 tss->hour -= 24;
02766             }
02767             if ((short) tss->day < 1 || tss->day >= 28) {
02768                 int mday, pday, pmon;
02769 
02770                 mday = getmdays(tss->year, tss->month);
02771                 pmon = tss->month - 1;
02772                 if (pmon < 1) {
02773                     pmon = 12;
02774                 }
02775                 pday = getmdays(tss->year, pmon);
02776                 if ((SQLSMALLINT) tss->day < 1) {
02777                     tss->month -= 1;
02778                     tss->day = pday;
02779                 } else if (tss->day > mday) {
02780                     tss->month += 1;
02781                     tss->day = 1;
02782                 }
02783                 if ((SQLSMALLINT) tss->month < 1) {
02784                     tss->year -= 1;
02785                     tss->month = 12;
02786                 } else if (tss->month > 12) {
02787                     tss->year += 1;
02788                     tss->month = 1;
02789                 }
02790             }
02791         }
02792     }
02793 done:
02794     /* Replace missing year/month/day with current date */
02795     if (!err && (m & 1) == 0) {
02796 #ifdef _WIN32
02797         SYSTEMTIME t;
02798 
02799         GetLocalTime(&t);
02800         tss->year = t.wYear;
02801         tss->month = t.wMonth;
02802         tss->day = t.wDay;
02803 #else
02804         struct timeval tv;
02805         struct tm tm;
02806 
02807         gettimeofday(&tv, NULL);
02808         tm = *localtime(&tv.tv_sec);
02809         tss->year = tm.tm_year + 1900;
02810         tss->month = tm.tm_mon + 1;
02811         tss->day = tm.tm_mday;
02812 #endif
02813     }
02814     /* final check for overflow */
02815     if (err ||
02816         tss->month < 1 || tss->month > 12 ||
02817         tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
02818         tss->hour > 23 || tss->minute > 59 || tss->second > 59) {
02819         return -1;
02820     }
02821     return ((m & 7) < 1) ? -1 : 0;
02822 }
02823 
02830 static int
02831 getbool(char *string)
02832 {
02833     if (string) {
02834         return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
02835     }
02836     return 0;
02837 }
02838 
02845 static void
02846 dbtrace(void *arg, const char *msg)
02847 {
02848     DBC *d = (DBC *) arg;
02849 
02850     if (msg && d->trace) {
02851         int len = strlen(msg);
02852 
02853         if (len > 0) {
02854             char *end = "\n";
02855 
02856             if (msg[len - 1] != ';') {
02857                 end = ";\n";
02858             }
02859             fprintf(d->trace, "%s%s", msg, end);
02860             fflush(d->trace);
02861         }
02862     }
02863 }
02864 
02872 static void
02873 dbtraceapi(DBC *d, char *fn, const char *sql)
02874 {
02875     if (fn && d->trace) {
02876         if (sql) {
02877             fprintf(d->trace, "-- %s: %s\n", fn, sql);
02878         } else {
02879             fprintf(d->trace, "-- %s\n", fn);
02880         }
02881         fflush(d->trace);
02882     }
02883 }
02884 
02892 static void
02893 dbtracerc(DBC *d, int rc, char *err)
02894 {
02895     if (rc != SQLITE_OK && d->trace) {
02896         fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
02897         fprintf(d->trace, err ? ": %s\n" : "\n", err);
02898         fflush(d->trace);
02899     }
02900 }
02901 
02916 static SQLRETURN
02917 dbopen(DBC *d, char *name, int isu, char *dsn, char *sflag,
02918        char *spflag, char *ntflag, char *jmode, char *busy)
02919 {
02920     char *endp = NULL;
02921     int rc, tmp, busyto = 100000;
02922 #if defined(HAVE_SQLITE3VFS) && HAVE_SQLITE3VFS
02923     int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
02924     char *uname = name;
02925     const char *vfs_name = NULL;
02926 #endif
02927 
02928     if (d->sqlite) {
02929         if (d->trace) {
02930             fprintf(d->trace, "-- sqlite3_close (deferred): '%s'\n",
02931                     d->dbname);
02932             fflush(d->trace);
02933         }
02934         sqlite3_close(d->sqlite);
02935         d->sqlite = NULL;
02936     }
02937 #if defined(HAVE_SQLITE3VFS) && HAVE_SQLITE3VFS
02938     if (d->nocreat) {
02939         flags &= ~ SQLITE_OPEN_CREATE;
02940     }
02941 #if defined(_WIN32) || defined(_WIN64)
02942     if (!isu) {
02943         uname = wmb_to_utf(name, -1);
02944         if (!uname) {
02945             rc = SQLITE_NOMEM;
02946             setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
02947             return SQL_ERROR;
02948         }
02949     }
02950 #endif
02951 #if defined(ENABLE_NVFS) && ENABLE_NVFS
02952     vfs_name = nvfs_makevfs(uname);
02953 #endif
02954     rc = sqlite3_open_v2(uname, &d->sqlite, flags, vfs_name);
02955 #if defined(WINTERFACE) || defined(_WIN32) || defined(_WIN64)
02956     if (uname != name) {
02957         uc_free(uname);
02958     }
02959 #endif
02960 #else
02961 #if defined(_WIN32) || defined(_WIN64)
02962     if (d->nocreat) {
02963         char *cname = NULL;
02964 
02965         if (isu) {
02966             cname = utf_to_wmb(name, -1);
02967         }
02968         if (GetFileAttributesA(cname ? cname : name) == 0xffffffff) {
02969             uc_free(cname);
02970             rc = SQLITE_CANTOPEN;
02971             setstatd(d, rc, "cannot open database",
02972                      (*d->ov3) ? "HY000" : "S1000");
02973             return SQL_ERROR;
02974         }
02975         uc_free(cname);
02976     }
02977 #else
02978     if (d->nocreat && access(name, 004) < 0) {
02979         rc = SQLITE_CANTOPEN;
02980         setstatd(d, rc, "cannot open database", (*d->ov3) ? "HY000" : "S1000");
02981         return SQL_ERROR;
02982     }
02983 #endif
02984 #if defined(_WIN32) || defined(_WIN64)
02985     if (!isu) {
02986         WCHAR *wname = wmb_to_uc(name, -1);
02987 
02988         if (!wname) {
02989             rc = SQLITE_NOMEM;
02990             setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
02991             return SQL_ERROR;
02992         }
02993         rc = sqlite3_open16(wname, &d->sqlite);
02994         uc_free(wname);
02995     } else
02996 #endif
02997     rc = sqlite3_open(name, &d->sqlite);
02998 #endif /* !HAVE_SQLITE3VFS */
02999     if (rc != SQLITE_OK) {
03000 connfail:
03001         setstatd(d, rc, "connect failed", (*d->ov3) ? "HY000" : "S1000");
03002         if (d->sqlite) {
03003             sqlite3_close(d->sqlite);
03004             d->sqlite = NULL;
03005         }
03006         return SQL_ERROR;
03007     }
03008     if (d->trace) {
03009         sqlite3_trace(d->sqlite, dbtrace, d);
03010     }
03011     d->step_enable = getbool(sflag);
03012     d->trans_disable = getbool(ntflag);
03013     d->curtype = d->step_enable ?
03014         SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
03015     tmp = strtol(busy, &endp, 0);
03016     if (endp && *endp == '\0' && endp != busy) {
03017         busyto = tmp;
03018     }
03019     if (busyto < 1 || busyto > 1000000) {
03020         busyto = 1000000;
03021     }
03022     d->timeout = busyto;
03023     if ((rc = setsqliteopts(d->sqlite, d)) != SQLITE_OK) {
03024         if (d->trace) {
03025             fprintf(d->trace, "-- sqlite3_close: '%s'\n",
03026                     d->dbname);
03027             fflush(d->trace);
03028         }
03029         sqlite3_close(d->sqlite);
03030         d->sqlite = NULL;
03031         goto connfail;
03032     }
03033     if (!spflag || spflag[0] == '\0') {
03034         spflag = "NORMAL";
03035     }
03036     if (spflag[0] != '\0') {
03037         char syncp[128];
03038 
03039         sprintf(syncp, "PRAGMA synchronous = %8.8s;", spflag);
03040         sqlite3_exec(d->sqlite, syncp, NULL, NULL, NULL);
03041     }
03042     if (jmode[0] != '\0') {
03043         char jourp[128];
03044 
03045         sprintf(jourp, "PRAGMA journal_mode = %16.16s;", jmode);
03046         sqlite3_exec(d->sqlite, jourp, NULL, NULL, NULL);
03047     }
03048     freep(&d->dbname);
03049     d->dbname = xstrdup(name);
03050     freep(&d->dsn);
03051     d->dsn = xstrdup(dsn);
03052     if (d->trace) {
03053         fprintf(d->trace, "-- sqlite3_open: '%s'\n", d->dbname);
03054         fflush(d->trace);
03055     }
03056 #if defined(_WIN32) || defined(_WIN64)
03057     {
03058         char pname[MAX_PATH];
03059         HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
03060                                FALSE, GetCurrentProcessId());
03061 
03062         pname[0] = '\0';
03063         if (h) {
03064             HMODULE m = NULL, l = LoadLibrary("psapi.dll");
03065             DWORD need;
03066             typedef BOOL (WINAPI *epmfunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
03067             typedef BOOL (WINAPI *gmbfunc)(HANDLE, HMODULE, LPSTR, DWORD);
03068             epmfunc epm;
03069             gmbfunc gmb;
03070 
03071             if (l) {
03072                 epm = (epmfunc) GetProcAddress(l, "EnumProcessModules");
03073                 gmb = (gmbfunc) GetProcAddress(l, "GetModuleBaseNameA");
03074                 if (epm && gmb && epm(h, &m, sizeof (m), &need)) {
03075                     gmb(h, m, pname, sizeof (pname));
03076                 }
03077                 FreeLibrary(l);
03078             }
03079             CloseHandle(h);
03080         }
03081         d->xcelqrx = strncasecmp(pname, "EXCEL", 5) == 0 ||
03082                      strncasecmp(pname, "MSQRY", 5) == 0;
03083         if (d->trace && d->xcelqrx) {
03084             fprintf(d->trace, "-- enabled EXCEL quirks\n");
03085             fflush(d->trace);
03086         }
03087     }
03088 #endif
03089     return SQL_SUCCESS;
03090 }
03091 
03098 static void
03099 dbloadext(DBC *d, char *exts)
03100 {
03101 #if defined(HAVE_SQLITE3LOADEXTENSION) && HAVE_SQLITE3LOADEXTENSION
03102     char *p;
03103     char path[SQL_MAX_MESSAGE_LENGTH];
03104     int plen = 0;
03105 
03106     if (!d->sqlite) {
03107         return;
03108     }
03109     sqlite3_enable_load_extension(d->sqlite, 1);
03110 #if defined(_WIN32) || defined(_WIN64)
03111     GetModuleFileName(hModule, path, sizeof (path));
03112     p = strrchr(path, '\\');
03113     plen = p ? ((p + 1) - path) : 0;
03114 #endif
03115     do {
03116         p = strchr(exts, ',');
03117         if (p) {
03118             strncpy(path + plen, exts, p - exts);
03119             path[plen + (p - exts)] = '\0';
03120         } else {
03121             strcpy(path + plen, exts);
03122         }
03123         if (exts[0]) {
03124             char *errmsg = NULL;
03125             int rc;
03126 #if defined(_WIN32) || defined(_WIN64)
03127             char *q;
03128 
03129             q = path + plen;
03130             if (!(q[0] &&
03131                   ((q[1] == ':' && (q[2] == '\\' || q[2] == '/')) ||
03132                    q[0] == '\\' || q[0] == '/' || q[0] == '.'))) {
03133                 q = path;
03134             }
03135             rc = sqlite3_load_extension(d->sqlite, q, 0, &errmsg);
03136 #else
03137             rc = sqlite3_load_extension(d->sqlite, path, 0, &errmsg);
03138 #endif
03139             if (rc != SQLITE_OK) {
03140 #if defined(_WIN32) || defined(_WIN64)
03141                 char buf[512], msg[512];
03142 
03143                 LoadString(hModule, IDS_EXTERR, buf, sizeof (buf));
03144                 wsprintf(msg, buf, q, errmsg ?
03145                          errmsg : "no error info available");
03146                 LoadString(hModule, IDS_EXTTITLE, buf, sizeof (buf));
03147                 MessageBox(NULL, msg, buf,
03148                            MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
03149                            MB_SETFOREGROUND);
03150 #else
03151                 fprintf(stderr, "extension '%s' did not load%s%s\n",
03152                         path, errmsg ? ": " : "", errmsg ? errmsg : "");
03153 #endif
03154             }
03155         }
03156         if (p) {
03157             exts = p + 1;
03158         }
03159     } while (p);
03160 #endif /* HAVE_SQLITE3LOADEXTENSION */
03161 }
03162 
03172 static char *
03173 s3stmt_coltype(sqlite3_stmt *s3stmt, int col, DBC *d, int *guessed_types)
03174 {
03175     char *typename = (char *) sqlite3_column_decltype(s3stmt, col);
03176     char guess[64];
03177 
03178     guess[0] = '\0';
03179     if (!typename) {
03180         int coltype = sqlite3_column_type(s3stmt, col);
03181 
03182         if (guessed_types) {
03183             guessed_types[0]++;
03184         }
03185         if (d->trace) {
03186             sprintf(guess, " (guessed from %d)", coltype);
03187         }
03188         switch (coltype) {
03189         case SQLITE_INTEGER: typename = "integer"; break;
03190         case SQLITE_FLOAT:   typename = "double";  break;
03191         default:
03192         case SQLITE_TEXT:    typename = "varchar"; break;
03193         case SQLITE_BLOB:    typename = "blob";    break;
03194 #if 0
03195         case SQLITE_NULL:    typename = "null";    break;
03196 #endif
03197         }
03198     }
03199     if (d->trace) {
03200         fprintf(d->trace, "-- column %d type%s: '%s'\n", col + 1,
03201                 guess, typename);
03202         fflush(d->trace);
03203     }
03204     return typename;
03205 }
03206 
03207 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && HAVE_SQLITE3TABLECOLUMNMETADATA
03208 
03217 static void
03218 s3stmt_addmeta(sqlite3_stmt *s3stmt, int col, DBC *d, COL *ci)
03219 {
03220     int nn = 0, pk = 0, ai = 0;
03221     const char *dn, *tn, *cn, *dummy1, *dummy2;
03222 
03223     dn = sqlite3_column_database_name(s3stmt, col);
03224     tn = sqlite3_column_table_name(s3stmt, col);
03225     cn = sqlite3_column_origin_name(s3stmt, col);
03226     sqlite3_table_column_metadata(d->sqlite, dn, tn, cn,
03227                                   &dummy1, &dummy2,
03228                                   &nn, &pk, &ai);
03229     ci->autoinc = ai ? SQL_TRUE: SQL_FALSE;
03230     ci->notnull = nn ? SQL_NO_NULLS : SQL_NULLABLE;
03231     if (d->trace) {
03232         fprintf(d->trace, "-- column %d %s\n",
03233                 col + 1, nn ? "notnull" : "nullable");
03234         if (ai) {
03235             fprintf(d->trace, "-- column %d autoincrement\n", col + 1);
03236         }
03237         fflush(d->trace);
03238     }
03239 }
03240 
03241 #endif
03242 
03249 static int
03250 s3stmt_step(STMT *s)
03251 {
03252     DBC *d = (DBC *) s->dbc;
03253     char **rowd = NULL;
03254     const char *errp = NULL;
03255     int i, ncols, rc;
03256 
03257     if (s != d->cur_s3stmt || !s->s3stmt) {
03258         setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
03259         return SQL_ERROR;
03260     }
03261     rc = sqlite3_step(s->s3stmt);
03262     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
03263         ++s->s3stmt_rownum;
03264         ncols = sqlite3_column_count(s->s3stmt);
03265         if (d->s3stmt_needmeta && s->s3stmt_rownum == 0 && ncols > 0) {
03266             PTRDIFF_T size;
03267             char *p;
03268             COL *dyncols;
03269             const char *colname, *typename;
03270 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
03271             char *tblname;
03272 #endif
03273 
03274             for (i = size = 0; i < ncols; i++) {
03275                 colname = sqlite3_column_name(s->s3stmt, i);
03276                 size += 3 + 3 * strlen(colname);
03277             }
03278 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
03279             tblname = (char *) size;
03280             for (i = 0; i < ncols; i++) {
03281                 p = (char *) sqlite3_column_table_name(s->s3stmt, i);
03282                 size += 2 + (p ? strlen(p) : 0);
03283             }
03284 #endif
03285             dyncols = xmalloc(ncols * sizeof (COL) + size);
03286             if (!dyncols) {
03287                 freedyncols(s);
03288                 s->ncols = 0;
03289                 dbtraceapi(d, "sqlite3_finalize", 0);
03290                 sqlite3_finalize(s->s3stmt);
03291                 s->s3stmt = NULL;
03292                 d->cur_s3stmt = NULL;
03293                 return nomem(s);
03294             }
03295             p = (char *) (dyncols + ncols);
03296 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
03297             tblname = p + (PTRDIFF_T) tblname;    
03298 #endif
03299             for (i = 0; i < ncols; i++) {
03300                 char *q;
03301 
03302                 colname = sqlite3_column_name(s->s3stmt, i);
03303                 if (d->trace) {
03304                     fprintf(d->trace, "-- column %d name: '%s'\n",
03305                             i + 1, colname);
03306                     fflush(d->trace);
03307                 }
03308 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
03309                 q = (char *) sqlite3_column_table_name(s->s3stmt, i);
03310                 strcpy(tblname, q ? q : "");
03311                 if (d->trace) {
03312                     fprintf(d->trace, "-- table %d name: '%s'\n",
03313                             i + 1, tblname);
03314                     fflush(d->trace);
03315                 }
03316                 dyncols[i].table = tblname;
03317                 tblname += strlen(tblname) + 1;
03318 #endif
03319                 typename = s3stmt_coltype(s->s3stmt, i, d, 0);
03320                 dyncols[i].db = ((DBC *) (s->dbc))->dbname;
03321                 strcpy(p, colname);
03322                 dyncols[i].label = p;
03323                 p += strlen(p) + 1;
03324                 q = strchr(colname, '.');
03325                 if (q) {
03326                     char *q2 = strchr(q + 1, '.');
03327 
03328                     /* SQLite 3.3.4 produces view.table.column sometimes */
03329                     if (q2) {
03330                         q = q2;
03331                     }
03332                 }
03333                 if (q) {
03334 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
03335                     dyncols[i].table = p;
03336 #endif
03337                     strncpy(p, colname, q - colname);
03338                     p[q - colname] = '\0';
03339                     p += strlen(p) + 1;
03340                     strcpy(p, q + 1);
03341                     dyncols[i].column = p;
03342                     p += strlen(p) + 1;
03343                 } else {
03344 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
03345                     dyncols[i].table = "";
03346 #endif
03347                     strcpy(p, colname);
03348                     dyncols[i].column = p;
03349                     p += strlen(p) + 1;
03350                 }
03351                 if (s->longnames) {
03352                     dyncols[i].column = dyncols[i].label;
03353                 }
03354 #ifdef SQL_LONGVARCHAR
03355                 dyncols[i].type = SQL_LONGVARCHAR;
03356                 dyncols[i].size = 65535;
03357 #else
03358                 dyncols[i].type = SQL_VARCHAR;
03359                 dyncols[i].size = 255;
03360 #endif
03361                 dyncols[i].index = i;
03362                 dyncols[i].scale = 0;
03363                 dyncols[i].prec = 0;
03364                 dyncols[i].nosign = 1;
03365 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && HAVE_SQLITE3TABLECOLUMNMETADATA
03366                 s3stmt_addmeta(s->s3stmt, i, d, &dyncols[i]);
03367 #else
03368                 dyncols[i].autoinc = SQL_FALSE;
03369                 dyncols[i].notnull = SQL_NULLABLE;
03370 #endif
03371                 dyncols[i].typename = xstrdup(typename);
03372             }
03373             freedyncols(s);
03374             s->ncols = s->dcols = ncols;
03375             s->dyncols = s->cols = dyncols;
03376             fixupdyncols(s, d);
03377             mkbindcols(s, s->ncols);
03378             d->s3stmt_needmeta = 0;
03379         }
03380         if (ncols <= 0) {
03381             goto killstmt;
03382         }
03383         if (rc == SQLITE_DONE) {
03384             freeresult(s, 0);
03385             s->nrows = 0;
03386             dbtraceapi(d, "sqlite3_finalize", 0);
03387             sqlite3_finalize(s->s3stmt);
03388             s->s3stmt = NULL;
03389             d->cur_s3stmt = NULL;
03390             return SQL_SUCCESS;
03391         }
03392         rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
03393         if (rowd) {
03394             const unsigned char *value;
03395 
03396             rowd[0] = (char *) ((PTRDIFF_T) (ncols * 2));
03397             ++rowd;
03398             for (i = 0; i < ncols; i++) {
03399                 int coltype = sqlite3_column_type(s->s3stmt, i);
03400 
03401                 rowd[i] = rowd[i + ncols] = NULL;
03402                 if (coltype == SQLITE_BLOB) {
03403                     int k, nbytes = sqlite3_column_bytes(s->s3stmt, i);
03404                     char *qp;
03405                     unsigned const char *bp;
03406 
03407                     bp = sqlite3_column_blob(s->s3stmt, i);
03408                     qp = xmalloc(nbytes * 2 + 4);
03409                     if (qp) {
03410                         rowd[i + ncols] = qp;
03411                         *qp++ = 'X';
03412                         *qp++ = '\'';
03413                         for (k = 0; k < nbytes; k++) {
03414                             *qp++ = xdigits[(bp[k] >> 4)];
03415                             *qp++ = xdigits[(bp[k] & 0xF)];
03416                         }
03417                         *qp++ = '\'';
03418                         *qp = '\0';
03419                     }
03420                 } else if (coltype != SQLITE_NULL) {
03421                     value = sqlite3_column_text(s->s3stmt, i);
03422                     rowd[i + ncols] = xstrdup((char *) value);
03423                 }
03424             }
03425             for (i = 0; i < ncols; i++) {
03426                 int coltype = sqlite3_column_type(s->s3stmt, i);
03427 
03428                 value = NULL;
03429                 if (coltype == SQLITE_BLOB) {
03430                     value = sqlite3_column_blob(s->s3stmt, i);
03431                 } else if (coltype != SQLITE_NULL) {
03432                     value = sqlite3_column_text(s->s3stmt, i);
03433                 }
03434                 if (value && !rowd[i + ncols]) {
03435                     freerows(rowd);
03436                     rowd = 0;
03437                     break;
03438                 }
03439             }
03440         }
03441         if (rowd) {
03442             freeresult(s, 0);
03443             s->nrows = 1;
03444             s->rows = rowd;
03445             s->rowfree = freerows;
03446             if (rc == SQLITE_DONE) {
03447                 dbtraceapi(d, "sqlite3_finalize", 0);
03448                 sqlite3_finalize(s->s3stmt);
03449                 s->s3stmt = NULL;
03450                 d->cur_s3stmt = NULL;
03451             }
03452             return SQL_SUCCESS;
03453         }
03454     }
03455 killstmt:
03456     dbtraceapi(d, "sqlite3_reset", 0);
03457     rc = sqlite3_reset(s->s3stmt);
03458     s->s3stmt_noreset = 1;
03459     errp = sqlite3_errmsg(d->sqlite);
03460     if (d->cur_s3stmt == s) {
03461         d->cur_s3stmt = NULL;
03462     }
03463     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
03464             errp ? errp : "unknown error", rc);
03465     return SQL_ERROR;   
03466 }
03467 
03473 static void
03474 s3stmt_end(STMT *s)
03475 {
03476     DBC *d;
03477 
03478     if (!s || !s->s3stmt) {
03479         return;
03480     }
03481     d = (DBC *) s->dbc;
03482     if (d) {
03483         d->busyint = 0;
03484     }
03485     if (!s->s3stmt_noreset) {
03486         dbtraceapi(d, "sqlite3_reset", 0);
03487         sqlite3_reset(s->s3stmt);
03488         s->s3stmt_noreset = 1;
03489         s->s3stmt_rownum = -1;
03490     }
03491     if (d->cur_s3stmt == s) {
03492         d->cur_s3stmt = NULL;
03493     }
03494 }
03495 
03501 static void
03502 s3stmt_end_if(STMT *s)
03503 {
03504     DBC *d = (DBC *) s->dbc;
03505 
03506     if (d) {
03507         d->busyint = 0;
03508     }
03509     if (d && d->cur_s3stmt == s) {
03510         s3stmt_end(s);
03511     }
03512 }
03513 
03519 static void
03520 s3stmt_drop(STMT *s)
03521 {
03522     if (s->s3stmt) {
03523         DBC *d = (DBC *) s->dbc;
03524 
03525         if (d) {
03526             dbtraceapi(d, "sqlite3_finalize", 0);
03527         }
03528         sqlite3_finalize(s->s3stmt);
03529         s->s3stmt = NULL;
03530         s->s3stmt_rownum = 0;
03531     }
03532 }
03533 
03540 static SQLRETURN
03541 s3stmt_start(STMT *s)
03542 {
03543     DBC *d = (DBC *) s->dbc;
03544     const char *endp;
03545     sqlite3_stmt *s3stmt = NULL;
03546     int rc, nretry = 0;
03547 
03548     d->s3stmt_needmeta = 0;
03549     if (!s->s3stmt) {
03550 #if defined(HAVE_SQLITE3PREPAREV2) && HAVE_SQLITE3PREPAREV2
03551         dbtraceapi(d, "sqlite3_prepare_v2", (char *) s->query);
03552 #else
03553         dbtraceapi(d, "sqlite3_prepare", (char *) s->query);
03554 #endif
03555         do {
03556             s3stmt = NULL;
03557 #if defined(HAVE_SQLITE3PREPAREV2) && HAVE_SQLITE3PREPAREV2
03558             rc = sqlite3_prepare_v2(d->sqlite, (char *) s->query, -1,
03559                                     &s3stmt, &endp);
03560 #else
03561             rc = sqlite3_prepare(d->sqlite, (char *) s->query, -1,
03562                                  &s3stmt, &endp);
03563 #endif
03564             if (rc != SQLITE_OK) {
03565                 if (s3stmt) {
03566                     sqlite3_finalize(s3stmt);
03567                     s3stmt = NULL;
03568                 }
03569             }
03570         } while (rc == SQLITE_SCHEMA && (++nretry) < 2);
03571         dbtracerc(d, rc, NULL);
03572         if (rc != SQLITE_OK) {
03573             if (s3stmt) {
03574                 dbtraceapi(d, "sqlite3_finalize", NULL);
03575                 sqlite3_finalize(s3stmt);
03576             }
03577             setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
03578                     sqlite3_errmsg(d->sqlite), rc);
03579             return SQL_ERROR;
03580         }
03581         if (sqlite3_bind_parameter_count(s3stmt) != s->nparams) {
03582             dbtraceapi(d, "sqlite3_finalize", 0);
03583             sqlite3_finalize(s3stmt);
03584             setstat(s, SQLITE_ERROR, "parameter marker count incorrect",
03585                     (*s->ov3) ? "HY000" : "S1000");
03586             return SQL_ERROR;
03587         }
03588         s->s3stmt = s3stmt;
03589         s->s3stmt_noreset = 1;
03590         d->s3stmt_needmeta = 1;
03591     }
03592     d->cur_s3stmt = s;
03593     s->s3stmt_rownum = -1;
03594     s3bind(d, s->s3stmt, s->nparams, s->bindparms);
03595     return SQL_SUCCESS;
03596 }
03597 
03602 SQLRETURN SQL_API
03603 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
03604 {
03605     SQLRETURN ret;
03606 
03607     HSTMT_LOCK(stmt);
03608     ret = drvunimplstmt(stmt);
03609     HSTMT_UNLOCK(stmt);
03610     return ret;
03611 }
03612 
03613 #ifndef WINTERFACE
03614 
03618 SQLRETURN SQL_API
03619 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
03620                SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
03621                SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
03622 {
03623     if (env == SQL_NULL_HENV) {
03624         return SQL_INVALID_HANDLE;
03625     }
03626     return SQL_ERROR;
03627 }
03628 #endif
03629 
03630 #ifdef WINTERFACE
03631 
03635 SQLRETURN SQL_API
03636 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
03637                 SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
03638                 SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
03639 {
03640     if (env == SQL_NULL_HENV) {
03641         return SQL_INVALID_HANDLE;
03642     }
03643     return SQL_ERROR;
03644 }
03645 #endif
03646 
03647 #ifndef WINTERFACE
03648 
03652 SQLRETURN SQL_API
03653 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
03654            SQLSMALLINT descmax, SQLSMALLINT *desclenp,
03655            SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
03656 {
03657     if (env == SQL_NULL_HENV) {
03658         return SQL_INVALID_HANDLE;
03659     }
03660     return SQL_ERROR;
03661 }
03662 #endif
03663 
03664 #ifdef WINTERFACE
03665 
03669 SQLRETURN SQL_API
03670 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
03671             SQLSMALLINT descmax, SQLSMALLINT *desclenp,
03672             SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
03673 {
03674     if (env == SQL_NULL_HENV) {
03675         return SQL_INVALID_HANDLE;
03676     }
03677     return SQL_ERROR;
03678 }
03679 #endif
03680 
03681 #ifndef WINTERFACE
03682 
03686 SQLRETURN SQL_API
03687 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
03688                  SQLCHAR *connout, SQLSMALLINT connoutMax,
03689                  SQLSMALLINT *connoutLen)
03690 {
03691     SQLRETURN ret;
03692 
03693     HDBC_LOCK(dbc);
03694     ret = drvunimpldbc(dbc);
03695     HDBC_UNLOCK(dbc);
03696     return ret;
03697 }
03698 #endif
03699 
03700 #ifdef WINTERFACE
03701 
03705 SQLRETURN SQL_API
03706 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
03707                   SQLWCHAR *connout, SQLSMALLINT connoutMax,
03708                   SQLSMALLINT *connoutLen)
03709 {
03710     SQLRETURN ret;
03711 
03712     HDBC_LOCK(dbc);
03713     ret = drvunimpldbc(dbc);
03714     HDBC_UNLOCK(dbc);
03715     return ret;
03716 }
03717 #endif
03718 
03727 static SQLRETURN
03728 drvputdata(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
03729 {
03730     STMT *s;
03731     int i, dlen, done = 0;
03732     BINDPARM *p;
03733 
03734     if (stmt == SQL_NULL_HSTMT) {
03735         return SQL_INVALID_HANDLE;
03736     }
03737     s = (STMT *) stmt;
03738     if (!s->query || s->nparams <= 0) {
03739 seqerr:
03740         setstat(s, -1, "sequence error", "HY010");
03741         return SQL_ERROR;
03742     }
03743     for (i = 0; i < s->nparams; i++) {
03744         p = &s->bindparms[i];
03745         if (p->need > 0) {
03746             int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
03747 
03748             if (len == SQL_NULL_DATA) {
03749                 freep(&p->parbuf);
03750                 p->param = NULL;
03751                 p->len = SQL_NULL_DATA;
03752                 p->need = -1;
03753             } else if (type != SQL_C_CHAR
03754 #ifdef WINTERFACE
03755                        && type != SQL_C_WCHAR
03756 #endif
03757                        && type != SQL_C_BINARY) {
03758                 int size = 0;
03759 
03760                 switch (type) {
03761                 case SQL_C_TINYINT:
03762                 case SQL_C_UTINYINT:
03763                 case SQL_C_STINYINT:
03764 #ifdef SQL_BIT
03765                 case SQL_C_BIT:
03766 #endif
03767                     size = sizeof (char);
03768                     break;
03769                 case SQL_C_SHORT:
03770                 case SQL_C_USHORT:
03771                 case SQL_C_SSHORT:
03772                     size = sizeof (short);
03773                     break;
03774                 case SQL_C_LONG:
03775                 case SQL_C_ULONG:
03776                 case SQL_C_SLONG:
03777                     size = sizeof (long);
03778                     break;
03779 #ifdef SQL_BIGINT
03780                 case SQL_C_UBIGINT:
03781                 case SQL_C_SBIGINT:
03782                     size = sizeof (SQLBIGINT);
03783                     break;
03784 #endif
03785                 case SQL_C_FLOAT:
03786                     size = sizeof (float);
03787                     break;
03788                 case SQL_C_DOUBLE:
03789                     size = sizeof (double);
03790                     break;
03791 #ifdef SQL_C_TYPE_DATE
03792                 case SQL_C_TYPE_DATE:
03793 #endif
03794                 case SQL_C_DATE:
03795                     size = sizeof (DATE_STRUCT);
03796                     break;
03797 #ifdef SQL_C_TYPE_DATE
03798                 case SQL_C_TYPE_TIME:
03799 #endif
03800                 case SQL_C_TIME:
03801                     size = sizeof (TIME_STRUCT);
03802                     break;
03803 #ifdef SQL_C_TYPE_DATE
03804                 case SQL_C_TYPE_TIMESTAMP:
03805 #endif
03806                 case SQL_C_TIMESTAMP:
03807                     size = sizeof (TIMESTAMP_STRUCT);
03808                     break;
03809                 }
03810                 freep(&p->parbuf);
03811                 p->parbuf = xmalloc(size);
03812                 if (!p->parbuf) {
03813                     return nomem(s);
03814                 }
03815                 p->param = p->parbuf;
03816                 memcpy(p->param, data, size);
03817                 p->len = size;
03818                 p->need = -1;
03819             } else if (len == SQL_NTS && (
03820                        type == SQL_C_CHAR
03821 #ifdef WINTERFACE
03822                        || type == SQL_C_WCHAR
03823 #endif
03824                       )) {
03825                 char *dp = data;
03826 
03827 #ifdef WINTERFACE
03828                 if (type == SQL_C_WCHAR) {
03829                     dp = uc_to_utf(data, len);
03830                     if (!dp) {
03831                         return nomem(s);
03832                     }
03833                 }
03834 #endif
03835                 dlen = strlen(dp);
03836                 freep(&p->parbuf);
03837                 p->parbuf = xmalloc(dlen + 1);
03838                 if (!p->parbuf) {
03839 #ifdef WINTERFACE
03840                     if (dp != data) {
03841                         uc_free(dp);
03842                     }
03843 #endif
03844                     return nomem(s);
03845                 }
03846                 p->param = p->parbuf;
03847                 strcpy(p->param, dp);
03848 #ifdef WINTERFACE
03849                 if (dp != data) {
03850                     uc_free(dp);
03851                 }
03852 #endif
03853                 p->len = dlen;
03854                 p->need = -1;
03855             } else if (len < 0) {
03856                 setstat(s, -1, "invalid length", "HY090");
03857                 return SQL_ERROR;
03858             } else {
03859                 dlen = min(p->len - p->offs, len);
03860                 if (!p->param) {
03861                     setstat(s, -1, "no memory for parameter", "HY013");
03862                     return SQL_ERROR;
03863                 }
03864                 memcpy((char *) p->param + p->offs, data, dlen);
03865                 p->offs += dlen;
03866                 if (p->offs >= p->len) {
03867 #ifdef WINTERFACE
03868                     if (type == SQL_C_WCHAR) {
03869                         char *dp = uc_to_utf(p->param, p->len);
03870                         char *np;
03871                         int nlen;
03872 
03873                         if (!dp) {
03874                             return nomem(s);
03875                         }
03876                         nlen = strlen(dp);
03877                         np = xmalloc(nlen + 1);
03878                         if (!np) {
03879                             uc_free(dp);
03880                             return nomem(s);
03881                         }
03882                         strcpy(np, dp);
03883                         uc_free(dp);
03884                         if (p->param == p->parbuf) {
03885                             freep(&p->parbuf);
03886                         }
03887                         p->parbuf = p->param = np;
03888                         p->len = nlen;
03889                     } else {
03890                         *((char *) p->param + p->len) = '\0';
03891                     }
03892                     p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR)
03893                             ? -1 : 0;
03894 #else
03895                     *((char *) p->param + p->len) = '\0';
03896                     p->need = (type == SQL_C_CHAR) ? -1 : 0;
03897 #endif
03898 #if defined(_WIN32) || defined(_WIN64)
03899                     if (p->type == SQL_C_WCHAR &&
03900                         (p->stype == SQL_VARCHAR ||
03901                          p->stype == SQL_LONGVARCHAR) &&
03902                          p->len == p->coldef * sizeof (SQLWCHAR)) {
03903                         /* fix for MS-Access */
03904                         p->len = p->coldef;
03905                     }
03906 #endif
03907                 }
03908             }
03909             done = 1;
03910             break;
03911         }
03912     }
03913     if (!done) {
03914         goto seqerr;
03915     }
03916     return SQL_SUCCESS;
03917 }
03918 
03927 SQLRETURN SQL_API
03928 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
03929 {
03930     SQLRETURN ret;
03931 
03932     HSTMT_LOCK(stmt);
03933     ret = drvputdata(stmt, data, len);
03934     HSTMT_UNLOCK(stmt);
03935     return ret;
03936 }
03937 
03943 static SQLRETURN
03944 freeparams(STMT *s)
03945 {
03946     if (s->bindparms) {
03947         int n;
03948 
03949         for (n = 0; n < s->nbindparms; n++) {
03950             freep(&s->bindparms[n].parbuf);
03951             memset(&s->bindparms[n], 0, sizeof (BINDPARM));
03952         }
03953     }
03954     return SQL_SUCCESS;
03955 }
03956 
03968 static SQLRETURN
03969 setupparam(STMT *s, char *sql, int pnum)
03970 {
03971     int type, len = 0, needalloc = 0;
03972     BINDPARM *p;
03973 
03974     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
03975         goto error;
03976     }
03977     p = &s->bindparms[pnum];
03978     type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
03979     if (p->need > 0) {
03980         return setupparbuf(s, p);      
03981     }
03982     p->strbuf[0] = '\0';
03983     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
03984         p->s3type = SQLITE_NULL;
03985         p->s3size = 0;
03986         return SQL_SUCCESS;
03987     }
03988     switch (type) {
03989     case SQL_C_BINARY:
03990         p->s3type = SQLITE_BLOB;
03991         p->s3size = p->len;
03992         p->s3val = p->param;
03993         if (p->need < 0) {
03994             break;
03995         }
03996         if (!p->lenp) {
03997             len = p->len;
03998         } else {
03999             len = *p->lenp;
04000             if (len <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
04001                 len = SQL_LEN_DATA_AT_EXEC(len);
04002             }
04003         }
04004         if (len < 0) {
04005             setstat(s, -1, "invalid length", "HY009");
04006             return SQL_ERROR;
04007         }
04008         p->len = len;
04009         p->max = p->len;
04010         p->need = -1;
04011         p->s3size = len;
04012         break;
04013 #ifdef WINTERFACE
04014     case SQL_C_WCHAR:
04015 #endif
04016     case SQL_C_CHAR:
04017         p->s3type = SQLITE_TEXT;
04018         p->s3size = -1;
04019         p->s3val = p->param;
04020         if (!p->parbuf && p->lenp) {
04021 #ifdef WINTERFACE
04022             if (type == SQL_C_WCHAR) {
04023                 if (*p->lenp == SQL_NTS) {
04024                     p->max = uc_strlen(p->param) * sizeof (SQLWCHAR);
04025                 } else if (*p->lenp >= 0) {
04026                     p->max = *p->lenp;
04027                 }
04028             } else
04029 #endif
04030             if (type == SQL_C_CHAR) {
04031                 if (*p->lenp == SQL_NTS) {
04032                     p->len = p->max = strlen(p->param);
04033                 } else if (*p->lenp >= 0) {
04034                     p->len = p->max = *p->lenp;
04035                     needalloc = 1;
04036                 }
04037             }
04038         }
04039         if (p->need < 0 && p->parbuf == p->param) {
04040             break;
04041         }
04042 #ifdef WINTERFACE
04043         if (type == SQL_C_WCHAR) {
04044             char *dp = uc_to_utf(p->param, p->max);
04045 
04046             if (!dp) {
04047                 return nomem(s);
04048             }
04049             if (p->param == p->parbuf) {
04050                 freep(&p->parbuf);
04051             }
04052             p->parbuf = p->param = dp;
04053             p->len = strlen(p->param);
04054             p->s3val = p->param;
04055             p->s3size = p->len;
04056         } else
04057 #endif
04058         if (type == SQL_C_CHAR) {
04059             p->s3val = p->param;
04060             if (needalloc) {
04061                 char *dp;
04062 
04063                 freep(&p->parbuf);
04064                 dp = xmalloc(p->len + 1);
04065                 if (!dp) {
04066                     return nomem(s);
04067                 }
04068                 memcpy(dp, p->param, p->len);
04069                 dp[p->len] = '\0';
04070                 p->parbuf = p->param = dp;
04071                 p->s3val = p->param;
04072                 p->s3size = p->len;
04073             }
04074         }
04075         break;
04076     case SQL_C_UTINYINT:
04077         p->s3type = SQLITE_INTEGER;
04078         p->s3size = sizeof (int);
04079         p->s3ival = *((unsigned char *) p->param);
04080         break;
04081     case SQL_C_TINYINT:
04082     case SQL_C_STINYINT:
04083         p->s3type = SQLITE_INTEGER;
04084         p->s3size = sizeof (int);
04085         p->s3ival = *((char *) p->param);
04086         break;
04087     case SQL_C_USHORT:
04088         p->s3type = SQLITE_INTEGER;
04089         p->s3size = sizeof (int);
04090         p->s3ival = *((unsigned short *) p->param);
04091         break;
04092     case SQL_C_SHORT:
04093     case SQL_C_SSHORT:
04094         p->s3type = SQLITE_INTEGER;
04095         p->s3size = sizeof (int);
04096         p->s3ival = *((short *) p->param);
04097         break;
04098     case SQL_C_ULONG:
04099         p->s3type = SQLITE_INTEGER;
04100         p->s3size = sizeof (int);
04101         p->s3ival = *((unsigned int *) p->param);
04102         break;
04103     case SQL_C_LONG:
04104     case SQL_C_SLONG:
04105         p->s3type = SQLITE_INTEGER;
04106         p->s3size = sizeof (int);
04107         p->s3ival = *((int *) p->param);
04108         break;
04109 #ifdef SQL_BIT
04110     case SQL_C_BIT:
04111         p->s3type = SQLITE_INTEGER;
04112         p->s3size = sizeof (int);
04113         p->s3ival = (*((unsigned char *) p->param)) ? 1 : 0;
04114         break;
04115 #endif
04116 #ifdef SQL_BIGINT
04117     case SQL_C_SBIGINT:
04118         p->s3type = SQLITE_INTEGER;
04119         p->s3size = sizeof (sqlite_int64);
04120         p->s3lival = *((sqlite_int64 *) p->param);
04121         break;
04122     case SQL_C_UBIGINT:
04123         p->s3type = SQLITE_INTEGER;
04124         p->s3size = sizeof (sqlite_int64);
04125         p->s3lival = *((sqlite_uint64 *) p->param);
04126         break;
04127 #endif
04128     case SQL_C_FLOAT:
04129         p->s3type = SQLITE_FLOAT;
04130         p->s3size = sizeof (double);
04131         p->s3dval = *((float *) p->param);
04132         break;
04133     case SQL_C_DOUBLE:
04134         p->s3type = SQLITE_FLOAT;
04135         p->s3size = sizeof (double);
04136         p->s3dval = *((double *) p->param);
04137         break;
04138 #ifdef SQL_C_TYPE_DATE
04139     case SQL_C_TYPE_DATE:
04140 #endif
04141     case SQL_C_DATE:
04142         sprintf(p->strbuf, "%04d-%02d-%02d",
04143                 ((DATE_STRUCT *) p->param)->year,
04144                 ((DATE_STRUCT *) p->param)->month,
04145                 ((DATE_STRUCT *) p->param)->day);
04146         p->s3type = SQLITE_TEXT;
04147         p->s3size = -1;
04148         p->s3val = p->strbuf;
04149         break;
04150 #ifdef SQL_C_TYPE_TIME
04151     case SQL_C_TYPE_TIME:
04152 #endif
04153     case SQL_C_TIME:
04154         sprintf(p->strbuf, "%02d:%02d:%02d",
04155                 ((TIME_STRUCT *) p->param)->hour,
04156                 ((TIME_STRUCT *) p->param)->minute,
04157                 ((TIME_STRUCT *) p->param)->second);
04158         p->s3type = SQLITE_TEXT;
04159         p->s3size = -1;
04160         p->s3val = p->strbuf;
04161         break;
04162 #ifdef SQL_C_TYPE_TIMESTAMP
04163     case SQL_C_TYPE_TIMESTAMP:
04164 #endif
04165     case SQL_C_TIMESTAMP:
04166         sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%d",
04167                 ((TIMESTAMP_STRUCT *) p->param)->year,
04168                 ((TIMESTAMP_STRUCT *) p->param)->month,
04169                 ((TIMESTAMP_STRUCT *) p->param)->day,
04170                 ((TIMESTAMP_STRUCT *) p->param)->hour,
04171                 ((TIMESTAMP_STRUCT *) p->param)->minute,
04172                 ((TIMESTAMP_STRUCT *) p->param)->second,
04173                 (int) ((TIMESTAMP_STRUCT *) p->param)->fraction);
04174         p->s3type = SQLITE_TEXT;
04175         p->s3size = -1;
04176         p->s3val = p->strbuf;
04177         break;
04178     default:
04179     error:
04180         setstat(s, -1, "unsupported parameter type",
04181                 (*s->ov3) ? "07009" : "S1093");
04182         return SQL_ERROR;
04183     }
04184     return SQL_SUCCESS;
04185 }
04186 
04202 static SQLRETURN
04203 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
04204              SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
04205              SQLSMALLINT scale,
04206              SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
04207 {
04208     STMT *s;
04209     BINDPARM *p;
04210 
04211     if (stmt == SQL_NULL_HSTMT) {
04212         return SQL_INVALID_HANDLE;
04213     }
04214     s = (STMT *) stmt;
04215     if (pnum == 0) {
04216         setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
04217         return SQL_ERROR;
04218     }
04219     if (!data && (!len || (*len != SQL_NULL_DATA &&
04220                            *len > SQL_LEN_DATA_AT_EXEC_OFFSET))) {
04221         setstat(s, -1, "invalid buffer", "HY003");
04222         return SQL_ERROR;
04223     }
04224     if (len && *len < 0 && *len > SQL_LEN_DATA_AT_EXEC_OFFSET &&
04225         *len != SQL_NTS && *len != SQL_NULL_DATA) {
04226         setstat(s, -1, "invalid length reference", "HY009");
04227         return SQL_ERROR;
04228     }
04229     --pnum;
04230     if (s->bindparms) {
04231         if (pnum >= s->nbindparms) {
04232             BINDPARM *newparms;
04233             
04234             newparms = xrealloc(s->bindparms,
04235                                 (pnum + 1) * sizeof (BINDPARM));
04236             if (!newparms) {
04237 outofmem:
04238                 return nomem(s);
04239             }
04240             s->bindparms = newparms;
04241             memset(&s->bindparms[s->nbindparms], 0,
04242                    (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
04243             s->nbindparms = pnum + 1;
04244         }
04245     } else {
04246         int npar = max(10, pnum + 1);
04247 
04248         s->bindparms = xmalloc(npar * sizeof (BINDPARM));
04249         if (!s->bindparms) {
04250             goto outofmem;
04251         }
04252         memset(s->bindparms, 0, npar * sizeof (BINDPARM));
04253         s->nbindparms = npar;
04254     }
04255     p = &s->bindparms[pnum];
04256     p->type = buftype;
04257     p->stype = ptype;
04258     p->coldef = coldef;
04259     p->scale = scale;
04260     p->max = buflen;
04261     p->inc = buflen;
04262     p->lenp = p->lenp0 = len;
04263     p->offs = 0;
04264     p->len = 0;
04265     p->param0 = data;
04266     freep(&p->parbuf);
04267     p->param = p->param0;
04268     p->bound = 1;
04269     p->need = 0;
04270     if (p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
04271         p->need = 1;       
04272     }
04273     return SQL_SUCCESS;
04274 }
04275 
04291 SQLRETURN SQL_API
04292 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
04293                  SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
04294                  SQLSMALLINT scale,
04295                  SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
04296 {
04297     SQLRETURN ret;
04298 
04299     HSTMT_LOCK(stmt);
04300     ret = drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
04301                        scale, data, buflen, len);
04302     HSTMT_UNLOCK(stmt);
04303     return ret;
04304 }
04305 
04319 SQLRETURN SQL_API
04320 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
04321              SQLSMALLINT ptype, SQLULEN lenprec,
04322              SQLSMALLINT scale, SQLPOINTER val,
04323              SQLLEN *lenp)
04324 {
04325     SQLRETURN ret;
04326 
04327     HSTMT_LOCK(stmt);
04328     ret = drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
04329                        lenprec, scale, val, 0, lenp);
04330     HSTMT_UNLOCK(stmt);
04331     return ret;
04332 }
04333 
04341 SQLRETURN SQL_API
04342 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
04343 {
04344     STMT *s;
04345     SQLSMALLINT dummy;
04346 
04347     HSTMT_LOCK(stmt);
04348     if (stmt == SQL_NULL_HSTMT) {
04349         return SQL_INVALID_HANDLE;
04350     }
04351     s = (STMT *) stmt;
04352     if (!nparam) {
04353         nparam = &dummy;
04354     }
04355     *nparam = s->nparams;
04356     HSTMT_UNLOCK(stmt);
04357     return SQL_SUCCESS;
04358 }
04359 
04367 static SQLRETURN
04368 setupparbuf(STMT *s, BINDPARM *p)
04369 {
04370     if (!p->parbuf) {
04371         p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
04372         if (p->len < 0 && p->len != SQL_NTS &&
04373             p->len != SQL_NULL_DATA) {
04374             setstat(s, -1, "invalid length", "HY009");
04375             return SQL_ERROR;
04376         }
04377         if (p->len >= 0) {
04378             p->parbuf = xmalloc(p->len + 1);
04379             if (!p->parbuf) {
04380                 return nomem(s);
04381             }
04382             p->param = p->parbuf;
04383         } else {
04384             p->param = NULL;
04385         }
04386     }
04387     return SQL_NEED_DATA;
04388 }
04389 
04397 SQLRETURN SQL_API
04398 SQLParamData(SQLHSTMT stmt, SQLPOINTER *pind)
04399 {
04400     STMT *s;
04401     int i;
04402     SQLPOINTER dummy;
04403     SQLRETURN ret;
04404 
04405     HSTMT_LOCK(stmt);
04406     if (stmt == SQL_NULL_HSTMT) {
04407         return SQL_INVALID_HANDLE;
04408     }
04409     s = (STMT *) stmt;
04410     if (!pind) {
04411         pind = &dummy;
04412     }
04413     for (i = 0; i < s->nparams; i++) {
04414         BINDPARM *p = &s->bindparms[i];
04415 
04416         if (p->need > 0) {
04417             *pind = (SQLPOINTER) p->param0;
04418             ret = setupparbuf(s, p);
04419             goto done;
04420         }
04421     }
04422     ret = drvexecute(stmt, 0);
04423 done:
04424     HSTMT_UNLOCK(stmt);
04425     return ret;
04426 }
04427 
04439 SQLRETURN SQL_API
04440 SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT *dtype,
04441                  SQLULEN *size, SQLSMALLINT *decdigits, SQLSMALLINT *nullable)
04442 {
04443     STMT *s;
04444     SQLRETURN ret = SQL_ERROR;
04445 
04446     HSTMT_LOCK(stmt);
04447     if (stmt == SQL_NULL_HSTMT) {
04448         return SQL_INVALID_HANDLE;
04449     }
04450     s = (STMT *) stmt;
04451     --pnum;
04452     if (pnum >= s->nparams) {
04453         setstat(s, -1, "invalid parameter index",
04454                 (*s->ov3) ? "HY000" : "S1000");
04455         goto done;
04456     }
04457     if (dtype) {
04458 #ifdef SQL_LONGVARCHAR
04459 #ifdef WINTERFACE
04460         *dtype = s->nowchar[0] ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
04461 #else   
04462         *dtype = SQL_LONGVARCHAR;
04463 #endif
04464 #else
04465 #ifdef WINTERFACE
04466         *dtype = s->nowchar[0] ? SQL_VARCHAR : SQL_WVARCHAR;
04467 #else
04468         *dtype = SQL_VARCHAR;
04469 #endif
04470 #endif
04471     }
04472     if (size) {
04473 #ifdef SQL_LONGVARCHAR
04474         *size = 65536;
04475 #else
04476         *size = 255;
04477 #endif
04478     }
04479     if (decdigits) {
04480         *decdigits = 0;
04481     }
04482     if (nullable) {
04483         *nullable = SQL_NULLABLE;
04484     }
04485     ret = SQL_SUCCESS;
04486 done:
04487     HSTMT_UNLOCK(stmt);
04488     return ret;
04489 }
04490 
04504 SQLRETURN SQL_API
04505 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
04506             SQLSMALLINT sqltype, SQLULEN coldef,
04507             SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
04508 {
04509     SQLRETURN ret;
04510 
04511     HSTMT_LOCK(stmt);
04512     ret = drvbindparam(stmt, par, SQL_PARAM_INPUT,
04513                        type, sqltype, coldef, scale, val,
04514                        SQL_SETPARAM_VALUE_MAX, nval);
04515     HSTMT_UNLOCK(stmt);
04516     return ret;
04517 }
04518 
04523 SQLRETURN SQL_API
04524 SQLParamOptions(SQLHSTMT stmt, SQLULEN rows, SQLULEN *rowp)
04525 {
04526     SQLRETURN ret;
04527 
04528     HSTMT_LOCK(stmt);
04529     ret = drvunimplstmt(stmt);
04530     HSTMT_UNLOCK(stmt);
04531     return ret;
04532 }
04533 
04534 #ifndef WINTERFACE
04535 
04539 SQLRETURN SQL_API
04540 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
04541                 SQLSMALLINT fieldid, SQLPOINTER value,
04542                 SQLINTEGER buflen, SQLINTEGER *strlen)
04543 {
04544     return SQL_ERROR;
04545 }
04546 #endif
04547 
04548 #ifdef WINTERFACE
04549 
04553 SQLRETURN SQL_API
04554 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
04555                  SQLSMALLINT fieldid, SQLPOINTER value,
04556                  SQLINTEGER buflen, SQLINTEGER *strlen)
04557 {
04558     return SQL_ERROR;
04559 }
04560 #endif
04561 
04562 #ifndef WINTERFACE
04563 
04567 SQLRETURN SQL_API
04568 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
04569                 SQLSMALLINT fieldid, SQLPOINTER value,
04570                 SQLINTEGER buflen)
04571 {
04572     return SQL_ERROR;
04573 }
04574 #endif
04575 
04576 #ifdef WINTERFACE
04577 
04581 SQLRETURN SQL_API
04582 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
04583                  SQLSMALLINT fieldid, SQLPOINTER value,
04584                  SQLINTEGER buflen)
04585 {
04586     return SQL_ERROR;
04587 }
04588 #endif
04589 
04590 #ifndef WINTERFACE
04591 
04595 SQLRETURN SQL_API
04596 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
04597               SQLCHAR *name, SQLSMALLINT buflen,
04598               SQLSMALLINT *strlen, SQLSMALLINT *type,
04599               SQLSMALLINT *subtype, SQLLEN *len,
04600               SQLSMALLINT *prec, SQLSMALLINT *scale,
04601               SQLSMALLINT *nullable)
04602 {
04603     return SQL_ERROR;
04604 }
04605 #endif
04606 
04607 #ifdef WINTERFACE
04608 
04612 SQLRETURN SQL_API
04613 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
04614                SQLWCHAR *name, SQLSMALLINT buflen,
04615                SQLSMALLINT *strlen, SQLSMALLINT *type,
04616                SQLSMALLINT *subtype, SQLLEN *len,
04617                SQLSMALLINT *prec, SQLSMALLINT *scale,
04618                SQLSMALLINT *nullable)
04619 {
04620     return SQL_ERROR;
04621 }
04622 #endif
04623 
04628 SQLRETURN SQL_API
04629 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
04630               SQLSMALLINT type, SQLSMALLINT subtype,
04631               SQLLEN len, SQLSMALLINT prec,
04632               SQLSMALLINT scale, SQLPOINTER data,
04633               SQLLEN *strlen, SQLLEN *indicator)
04634 {
04635     return SQL_ERROR;
04636 }
04637 
04649 static SQLRETURN
04650 mkresultset(HSTMT stmt, COL *colspec, int ncols, COL *colspec3,
04651             int ncols3, int *nret)
04652 {
04653     STMT *s;
04654     DBC *d;
04655 
04656     if (stmt == SQL_NULL_HSTMT) {
04657         return SQL_INVALID_HANDLE;
04658     }
04659     s = (STMT *) stmt;
04660     if (s->dbc == SQL_NULL_HDBC) {
04661 noconn:
04662         return noconn(s);
04663     }
04664     d = (DBC *) s->dbc;
04665     if (!d->sqlite) {
04666         goto noconn;
04667     }
04668     s3stmt_end_if(s);
04669     freeresult(s, 0);
04670     if (colspec3 && *s->ov3) {
04671         s->ncols = ncols3;
04672         s->cols = colspec3;
04673     } else {
04674         s->ncols = ncols;
04675         s->cols = colspec;
04676     }
04677     mkbindcols(s, s->ncols);
04678     s->nowchar[1] = 1;
04679     s->nrows = 0;
04680     s->rowp = -1;
04681     s->isselect = -1;
04682     if (nret) {
04683         *nret = s->ncols;
04684     }
04685     return SQL_SUCCESS;
04686 }
04687 
04692 static COL tablePrivSpec2[] = {
04693     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
04694     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
04695     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
04696     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
04697     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
04698     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
04699     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
04700 };
04701 
04702 static COL tablePrivSpec3[] = {
04703     { "SYSTEM", "TABLEPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
04704     { "SYSTEM", "TABLEPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
04705     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
04706     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
04707     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
04708     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
04709     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
04710 };
04711 
04712 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC)
04713 
04725 SQLRETURN SQL_API
04726 SQLTablePrivileges(SQLHSTMT stmt,
04727                    SQLCHAR *catalog, SQLSMALLINT catalogLen,
04728                    SQLCHAR *schema, SQLSMALLINT schemaLen,
04729                    SQLCHAR *table, SQLSMALLINT tableLen)
04730 {
04731     SQLRETURN ret;
04732 
04733     HSTMT_LOCK(stmt);
04734     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
04735                       tablePrivSpec3, array_size(tablePrivSpec3), NULL);
04736     HSTMT_UNLOCK(stmt);
04737     return ret;
04738 }
04739 #endif
04740 
04741 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
04742 #ifdef WINTERFACE
04743 
04755 SQLRETURN SQL_API
04756 SQLTablePrivilegesW(SQLHSTMT stmt,
04757                     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
04758                     SQLWCHAR *schema, SQLSMALLINT schemaLen,
04759                     SQLWCHAR *table, SQLSMALLINT tableLen)
04760 {
04761     SQLRETURN ret;
04762 
04763     HSTMT_LOCK(stmt);
04764     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
04765                       tablePrivSpec3, array_size(tablePrivSpec3), NULL);
04766     HSTMT_UNLOCK(stmt);
04767     return ret;
04768 }
04769 #endif
04770 #endif
04771 
04776 static COL colPrivSpec2[] = {
04777     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
04778     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
04779     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
04780     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
04781     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
04782     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
04783     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
04784 };
04785 
04786 static COL colPrivSpec3[] = {
04787     { "SYSTEM", "COLPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
04788     { "SYSTEM", "COLPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
04789     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
04790     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
04791     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
04792     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
04793     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
04794 };
04795 
04796 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC)
04797 
04811 SQLRETURN SQL_API
04812 SQLColumnPrivileges(SQLHSTMT stmt,
04813                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
04814                     SQLCHAR *schema, SQLSMALLINT schemaLen,
04815                     SQLCHAR *table, SQLSMALLINT tableLen,
04816                     SQLCHAR *column, SQLSMALLINT columnLen)
04817 {
04818     SQLRETURN ret;
04819 
04820     HSTMT_LOCK(stmt);
04821     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
04822                       colPrivSpec3, array_size(colPrivSpec3), NULL);
04823     HSTMT_UNLOCK(stmt);
04824     return ret;
04825 }
04826 #endif
04827 
04828 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
04829 #ifdef WINTERFACE
04830 
04844 SQLRETURN SQL_API
04845 SQLColumnPrivilegesW(SQLHSTMT stmt,
04846                      SQLWCHAR *catalog, SQLSMALLINT catalogLen,
04847                      SQLWCHAR *schema, SQLSMALLINT schemaLen,
04848                      SQLWCHAR *table, SQLSMALLINT tableLen,
04849                      SQLWCHAR *column, SQLSMALLINT columnLen)
04850 {
04851     SQLRETURN ret;
04852 
04853     HSTMT_LOCK(stmt);
04854     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
04855                       colPrivSpec3, array_size(colPrivSpec3), NULL);
04856     HSTMT_UNLOCK(stmt);
04857     return ret;
04858 }
04859 #endif
04860 #endif
04861 
04866 static COL pkeySpec2[] = {
04867     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
04868     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
04869     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
04870     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
04871     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
04872     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
04873 };
04874 
04875 static COL pkeySpec3[] = {
04876     { "SYSTEM", "PRIMARYKEY", "TABLE_CAT", SCOL_VARCHAR, 50 },
04877     { "SYSTEM", "PRIMARYKEY", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
04878     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
04879     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
04880     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
04881     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
04882 };
04883 
04896 static SQLRETURN
04897 drvprimarykeys(SQLHSTMT stmt,
04898                SQLCHAR *cat, SQLSMALLINT catLen,
04899                SQLCHAR *schema, SQLSMALLINT schemaLen,
04900                SQLCHAR *table, SQLSMALLINT tableLen)
04901 {
04902     STMT *s;
04903     DBC *d;
04904     SQLRETURN sret;
04905     int i, asize, ret, nrows, ncols, nrows2 = 0, ncols2 = 0;
04906     int namec = -1, uniquec = -1, namec2 = -1, uniquec2 = -1, offs, seq = 1;
04907     PTRDIFF_T size;
04908     char **rowp = NULL, **rowp2 = NULL, *errp = NULL, *sql, tname[512];
04909 
04910     sret = mkresultset(stmt, pkeySpec2, array_size(pkeySpec2),
04911                        pkeySpec3, array_size(pkeySpec3), &asize);
04912     if (sret != SQL_SUCCESS) {
04913         return sret;
04914     }
04915     s = (STMT *) stmt;
04916     d = (DBC *) s->dbc;
04917     if (!table || table[0] == '\0' || table[0] == '%') {
04918         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
04919         return SQL_ERROR;
04920     }
04921     if (tableLen == SQL_NTS) {
04922         size = sizeof (tname) - 1;
04923     } else {
04924         size = min(sizeof (tname) - 1, tableLen);
04925     }
04926     strncpy(tname, (char *) table, size);
04927     tname[size] = '\0';
04928     unescpat(tname);
04929     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
04930     if (!sql) {
04931         return nomem(s);
04932     }
04933     sret = starttran(s);
04934     if (sret != SQL_SUCCESS) {
04935         sqlite3_free(sql);
04936         return sret;
04937     }
04938     dbtraceapi(d, "sqlite3_get_table", sql);
04939     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
04940     sqlite3_free(sql);
04941     if (ret != SQLITE_OK) {
04942         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04943                 errp ? errp : "unknown error", ret);
04944         if (errp) {
04945             sqlite3_free(errp);
04946             errp = NULL;
04947         }
04948         return SQL_ERROR;
04949     }
04950     if (errp) {
04951         sqlite3_free(errp);
04952         errp = NULL;
04953     }
04954     size = 0;
04955     if (ncols * nrows > 0) {
04956         int typec;
04957 
04958         namec = findcol(rowp, ncols, "name");
04959         uniquec = findcol(rowp, ncols, "pk");
04960         typec = findcol(rowp, ncols, "type");
04961         if (namec >= 0 && uniquec >= 0 && typec >= 0) {
04962             for (i = 1; i <= nrows; i++) {
04963                 if (*rowp[i * ncols + uniquec] != '0') {
04964                     size++;
04965                 }
04966             }
04967         }
04968     }
04969     if (size == 0) {
04970         sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
04971         if (!sql) {
04972             sqlite3_free_table(rowp);
04973             return nomem(s);
04974         }
04975         dbtraceapi(d, "sqlite3_get_table", sql);
04976         ret = sqlite3_get_table(d->sqlite, sql, &rowp2, &nrows2, &ncols2,
04977                                 &errp);
04978         sqlite3_free(sql);
04979         if (ret != SQLITE_OK) {
04980             sqlite3_free_table(rowp);
04981             sqlite3_free_table(rowp2);
04982             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04983                     errp ? errp : "unknown error", ret);
04984             if (errp) {
04985                 sqlite3_free(errp);
04986                 errp = NULL;
04987             }
04988             return SQL_ERROR;
04989         }
04990         if (errp) {
04991             sqlite3_free(errp);
04992             errp = NULL;
04993         }
04994     }
04995     if (ncols2 * nrows2 > 0) {
04996         namec2 = findcol(rowp2, ncols2, "name");
04997         uniquec2 = findcol(rowp2, ncols2, "unique");
04998         if (namec2 >= 0 && uniquec2 >=  0) {
04999             for (i = 1; i <= nrows2; i++) {
05000                 int nnrows, nncols, nlen = 0;
05001                 char **rowpp;
05002 
05003                 if (rowp2[i * ncols2 + namec2]) {
05004                     nlen = strlen(rowp2[i * ncols2 + namec2]);
05005                 }
05006                 if (nlen < 17 ||
05007                     strncmp(rowp2[i * ncols2 + namec2],
05008                             "sqlite_autoindex_", 17)) {
05009                     continue;
05010                 }
05011                 if (*rowp2[i * ncols2 + uniquec2] != '0') {
05012                     ret = SQLITE_ERROR;
05013                     sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
05014                                           rowp2[i * ncols2 + namec2]);
05015                     if (sql) {
05016                         dbtraceapi(d, "sqlite3_get_table", sql);
05017                         ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
05018                                                 &nnrows, &nncols, NULL);
05019                         sqlite3_free(sql);
05020                     }
05021                     if (ret == SQLITE_OK) {
05022                         size += nnrows;
05023                         sqlite3_free_table(rowpp);
05024                     }
05025                 }
05026             }
05027         }
05028     }
05029     if (size == 0) {
05030         sqlite3_free_table(rowp);
05031         sqlite3_free_table(rowp2);
05032         return SQL_SUCCESS;
05033     }
05034     s->nrows = size;
05035     size = (size + 1) * asize;
05036     s->rows = xmalloc((size + 1) * sizeof (char *));
05037     if (!s->rows) {
05038         s->nrows = 0;
05039         sqlite3_free_table(rowp);
05040         sqlite3_free_table(rowp2);
05041         return nomem(s);
05042     }
05043     s->rows[0] = (char *) size;
05044     s->rows += 1;
05045     memset(s->rows, 0, sizeof (char *) * size);
05046     s->rowfree = freerows;
05047     offs = s->ncols;
05048     if (rowp) {
05049         for (i = 1; i <= nrows; i++) {
05050             if (*rowp[i * ncols + uniquec] != '0') {
05051                 char buf[32];
05052 
05053                 s->rows[offs + 0] = xstrdup("");
05054 #if defined(_WIN32) || defined(_WIN64)
05055                 s->rows[offs + 1] = xstrdup(d->xcelqrx ? "main" : "");
05056 #else
05057                 s->rows[offs + 1] = xstrdup("");
05058 #endif
05059                 s->rows[offs + 2] = xstrdup(tname);
05060                 s->rows[offs + 3] = xstrdup(rowp[i * ncols + namec]);
05061                 sprintf(buf, "%d", seq++);
05062                 s->rows[offs + 4] = xstrdup(buf);
05063                 offs += s->ncols;
05064             }
05065         }
05066     }
05067     if (rowp2) {
05068         for (i = 1; i <= nrows2; i++) {
05069             int nnrows, nncols, nlen = 0;
05070             char **rowpp;
05071 
05072             if (rowp2[i * ncols2 + namec2]) {
05073                 nlen = strlen(rowp2[i * ncols2 + namec2]);
05074             }
05075             if (nlen < 17 ||
05076                 strncmp(rowp2[i * ncols2 + namec2], "sqlite_autoindex_", 17)) {
05077                 continue;
05078             }
05079             if (*rowp2[i * ncols2 + uniquec2] != '0') {
05080                 int k;
05081 
05082                 ret = SQLITE_ERROR;
05083                 sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
05084                                       rowp2[i * ncols2 + namec2]);
05085                 if (sql) {
05086                     dbtraceapi(d, "sqlite3_get_table", sql);
05087                     ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
05088                                             &nnrows, &nncols, NULL);
05089                     sqlite3_free(sql);
05090                 }
05091                 if (ret != SQLITE_OK) {
05092                     continue;
05093                 }
05094                 for (k = 0; nnrows && k < nncols; k++) {
05095                     if (strcmp(rowpp[k], "name") == 0) {
05096                         int m;
05097 
05098                         for (m = 1; m <= nnrows; m++) {
05099                             int roffs = offs + (m - 1) * s->ncols;
05100 
05101                             s->rows[roffs + 0] = xstrdup("");
05102 #if defined(_WIN32) || defined(_WIN64)
05103                             s->rows[roffs + 1] = 
05104                                 xstrdup(d->xcelqrx ? "main" : "");
05105 #else
05106                             s->rows[roffs + 1] = xstrdup("");
05107 #endif
05108                             s->rows[roffs + 2] = xstrdup(tname);
05109                             s->rows[roffs + 3] =
05110                                 xstrdup(rowpp[m * nncols + k]);
05111                             s->rows[roffs + 5] =
05112                                 xstrdup(rowp2[i * ncols2 + namec2]);
05113                         }
05114                     } else if (strcmp(rowpp[k], "seqno") == 0) {
05115                         int m;
05116 
05117                         for (m = 1; m <= nnrows; m++) {
05118                             int roffs = offs + (m - 1) * s->ncols;
05119                             int pos = m - 1;
05120                             char buf[32];
05121 
05122                             sscanf(rowpp[m * nncols + k], "%d", &pos);
05123                             sprintf(buf, "%d", pos + 1);
05124                             s->rows[roffs + 4] = xstrdup(buf);
05125                         }
05126                     }
05127                 }
05128                 offs += nnrows * s->ncols;
05129                 sqlite3_free_table(rowpp);
05130             }
05131         }
05132     }
05133     sqlite3_free_table(rowp);
05134     sqlite3_free_table(rowp2);
05135     return SQL_SUCCESS;
05136 }
05137 
05138 #ifndef WINTERFACE
05139 
05151 SQLRETURN SQL_API
05152 SQLPrimaryKeys(SQLHSTMT stmt,
05153                SQLCHAR *cat, SQLSMALLINT catLen,
05154                SQLCHAR *schema, SQLSMALLINT schemaLen,
05155                SQLCHAR *table, SQLSMALLINT tableLen)
05156 {
05157     SQLRETURN ret;
05158 
05159     HSTMT_LOCK(stmt);
05160     ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
05161                          table, tableLen);
05162     HSTMT_UNLOCK(stmt);
05163     return ret;
05164 }
05165 #endif
05166 
05167 #ifdef WINTERFACE
05168 
05180 SQLRETURN SQL_API
05181 SQLPrimaryKeysW(SQLHSTMT stmt,
05182                 SQLWCHAR *cat, SQLSMALLINT catLen,
05183                 SQLWCHAR *schema, SQLSMALLINT schemaLen,
05184                 SQLWCHAR *table, SQLSMALLINT tableLen)
05185 {
05186     char *c = NULL, *s = NULL, *t = NULL;
05187     SQLRETURN ret;
05188 
05189     HSTMT_LOCK(stmt);
05190     if (cat) {
05191         c = uc_to_utf_c(cat, catLen);
05192         if (!c) {
05193             ret = nomem((STMT *) stmt);
05194             goto done;
05195         }
05196     }
05197     if (schema) {
05198         s = uc_to_utf_c(schema, schemaLen);
05199         if (!s) {
05200             ret = nomem((STMT *) stmt);
05201             goto done;
05202         }
05203     }
05204     if (table) {
05205         t = uc_to_utf_c(table, tableLen);
05206         if (!t) {
05207             ret = nomem((STMT *) stmt);
05208             goto done;
05209         }
05210     }
05211     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
05212                          (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
05213 done:
05214     HSTMT_UNLOCK(stmt);
05215     uc_free(t);
05216     uc_free(s);
05217     uc_free(c);
05218     return ret;
05219 }
05220 #endif
05221 
05226 static COL scolSpec2[] = {
05227     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
05228     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
05229     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
05230     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
05231     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
05232     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
05233     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
05234     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
05235     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
05236 };
05237 
05238 static COL scolSpec3[] = {
05239     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
05240     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
05241     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
05242     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
05243     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
05244     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
05245     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
05246     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
05247     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
05248 };
05249 
05265 static SQLRETURN
05266 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
05267                   SQLCHAR *cat, SQLSMALLINT catLen,
05268                   SQLCHAR *schema, SQLSMALLINT schemaLen,
05269                   SQLCHAR *table, SQLSMALLINT tableLen,
05270                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
05271 {
05272     STMT *s;
05273     DBC *d;
05274     SQLRETURN sret;
05275     int i, asize, ret, nrows, ncols, nnnrows, nnncols, offs;
05276     PTRDIFF_T size;
05277     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
05278     int notnullcc = -1, mkrowid = 0;
05279     char *errp = NULL, *sql, tname[512];
05280     char **rowp = NULL, **rowppp = NULL;
05281 
05282     sret = mkresultset(stmt, scolSpec2, array_size(scolSpec2),
05283                        scolSpec3, array_size(scolSpec3), &asize);
05284     if (sret != SQL_SUCCESS) {
05285         return sret;
05286     }
05287     s = (STMT *) stmt;
05288     d = (DBC *) s->dbc;
05289     if (!table || table[0] == '\0' || table[0] == '%') {
05290         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
05291         return SQL_ERROR;
05292     }
05293     if (tableLen == SQL_NTS) {
05294         size = sizeof (tname) - 1;
05295     } else {
05296         size = min(sizeof (tname) - 1, tableLen);
05297     }
05298     strncpy(tname, (char *) table, size);
05299     tname[size] = '\0';
05300     unescpat(tname);
05301     if (id != SQL_BEST_ROWID) {
05302         return SQL_SUCCESS;
05303     }
05304     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
05305     if (!sql) {
05306         return nomem(s);
05307     }
05308     sret = starttran(s);
05309     if (sret != SQL_SUCCESS) {
05310         sqlite3_free(sql);
05311         return sret;
05312     }
05313     dbtraceapi(d, "sqlite3_get_table", sql);
05314     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
05315     sqlite3_free(sql);
05316     if (ret != SQLITE_OK) {
05317 doerr:
05318         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
05319                 errp ? errp : "unknown error", ret);
05320         if (errp) {
05321             sqlite3_free(errp);
05322             errp = NULL;
05323         }
05324         return SQL_ERROR;       
05325     }
05326     if (errp) {
05327         sqlite3_free(errp);
05328         errp = NULL;
05329     }
05330     size = 0; /* number result rows */
05331     if (ncols * nrows <= 0) {
05332         goto nodata_but_rowid;
05333     }
05334     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
05335     if (!sql) {
05336         return nomem(s);
05337     }
05338     dbtraceapi(d, "sqlite3_get_table", sql);
05339     ret = sqlite3_get_table(d->sqlite, sql, &rowppp, &nnnrows, &nnncols,
05340                             &errp);
05341     sqlite3_free(sql);
05342     if (ret != SQLITE_OK) {
05343         sqlite3_free_table(rowp);
05344         goto doerr;
05345     }
05346     if (errp) {
05347         sqlite3_free(errp);
05348         errp = NULL;
05349     }
05350     namec = findcol(rowp, ncols, "name");
05351     uniquec = findcol(rowp, ncols, "unique");
05352     if (namec < 0 || uniquec < 0) {
05353         goto nodata_but_rowid;
05354     }
05355     namecc = findcol(rowppp, nnncols, "name");
05356     typecc = findcol(rowppp, nnncols, "type");
05357     notnullcc = findcol(rowppp, nnncols, "notnull");
05358     for (i = 1; i <= nrows; i++) {
05359         int nnrows, nncols;
05360         char **rowpp = NULL;
05361 
05362         if (*rowp[i * ncols + uniquec] != '0') {
05363             ret = SQLITE_ERROR;
05364             sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
05365                                   rowp[i * ncols + namec]);
05366             if (sql) {
05367                 dbtraceapi(d, "sqlite3_get_table", sql);
05368                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
05369                                         &nnrows, &nncols, NULL);
05370                 sqlite3_free(sql);
05371             }
05372             if (ret == SQLITE_OK) {
05373                 size += nnrows;
05374                 sqlite3_free_table(rowpp);
05375             }
05376         }
05377     }
05378 nodata_but_rowid:
05379     if (size == 0) {
05380         size = 1;
05381         mkrowid = 1;
05382     }
05383     s->nrows = size;
05384     size = (size + 1) * asize;
05385     s->rows = xmalloc((size + 1) * sizeof (char *));
05386     if (!s->rows) {
05387         s->nrows = 0;
05388         sqlite3_free_table(rowp);
05389         sqlite3_free_table(rowppp);
05390         return nomem(s);
05391     }
05392     s->rows[0] = (char *) size;
05393     s->rows += 1;
05394     memset(s->rows, 0, sizeof (char *) * size);
05395     s->rowfree = freerows;
05396     if (mkrowid) {
05397         s->nrows = 0;
05398         goto mkrowid;
05399     }
05400     offs = 0;
05401     for (i = 1; i <= nrows; i++) {
05402         int nnrows, nncols;
05403         char **rowpp = NULL;
05404 
05405         if (*rowp[i * ncols + uniquec] != '0') {
05406             int k;
05407 
05408             ret = SQLITE_ERROR;
05409             sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
05410                                   rowp[i * ncols + namec]);
05411             if (sql) {
05412                 dbtraceapi(d, "sqlite3_get_table", sql);
05413                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
05414                                         &nnrows, &nncols, NULL);
05415                 sqlite3_free(sql);
05416             }
05417             if (ret != SQLITE_OK) {
05418                 continue;
05419             }
05420             for (k = 0; nnrows && k < nncols; k++) {
05421                 if (strcmp(rowpp[k], "name") == 0) {
05422                     int m;
05423 
05424                     for (m = 1; m <= nnrows; m++) {
05425                         int roffs = (offs + m) * s->ncols;
05426 
05427                         s->rows[roffs + 0] =
05428                             xstrdup(stringify(SQL_SCOPE_SESSION));
05429                         s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
05430                         s->rows[roffs + 4] = xstrdup("0");
05431                         s->rows[roffs + 7] =
05432                             xstrdup(stringify(SQL_PC_NOT_PSEUDO));
05433                         if (namecc >= 0 && typecc >= 0) {
05434                             int ii;
05435 
05436                             for (ii = 1; ii <= nnnrows; ii++) {
05437                                 if (strcmp(rowppp[ii * nnncols + namecc],
05438                                            rowpp[m * nncols + k]) == 0) {
05439                                     char *typen = rowppp[ii * nnncols + typecc];
05440                                     int sqltype, mm, dd, isnullable = 0;
05441                                     char buf[32];
05442                                         
05443                                     s->rows[roffs + 3] = xstrdup(typen);
05444                                     sqltype = mapsqltype(typen, NULL, *s->ov3,
05445                                                          s->nowchar[0]);
05446                                     getmd(typen, sqltype, &mm, &dd);
05447 #ifdef SQL_LONGVARCHAR
05448                                     if (sqltype == SQL_VARCHAR && mm > 255) {
05449                                         sqltype = SQL_LONGVARCHAR;
05450                                     }
05451 #endif
05452 #ifdef WINTERFACE
05453 #ifdef SQL_WLONGVARCHAR
05454                                     if (sqltype == SQL_WVARCHAR && mm > 255) {
05455                                         sqltype = SQL_WLONGVARCHAR;
05456                                     }
05457 #endif
05458 #endif
05459                                     if (sqltype == SQL_VARBINARY && mm > 255) {
05460                                         sqltype = SQL_LONGVARBINARY;
05461                                     }
05462                                     sprintf(buf, "%d", sqltype);
05463                                     s->rows[roffs + 2] = xstrdup(buf);
05464                                     sprintf(buf, "%d", mm);
05465                                     s->rows[roffs + 5] = xstrdup(buf);
05466                                     sprintf(buf, "%d", dd);
05467                                     s->rows[roffs + 6] = xstrdup(buf);
05468                                     if (notnullcc >= 0) {
05469                                         char *inp =
05470                                            rowppp[ii * nnncols + notnullcc];
05471 
05472                                         isnullable = inp[0] != '0';
05473                                     }
05474                                     sprintf(buf, "%d", isnullable);
05475                                     s->rows[roffs + 8] = xstrdup(buf);
05476                                 }
05477                             }
05478                         }
05479                     }
05480                 }
05481             }
05482             offs += nnrows;
05483             sqlite3_free_table(rowpp);
05484         }
05485     }
05486     if (nullable == SQL_NO_NULLS) {
05487         for (i = 1; i < s->nrows; i++) {
05488             if (s->rows[i * s->ncols + 8][0] == '0') {
05489                 int m, i1 = i + 1;
05490 
05491                 for (m = 0; m < s->ncols; m++) {
05492                     freep(&s->rows[i * s->ncols + m]);
05493                 }
05494                 size = s->ncols * sizeof (char *) * (s->nrows - i1);
05495                 if (size > 0) {
05496                     memmove(s->rows + i * s->ncols,
05497                             s->rows + i1 * s->ncols,
05498                             size);
05499                     memset(s->rows + s->nrows * s->ncols, 0,
05500                            s->ncols * sizeof (char *));
05501                 }
05502                 s->nrows--;
05503                 --i;
05504             }
05505         }
05506     }
05507 mkrowid:
05508     sqlite3_free_table(rowp);
05509     sqlite3_free_table(rowppp);
05510     if (s->nrows == 0) {
05511         s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
05512         s->rows[s->ncols + 1] = xstrdup("_ROWID_");
05513         s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
05514         s->rows[s->ncols + 3] = xstrdup("integer");
05515         s->rows[s->ncols + 4] = xstrdup("0");
05516         s->rows[s->ncols + 5] = xstrdup("10");
05517         s->rows[s->ncols + 6] = xstrdup("9");
05518         s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
05519         s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
05520         s->nrows = 1;
05521     }
05522     return SQL_SUCCESS;
05523 }
05524 
05525 #ifndef WINTERFACE
05526 
05541 SQLRETURN SQL_API
05542 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
05543                   SQLCHAR *cat, SQLSMALLINT catLen,
05544                   SQLCHAR *schema, SQLSMALLINT schemaLen,
05545                   SQLCHAR *table, SQLSMALLINT tableLen,
05546                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
05547 {
05548     SQLRETURN ret;
05549 
05550     HSTMT_LOCK(stmt);
05551     ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
05552                             table, tableLen, scope, nullable);
05553     HSTMT_UNLOCK(stmt);
05554     return ret;
05555 }
05556 #endif
05557 
05558 #ifdef WINTERFACE
05559 
05574 SQLRETURN SQL_API
05575 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
05576                    SQLWCHAR *cat, SQLSMALLINT catLen,
05577                    SQLWCHAR *schema, SQLSMALLINT schemaLen,
05578                    SQLWCHAR *table, SQLSMALLINT tableLen,
05579                    SQLUSMALLINT scope, SQLUSMALLINT nullable)
05580 {
05581     char *c = NULL, *s = NULL, *t = NULL;
05582     SQLRETURN ret;
05583 
05584     HSTMT_LOCK(stmt);
05585     if (cat) {
05586         c = uc_to_utf_c(cat, catLen);
05587         if (!c) {
05588             ret = nomem((STMT *) stmt);
05589             goto done;
05590         }
05591     }
05592     if (schema) {
05593         s = uc_to_utf_c(schema, schemaLen);
05594         if (!s) {
05595             ret = nomem((STMT *) stmt);
05596             goto done;
05597         }
05598     }
05599     if (table) {
05600         t = uc_to_utf_c(table, tableLen);
05601         if (!t) {
05602             ret = nomem((STMT *) stmt);
05603             goto done;
05604         }
05605     }
05606     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
05607                             (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
05608                             scope, nullable);
05609 done:
05610     HSTMT_UNLOCK(stmt);
05611     uc_free(t);
05612     uc_free(s);
05613     uc_free(c);
05614     return ret;
05615 }
05616 #endif
05617 
05622 static COL fkeySpec2[] = {
05623     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
05624     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
05625     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
05626     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
05627     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
05628     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
05629     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
05630     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
05631     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
05632     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
05633     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
05634     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
05635     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
05636     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
05637 };
05638 
05639 static COL fkeySpec3[] = {
05640     { "SYSTEM", "FOREIGNKEY", "PKTABLE_CAT", SCOL_VARCHAR, 50 },
05641     { "SYSTEM", "FOREIGNKEY", "PKTABLE_SCHEM", SCOL_VARCHAR, 50 },
05642     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
05643     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
05644     { "SYSTEM", "FOREIGNKEY", "FKTABLE_CAT", SCOL_VARCHAR, 50 },
05645     { "SYSTEM", "FOREIGNKEY", "FKTABLE_SCHEM", SCOL_VARCHAR, 50 },
05646     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
05647     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
05648     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
05649     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
05650     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
05651     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
05652     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
05653     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
05654 };
05655 
05674 static SQLRETURN SQL_API
05675 drvforeignkeys(SQLHSTMT stmt,
05676                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
05677                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
05678                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
05679                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
05680                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
05681                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
05682 {
05683     STMT *s;
05684     DBC *d;
05685     SQLRETURN sret;
05686     int i, asize, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
05687     PTRDIFF_T size;
05688     char **rowp, *errp = NULL, *sql, pname[512], fname[512];
05689 
05690     sret = mkresultset(stmt, fkeySpec2, array_size(fkeySpec2),
05691                        fkeySpec3, array_size(fkeySpec3), &asize);
05692     if (sret != SQL_SUCCESS) {
05693         return sret;
05694     }
05695     s = (STMT *) stmt;
05696     sret = starttran(s);
05697     if (sret != SQL_SUCCESS) {
05698         return sret;
05699     }
05700     d = (DBC *) s->dbc;
05701     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
05702         (!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
05703         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
05704         return SQL_ERROR;
05705     }
05706     size = 0;
05707     if (PKtable) {
05708         if (PKtableLen == SQL_NTS) {
05709             size = sizeof (pname) - 1;
05710         } else {
05711             size = min(sizeof (pname) - 1, PKtableLen);
05712         }
05713         strncpy(pname, (char *) PKtable, size);
05714     }
05715     pname[size] = '\0';
05716     size = 0;
05717     if (FKtable) {
05718 
05719         if (FKtableLen == SQL_NTS) {
05720             size = sizeof (fname) - 1;
05721         } else {
05722             size = min(sizeof (fname) - 1, FKtableLen);
05723         }
05724         strncpy(fname, (char *) FKtable, size);
05725     }
05726     fname[size] = '\0';
05727     if (fname[0] != '\0') {
05728         int plen;
05729 
05730         ret = SQLITE_ERROR;
05731         sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", fname);
05732         if (sql) {
05733             dbtraceapi(d, "sqlite3_get_table", sql);
05734             ret = sqlite3_get_table(d->sqlite, sql, &rowp,
05735                                     &nrows, &ncols, &errp);
05736             sqlite3_free(sql);
05737         }
05738         if (ret != SQLITE_OK) {
05739             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
05740                     errp ? errp : "unknown error", ret);
05741             if (errp) {
05742                 sqlite3_free(errp);
05743                 errp = NULL;
05744             }
05745             return SQL_ERROR;
05746         }
05747         if (errp) {
05748             sqlite3_free(errp);
05749             errp = NULL;
05750         }
05751         if (ncols * nrows <= 0) {
05752 nodata:
05753             sqlite3_free_table(rowp);
05754             return SQL_SUCCESS;
05755         }
05756         size = 0;
05757         namec = findcol(rowp, ncols, "table");
05758         seqc = findcol(rowp, ncols, "seq");
05759         fromc = findcol(rowp, ncols, "from");
05760         toc = findcol(rowp, ncols, "to");
05761         if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
05762             goto nodata;
05763         }
05764         plen = strlen(pname);
05765         for (i = 1; i <= nrows; i++) {
05766             char *ptab = unquote(rowp[i * ncols + namec]);
05767 
05768             if (plen && ptab) {
05769                 int len = strlen(ptab);
05770 
05771                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
05772                     continue;
05773                 }
05774             }
05775             size++;
05776         }
05777         if (size == 0) {
05778             goto nodata;
05779         }
05780         s->nrows = size;
05781         size = (size + 1) * asize;
05782         s->rows = xmalloc((size + 1) * sizeof (char *));
05783         if (!s->rows) {
05784             s->nrows = 0;
05785             return nomem(s);
05786         }
05787         s->rows[0] = (char *) size;
05788         s->rows += 1;
05789         memset(s->rows, 0, sizeof (char *) * size);
05790         s->rowfree = freerows;
05791         offs = 0;
05792         for (i = 1; i <= nrows; i++) {
05793             int pos = 0, roffs = (offs + 1) * s->ncols;
05794             char *ptab = rowp[i * ncols + namec];
05795             char buf[32];
05796 
05797             if (plen && ptab) {
05798                 int len = strlen(ptab);
05799 
05800                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
05801                     continue;
05802                 }
05803             }
05804             s->rows[roffs + 0] = xstrdup("");
05805 #if defined(_WIN32) || defined(_WIN64)
05806             s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
05807 #else
05808             s->rows[roffs + 1] = xstrdup("");
05809 #endif
05810             s->rows[roffs + 2] = xstrdup(ptab);
05811             s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
05812             s->rows[roffs + 4] = xstrdup("");
05813             s->rows[roffs + 5] = xstrdup("");
05814             s->rows[roffs + 6] = xstrdup(fname);
05815             s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
05816             sscanf(rowp[i * ncols + seqc], "%d", &pos);
05817             sprintf(buf, "%d", pos + 1);
05818             s->rows[roffs + 8] = xstrdup(buf);
05819             s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
05820             s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
05821             s->rows[roffs + 11] = NULL;
05822             s->rows[roffs + 12] = NULL;
05823             s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
05824             offs++;
05825         }
05826         sqlite3_free_table(rowp);
05827     } else {
05828         int nnrows, nncols, plen = strlen(pname);
05829         char **rowpp;
05830 
05831         sql = "select name from sqlite_master where type='table'";
05832         dbtraceapi(d, "sqlite3_get_table", sql);
05833         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
05834         if (ret != SQLITE_OK) {
05835             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
05836                     errp ? errp : "unknown error", ret);
05837             if (errp) {
05838                 sqlite3_free(errp);
05839                 errp = NULL;
05840             }
05841             return SQL_ERROR;
05842         }
05843         if (errp) {
05844             sqlite3_free(errp);
05845             errp = NULL;
05846         }
05847         if (ncols * nrows <= 0) {
05848             goto nodata;
05849         }
05850         size = 0;
05851         for (i = 1; i <= nrows; i++) {
05852             int k, len;
05853 
05854             if (!rowp[i]) {
05855                 continue;
05856             }
05857             len = strlen(rowp[i]);
05858             if (len == plen && strncasecmp(pname, rowp[i], plen) == 0) {
05859                 continue;
05860             }
05861             rowpp = NULL;
05862             ret = SQLITE_ERROR;
05863             sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
05864             if (sql) {
05865                 dbtraceapi(d, "sqlite3_get_table", sql);
05866                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
05867                                       &nnrows, &nncols, NULL);
05868                 sqlite3_free(sql);
05869             }
05870             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
05871                 sqlite3_free_table(rowpp);
05872                 continue;
05873             }
05874             namec = findcol(rowpp, nncols, "table");
05875             seqc = findcol(rowpp, nncols, "seq");
05876             fromc = findcol(rowpp, nncols, "from");
05877             toc = findcol(rowpp, nncols, "to");
05878             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
05879                 sqlite3_free_table(rowpp);
05880                 continue;
05881             }
05882             for (k = 1; k <= nnrows; k++) {
05883                 char *ptab = unquote(rowpp[k * nncols + namec]);
05884 
05885                 if (plen && ptab) {
05886                     len = strlen(ptab);
05887                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
05888                         continue;
05889                     }
05890                 }
05891                 size++;
05892             }
05893             sqlite3_free_table(rowpp);
05894         }
05895         if (size == 0) {
05896             goto nodata;
05897         }
05898         s->nrows = size;
05899         size = (size + 1) * asize;
05900         s->rows = xmalloc((size + 1) * sizeof (char *));
05901         if (!s->rows) {
05902             s->nrows = 0;
05903             return nomem(s);
05904         }
05905         s->rows[0] = (char *) size;
05906         s->rows += 1;
05907         memset(s->rows, 0, sizeof (char *) * size);
05908         s->rowfree = freerows;
05909         offs = 0;
05910         for (i = 1; i <= nrows; i++) {
05911             int k, len;
05912 
05913             if (!rowp[i]) {
05914                 continue;
05915             }
05916             len = strlen(rowp[i]);
05917             if (len == plen && strncasecmp(pname, rowp[i], plen) == 0) {
05918                 continue;
05919             }
05920             rowpp = NULL;
05921             ret = SQLITE_ERROR;
05922             sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
05923             if (sql) {
05924                 dbtraceapi(d, "sqlite3_get_table", sql);
05925                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
05926                                         &nnrows, &nncols, NULL);
05927                 sqlite3_free(sql);
05928             }
05929             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
05930                 sqlite3_free_table(rowpp);
05931                 continue;
05932             }
05933             namec = findcol(rowpp, nncols, "table");
05934             seqc = findcol(rowpp, nncols, "seq");
05935             fromc = findcol(rowpp, nncols, "from");
05936             toc = findcol(rowpp, nncols, "to");
05937             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
05938                 sqlite3_free_table(rowpp);
05939                 continue;
05940             }
05941             for (k = 1; k <= nnrows; k++) {
05942                 int pos = 0, roffs = (offs + 1) * s->ncols;
05943                 char *ptab = unquote(rowpp[k * nncols + namec]);
05944                 char buf[32];
05945 
05946                 if (plen && ptab) {
05947                     len = strlen(ptab);
05948                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
05949                         continue;
05950                     }
05951                 }
05952                 s->rows[roffs + 0] = xstrdup("");
05953 #if defined(_WIN32) || defined(_WIN64)
05954                 s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
05955 #else
05956                 s->rows[roffs + 1] = xstrdup("");
05957 #endif
05958                 s->rows[roffs + 2] = xstrdup(ptab);
05959                 s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
05960                 s->rows[roffs + 4] = xstrdup("");
05961                 s->rows[roffs + 5] = xstrdup("");
05962                 s->rows[roffs + 6] = xstrdup(rowp[i]);
05963                 s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
05964                 sscanf(rowpp[k * nncols + seqc], "%d", &pos);
05965                 sprintf(buf, "%d", pos + 1);
05966                 s->rows[roffs + 8] = xstrdup(buf);
05967                 s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
05968                 s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
05969                 s->rows[roffs + 11] = NULL;
05970                 s->rows[roffs + 12] = NULL;
05971                 s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
05972                 offs++;
05973             }
05974             sqlite3_free_table(rowpp);
05975         }
05976         sqlite3_free_table(rowp);
05977     }
05978     return SQL_SUCCESS;
05979 }
05980 
05981 #ifndef WINTERFACE
05982 
06000 SQLRETURN SQL_API
06001 SQLForeignKeys(SQLHSTMT stmt,
06002                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
06003                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
06004                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
06005                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
06006                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
06007                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
06008 {
06009     SQLRETURN ret;
06010 
06011     HSTMT_LOCK(stmt);
06012     ret = drvforeignkeys(stmt,
06013                          PKcatalog, PKcatalogLen,
06014                          PKschema, PKschemaLen, PKtable, PKtableLen,
06015                          FKcatalog, FKcatalogLen,
06016                          FKschema, FKschemaLen,
06017                          FKtable, FKtableLen);
06018     HSTMT_UNLOCK(stmt);
06019     return ret;
06020 }
06021 #endif
06022 
06023 #ifdef WINTERFACE
06024 
06042 SQLRETURN SQL_API
06043 SQLForeignKeysW(SQLHSTMT stmt,
06044                 SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
06045                 SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
06046                 SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
06047                 SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
06048                 SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
06049                 SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
06050 {
06051     char *pc = NULL, *ps = NULL, *pt = NULL;
06052     char *fc = NULL, *fs = NULL, *ft = NULL;
06053     SQLRETURN ret;
06054 
06055     HSTMT_LOCK(stmt);
06056     if (PKcatalog) {
06057         pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
06058         if (!pc) {
06059             ret = nomem((STMT *) stmt);
06060             goto done;
06061         }
06062     }
06063     if (PKschema) {
06064         ps = uc_to_utf_c(PKschema, PKschemaLen);
06065         if (!ps) {
06066             ret = nomem((STMT *) stmt);
06067             goto done;
06068         }
06069     }
06070     if (PKtable) {
06071         pt = uc_to_utf_c(PKtable, PKtableLen);
06072         if (!pt) {
06073             ret = nomem((STMT *) stmt);
06074             goto done;
06075         }
06076     }
06077     if (FKcatalog) {
06078         fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
06079         if (!fc) {
06080             ret = nomem((STMT *) stmt);
06081             goto done;
06082         }
06083     }
06084     if (FKschema) {
06085         fs = uc_to_utf_c(FKschema, FKschemaLen);
06086         if (!fs) {
06087             ret = nomem((STMT *) stmt);
06088             goto done;
06089         }
06090     }
06091     if (FKtable) {
06092         ft = uc_to_utf_c(FKtable, FKtableLen);
06093         if (!ft) {
06094             ret = nomem((STMT *) stmt);
06095             goto done;
06096         }
06097     }
06098     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
06099                          (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
06100                          (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
06101                          (SQLCHAR *) ft, SQL_NTS);
06102 done:
06103     HSTMT_UNLOCK(stmt);
06104     uc_free(ft);
06105     uc_free(fs);
06106     uc_free(fc);
06107     uc_free(pt);
06108     uc_free(ps);
06109     uc_free(pc);
06110     return ret;
06111 }
06112 #endif
06113 
06120 static SQLRETURN
06121 starttran(STMT *s)
06122 {
06123     int ret = SQL_SUCCESS, rc, busy_count = 0;
06124     char *errp = NULL;
06125     DBC *d = (DBC *) s->dbc;
06126 
06127     if (!d->autocommit && !d->intrans && !d->trans_disable) {
06128 begin_again:
06129         rc = sqlite3_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL, &errp);
06130         if (rc == SQLITE_BUSY) {
06131             if (busy_handler((void *) d, ++busy_count)) {
06132                 if (errp) {
06133                     sqlite3_free(errp);
06134                     errp = NULL;
06135                 }
06136                 goto begin_again;
06137             }
06138         }
06139         dbtracerc(d, rc, errp);
06140         if (rc != SQLITE_OK) {
06141             setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
06142                     errp ? errp : "unknown error", rc);
06143             ret = SQL_ERROR;
06144         } else {
06145             d->intrans = 1;
06146         }
06147         if (errp) {
06148             sqlite3_free(errp);
06149             errp = NULL;
06150         }
06151     }
06152     return ret;
06153 }
06154 
06163 static SQLRETURN
06164 endtran(DBC *d, SQLSMALLINT comptype, int force)
06165 {
06166     int fail = 0, ret, busy_count = 0;
06167     char *sql, *errp = NULL;
06168 
06169     if (!d->sqlite) {
06170         setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
06171         return SQL_ERROR;
06172     }
06173     if ((!force && d->autocommit) || !d->intrans) {
06174         return SQL_SUCCESS;
06175     }
06176     switch (comptype) {
06177     case SQL_COMMIT:
06178         sql = "COMMIT TRANSACTION";
06179         goto doit;
06180     case SQL_ROLLBACK:
06181     rollback:
06182         sql = "ROLLBACK TRANSACTION";
06183     doit:
06184         ret = sqlite3_exec(d->sqlite, sql, NULL, NULL, &errp);
06185         dbtracerc(d, ret, errp);
06186         if (ret == SQLITE_BUSY && !fail && comptype == SQL_COMMIT) {
06187             if (busy_handler((void *) d, ++busy_count)) {
06188                 if (errp) {
06189                     sqlite3_free(errp);
06190                     errp = NULL;
06191                 }
06192                 goto doit;
06193             }
06194         }
06195         d->intrans = 0;
06196         if (ret != SQLITE_OK) {
06197             if (!fail) {
06198                 setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
06199                          errp ? errp : "transaction failed");
06200                 if (errp) {
06201                     sqlite3_free(errp);
06202                     errp = NULL;
06203                 }
06204                 fail = 1;
06205                 goto rollback;
06206             }
06207             if (errp) {
06208                 sqlite3_free(errp);
06209                 errp = NULL;
06210             }
06211             return SQL_ERROR;
06212         }
06213         if (errp) {
06214             sqlite3_free(errp);
06215             errp = NULL;
06216         }
06217         return SQL_SUCCESS;
06218     }
06219     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
06220     return SQL_ERROR;
06221 }
06222 
06231 static SQLRETURN
06232 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
06233 {
06234     DBC *d;
06235     int fail = 0;
06236     SQLRETURN ret;
06237 #if defined(_WIN32) || defined(_WIN64)
06238     ENV *e;
06239 #endif
06240 
06241     switch (type) {
06242     case SQL_HANDLE_DBC:
06243         HDBC_LOCK((SQLHDBC) handle);
06244         if (handle == SQL_NULL_HDBC) {
06245             return SQL_INVALID_HANDLE;
06246         }
06247         d = (DBC *) handle;
06248         ret = endtran(d, comptype, 0);
06249         HDBC_UNLOCK((SQLHDBC) handle);
06250         return ret;
06251     case SQL_HANDLE_ENV:
06252         if (handle == SQL_NULL_HENV) {
06253             return SQL_INVALID_HANDLE;
06254         }
06255 #if defined(_WIN32) || defined(_WIN64)
06256         e = (ENV *) handle;
06257         if (e->magic != ENV_MAGIC) {
06258             return SQL_INVALID_HANDLE;
06259         }
06260         EnterCriticalSection(&e->cs);
06261         e->owner = GetCurrentThreadId();
06262 #endif
06263         d = ((ENV *) handle)->dbcs;
06264         while (d) {
06265             ret = endtran(d, comptype, 0);
06266             if (ret != SQL_SUCCESS) {
06267                 fail++;
06268                 comptype = SQL_ROLLBACK;
06269             }
06270             d = d->next;
06271         }
06272 #if defined(_WIN32) || defined(_WIN64)
06273         e->owner = 0;
06274         LeaveCriticalSection(&e->cs);
06275 #endif
06276         return fail ? SQL_ERROR : SQL_SUCCESS;
06277     }
06278     return SQL_INVALID_HANDLE;
06279 }
06280 
06289 SQLRETURN SQL_API
06290 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
06291 {
06292     return drvendtran(type, handle, comptype);
06293 }
06294 
06303 SQLRETURN SQL_API
06304 SQLTransact(SQLHENV env, SQLHDBC dbc, SQLUSMALLINT type)
06305 {
06306     if (env != SQL_NULL_HENV) {
06307         return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
06308     }
06309     return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
06310 }
06311 
06316 SQLRETURN SQL_API
06317 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
06318 {
06319     return SQL_ERROR;
06320 }
06321 
06322 #ifndef WINTERFACE
06323 
06334 SQLRETURN SQL_API
06335 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
06336              SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
06337 {
06338     int outLen = 0;
06339     SQLRETURN ret = SQL_SUCCESS;
06340 
06341     HSTMT_LOCK(stmt);
06342     if (sqlinLen == SQL_NTS) {
06343         sqlinLen = strlen((char *) sqlin);
06344     }
06345     if (sql) {
06346         if (sqlMax > 0) {
06347             strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
06348             sqlin[sqlMax - 1] = '\0';
06349             outLen = min(sqlMax - 1, sqlinLen);
06350         }
06351     } else {
06352         outLen = sqlinLen;
06353     }
06354     if (sqlLen) {
06355         *sqlLen = outLen;
06356     }
06357     if (sql && outLen < sqlinLen) {
06358         setstat((STMT *) stmt, -1, "data right truncated", "01004");
06359         ret = SQL_SUCCESS_WITH_INFO;
06360     }
06361     HSTMT_UNLOCK(stmt);
06362     return ret;
06363 }
06364 #endif
06365 
06366 #ifdef WINTERFACE
06367 
06378 SQLRETURN SQL_API
06379 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
06380               SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
06381 {
06382     int outLen = 0;
06383     SQLRETURN ret = SQL_SUCCESS;
06384 
06385     HSTMT_LOCK(stmt);
06386     if (sqlinLen == SQL_NTS) {
06387         sqlinLen = uc_strlen(sqlin);
06388     }
06389     if (sql) {
06390         if (sqlMax > 0) {
06391             uc_strncpy(sql, sqlin, sqlMax - 1);
06392             sqlin[sqlMax - 1] = 0;
06393             outLen = min(sqlMax  - 1, sqlinLen);
06394         }
06395     } else {
06396         outLen = sqlinLen;
06397     }
06398     if (sqlLen) {
06399         *sqlLen = outLen;
06400     }
06401     if (sql && outLen < sqlinLen) {
06402         setstat((STMT *) stmt, -1, "data right truncated", "01004");
06403         ret = SQL_SUCCESS_WITH_INFO;
06404     }
06405     HSTMT_UNLOCK(stmt);
06406     return ret;
06407 }
06408 #endif
06409 
06414 static COL procSpec2[] = {
06415     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
06416     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
06417     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
06418     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
06419     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
06420     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
06421     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
06422     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
06423 };
06424 
06425 static COL procSpec3[] = {
06426     { "SYSTEM", "PROCEDURE", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
06427     { "SYSTEM", "PROCEDURE", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
06428     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
06429     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
06430     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
06431     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
06432     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
06433     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
06434 };
06435 
06436 #ifndef WINTERFACE
06437 
06449 SQLRETURN SQL_API
06450 SQLProcedures(SQLHSTMT stmt,
06451               SQLCHAR *catalog, SQLSMALLINT catalogLen,
06452               SQLCHAR *schema, SQLSMALLINT schemaLen,
06453               SQLCHAR *proc, SQLSMALLINT procLen)
06454 {
06455     SQLRETURN ret;
06456 
06457     HSTMT_LOCK(stmt);
06458     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
06459                       procSpec3, array_size(procSpec3), NULL);
06460     HSTMT_UNLOCK(stmt);
06461     return ret;
06462 }
06463 #endif
06464 
06465 #ifdef WINTERFACE
06466 
06478 SQLRETURN SQL_API
06479 SQLProceduresW(SQLHSTMT stmt,
06480                SQLWCHAR *catalog, SQLSMALLINT catalogLen,
06481                SQLWCHAR *schema, SQLSMALLINT schemaLen,
06482                SQLWCHAR *proc, SQLSMALLINT procLen)
06483 {
06484     SQLRETURN ret;
06485 
06486     HSTMT_LOCK(stmt);
06487     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
06488                       procSpec3, array_size(procSpec3), NULL);
06489     HSTMT_UNLOCK(stmt);
06490     return ret;
06491 }
06492 #endif
06493 
06498 static COL procColSpec2[] = {
06499     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
06500     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
06501     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
06502     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06503     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
06504     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
06505     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
06506     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
06507     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
06508     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
06509     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
06510     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
06511     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
06512     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
06513     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
06514     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
06515     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
06516     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
06517     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
06518 };
06519 
06520 static COL procColSpec3[] = {
06521     { "SYSTEM", "PROCCOL", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
06522     { "SYSTEM", "PROCCOL", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
06523     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
06524     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
06525     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
06526     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
06527     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
06528     { "SYSTEM", "PROCCOL", "COLUMN_SIZE", SQL_INTEGER, 10 },
06529     { "SYSTEM", "PROCCOL", "BUFFER_LENGTH", SQL_INTEGER, 10 },
06530     { "SYSTEM", "PROCCOL", "DECIMAL_DIGITS", SQL_SMALLINT, 5 },
06531     { "SYSTEM", "PROCCOL", "NUM_PREC_RADIX", SQL_SMALLINT, 5 },
06532     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
06533     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
06534     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
06535     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
06536     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
06537     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
06538     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
06539     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
06540 };
06541 
06542 #ifndef WINTERFACE
06543 
06557 SQLRETURN SQL_API
06558 SQLProcedureColumns(SQLHSTMT stmt,
06559                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
06560                     SQLCHAR *schema, SQLSMALLINT schemaLen,
06561                     SQLCHAR *proc, SQLSMALLINT procLen,
06562                     SQLCHAR *column, SQLSMALLINT columnLen)
06563 {
06564     SQLRETURN ret;
06565 
06566     HSTMT_LOCK(stmt);
06567     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
06568                       procColSpec3, array_size(procColSpec3), NULL);
06569     HSTMT_UNLOCK(stmt);
06570     return ret;
06571 }
06572 #endif
06573 
06574 #ifdef WINTERFACE
06575 
06590 SQLRETURN SQL_API
06591 SQLProcedureColumnsW(SQLHSTMT stmt,
06592                      SQLWCHAR *catalog, SQLSMALLINT catalogLen,
06593                      SQLWCHAR *schema, SQLSMALLINT schemaLen,
06594                      SQLWCHAR *proc, SQLSMALLINT procLen,
06595                      SQLWCHAR *column, SQLSMALLINT columnLen)
06596 {
06597     SQLRETURN ret;
06598 
06599     HSTMT_LOCK(stmt);
06600     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
06601                       procColSpec3, array_size(procColSpec3), NULL);
06602     HSTMT_UNLOCK(stmt);
06603     return ret;
06604 }
06605 #endif
06606 
06617 SQLRETURN SQL_API
06618 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
06619               SQLINTEGER len, SQLINTEGER *lenp)
06620 {
06621     ENV *e;
06622     SQLRETURN ret = SQL_ERROR;
06623 
06624     if (env == SQL_NULL_HENV) {
06625         return SQL_INVALID_HANDLE;
06626     }
06627     e = (ENV *) env;
06628     if (!e || e->magic != ENV_MAGIC) {
06629         return SQL_INVALID_HANDLE;
06630     }
06631 #if defined(_WIN32) || defined(_WIN64)
06632     EnterCriticalSection(&e->cs);
06633     e->owner = GetCurrentThreadId();
06634 #endif
06635     switch (attr) {
06636     case SQL_ATTR_CONNECTION_POOLING:
06637         ret = SQL_ERROR;
06638         break;
06639     case SQL_ATTR_CP_MATCH:
06640         ret = SQL_NO_DATA;
06641         break;
06642     case SQL_ATTR_OUTPUT_NTS:
06643         if (val) {
06644             *((SQLINTEGER *) val) = SQL_TRUE;
06645         }
06646         if (lenp) {
06647             *lenp = sizeof (SQLINTEGER);
06648         }
06649         ret = SQL_SUCCESS;
06650         break;
06651     case SQL_ATTR_ODBC_VERSION:
06652         if (val) {
06653             *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
06654         }
06655         if (lenp) {
06656             *lenp = sizeof (SQLINTEGER);
06657         }
06658         ret = SQL_SUCCESS;
06659         break;
06660     }
06661 #if defined(_WIN32) || defined(_WIN64)
06662     e->owner = 0;
06663     LeaveCriticalSection(&e->cs);
06664 #endif
06665     return ret;
06666 }
06667 
06677 SQLRETURN SQL_API
06678 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
06679 {
06680     ENV *e;
06681     SQLRETURN ret = SQL_ERROR;
06682 
06683     if (env == SQL_NULL_HENV) {
06684         return SQL_INVALID_HANDLE;
06685     }
06686     e = (ENV *) env;
06687     if (!e || e->magic != ENV_MAGIC) {
06688         return SQL_INVALID_HANDLE;
06689     }
06690 #if defined(_WIN32) || defined(_WIN64)
06691     EnterCriticalSection(&e->cs);
06692     e->owner = GetCurrentThreadId();
06693 #endif
06694     switch (attr) {
06695     case SQL_ATTR_CONNECTION_POOLING:
06696         ret = SQL_SUCCESS;
06697         break;
06698     case SQL_ATTR_CP_MATCH:
06699         ret = SQL_NO_DATA;
06700         break;
06701     case SQL_ATTR_OUTPUT_NTS:
06702         if (val == (SQLPOINTER) SQL_TRUE) {
06703             ret = SQL_SUCCESS;
06704         }
06705         break;
06706     case SQL_ATTR_ODBC_VERSION:
06707         if (!val) {
06708             break;
06709         }
06710         if (val == (SQLPOINTER) SQL_OV_ODBC2) {
06711             e->ov3 = 0;
06712             ret = SQL_SUCCESS;
06713         }
06714         if (val == (SQLPOINTER) SQL_OV_ODBC3) {
06715             e->ov3 = 1;
06716             ret = SQL_SUCCESS;
06717         }
06718         break;
06719     }
06720 #if defined(_WIN32) || defined(_WIN64)
06721     e->owner = 0;
06722     LeaveCriticalSection(&e->cs);
06723 #endif
06724     return ret;
06725 }
06726 
06740 static SQLRETURN
06741 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
06742               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
06743               SQLSMALLINT buflen, SQLSMALLINT *msglen)
06744 {
06745     DBC *d = NULL;
06746     STMT *s = NULL;
06747     int len, naterr;
06748     char *logmsg, *sqlst;
06749     SQLRETURN ret = SQL_ERROR;
06750 
06751     if (handle == SQL_NULL_HANDLE) {
06752         return SQL_INVALID_HANDLE;
06753     }
06754     if (sqlstate) {
06755         sqlstate[0] = '\0';
06756     }
06757     if (msg && buflen > 0) {
06758         msg[0] = '\0';
06759     }
06760     if (msglen) {
06761         *msglen = 0;
06762     }
06763     if (nativeerr) {
06764         *nativeerr = 0;
06765     }
06766     switch (htype) {
06767     case SQL_HANDLE_ENV:
06768     case SQL_HANDLE_DESC:
06769         return SQL_NO_DATA;
06770     case SQL_HANDLE_DBC:
06771         HDBC_LOCK((SQLHDBC) handle);
06772         d = (DBC *) handle;
06773         logmsg = (char *) d->logmsg;
06774         sqlst = d->sqlstate;
06775         naterr = d->naterr;
06776         break;
06777     case SQL_HANDLE_STMT:
06778         HSTMT_LOCK((SQLHSTMT) handle);
06779         s = (STMT *) handle;
06780         logmsg = (char *) s->logmsg;
06781         sqlst = s->sqlstate;
06782         naterr = s->naterr;
06783         break;
06784     default:
06785         return SQL_INVALID_HANDLE;
06786     }
06787     if (buflen < 0) {
06788         goto done;
06789     }
06790     if (recno > 1) {
06791         ret = SQL_NO_DATA;
06792         goto done;
06793     }
06794     len = strlen(logmsg);
06795     if (len == 0) {
06796         ret = SQL_NO_DATA;
06797         goto done;
06798     }
06799     if (nativeerr) {
06800         *nativeerr = naterr;
06801     }
06802     if (sqlstate) {
06803         strcpy((char *) sqlstate, sqlst);
06804     }
06805     if (msglen) {
06806         *msglen = len;
06807     }
06808     if (len >= buflen) {
06809         if (msg && buflen > 0) {
06810             strncpy((char *) msg, logmsg, buflen);
06811             msg[buflen - 1] = '\0';
06812             logmsg[0] = '\0';
06813         }
06814     } else if (msg) {
06815         strcpy((char *) msg, logmsg);
06816         logmsg[0] = '\0';
06817     }
06818     ret = SQL_SUCCESS;
06819 done:
06820     switch (htype) {
06821     case SQL_HANDLE_DBC:
06822         HDBC_UNLOCK((SQLHDBC) handle);
06823         break;
06824     case SQL_HANDLE_STMT:
06825         HSTMT_UNLOCK((SQLHSTMT) handle);
06826         break;
06827     }
06828     return ret;
06829 }
06830 
06831 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC)
06832 
06845 SQLRETURN SQL_API
06846 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
06847               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
06848               SQLSMALLINT buflen, SQLSMALLINT *msglen)
06849 {
06850     return drvgetdiagrec(htype, handle, recno, sqlstate,
06851                          nativeerr, msg, buflen, msglen);
06852 }
06853 #endif
06854 
06855 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
06856 #ifdef WINTERFACE
06857 
06871 SQLRETURN SQL_API
06872 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
06873               SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
06874               SQLSMALLINT buflen, SQLSMALLINT *msglen)
06875 {
06876     char state[16];
06877     SQLSMALLINT len;
06878     SQLRETURN ret;
06879     
06880     ret = drvgetdiagrec(htype, handle, recno, (SQLCHAR *) state,
06881                         nativeerr, (SQLCHAR *) msg, buflen, &len);
06882     if (ret == SQL_SUCCESS) {
06883         if (sqlstate) {
06884             uc_from_utf_buf((SQLCHAR *) state, -1, sqlstate,
06885                             6 * sizeof (SQLWCHAR));
06886         }
06887         if (msg) {
06888             if (len > 0) {
06889                 SQLWCHAR *m = NULL;
06890 
06891                 m = uc_from_utf((unsigned char *) msg, len);
06892                 if (m) {
06893                     if (buflen) {
06894                         buflen /= sizeof (SQLWCHAR);
06895                         uc_strncpy(msg, m, buflen);
06896                         m[len] = 0;
06897                         len = min(buflen, uc_strlen(m));
06898                     } else {
06899                         len = uc_strlen(m);
06900                     }
06901                     uc_free(m);
06902                 } else {
06903                     len = 0;
06904                 }
06905             }
06906             if (len <= 0) {
06907                 len = 0;
06908                 if (buflen > 0) {
06909                     msg[0] = 0;
06910                 }
06911             }
06912         } else {
06913             /* estimated length !!! */
06914             len *= sizeof (SQLWCHAR);
06915         }
06916         if (msglen) {
06917             *msglen = len;
06918         }
06919     } else if (ret == SQL_NO_DATA) {
06920         if (sqlstate) {
06921             sqlstate[0] = 0;
06922         }
06923         if (msg) {
06924             if (buflen > 0) {
06925                 msg[0] = 0;
06926             }
06927         }
06928         if (msglen) {
06929             *msglen = 0;
06930         }
06931     }
06932     return ret;
06933 }
06934 #endif
06935 #endif
06936 
06949 static SQLRETURN
06950 drvgetdiagfield(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
06951                 SQLSMALLINT id, SQLPOINTER info, 
06952                 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
06953 {
06954     DBC *d = NULL;
06955     STMT *s = NULL;
06956     int len, naterr;
06957     char *logmsg, *sqlst, *clrmsg = NULL;
06958     SQLRETURN ret = SQL_ERROR;
06959 
06960     if (handle == SQL_NULL_HANDLE) {
06961         return SQL_INVALID_HANDLE;
06962     }
06963     if (stringlen) {
06964         *stringlen = 0;
06965     }
06966     switch (htype) {
06967     case SQL_HANDLE_ENV:
06968     case SQL_HANDLE_DESC:
06969         return SQL_NO_DATA;
06970     case SQL_HANDLE_DBC:
06971         HDBC_LOCK((SQLHDBC) handle);
06972         d = (DBC *) handle;
06973         logmsg = (char *) d->logmsg;
06974         sqlst = d->sqlstate;
06975         naterr = d->naterr;
06976         break;
06977     case SQL_HANDLE_STMT:
06978         HSTMT_LOCK((SQLHSTMT) handle);
06979         s = (STMT *) handle;
06980         d = (DBC *) s->dbc;
06981         logmsg = (char *) s->logmsg;
06982         sqlst = s->sqlstate;
06983         naterr = s->naterr;
06984         break;
06985     default:
06986         return SQL_INVALID_HANDLE;
06987     }
06988     if (buflen < 0) {
06989         goto done;
06990     }
06991     if (recno > 1) {
06992         ret = SQL_NO_DATA;
06993         goto done;
06994     }
06995     switch (id) {
06996     case SQL_DIAG_CLASS_ORIGIN:
06997         logmsg = "ISO 9075";
06998         if (sqlst[0] == 'I' && sqlst[1] == 'M') {
06999             logmsg = "ODBC 3.0";
07000         }
07001         break;
07002     case SQL_DIAG_SUBCLASS_ORIGIN:
07003         logmsg = "ISO 9075";
07004         if (sqlst[0] == 'I' && sqlst[1] == 'M') {
07005             logmsg = "ODBC 3.0";
07006         } else if (sqlst[0] == 'H' && sqlst[1] == 'Y') {
07007             logmsg = "ODBC 3.0";
07008         } else if (sqlst[0] == '2' || sqlst[0] == '0' || sqlst[0] == '4') {
07009             logmsg = "ODBC 3.0";
07010         }
07011         break;
07012     case SQL_DIAG_CONNECTION_NAME:
07013     case SQL_DIAG_SERVER_NAME:
07014         logmsg = d->dsn ? d->dsn : "No DSN";
07015         break;
07016     case SQL_DIAG_SQLSTATE:
07017         logmsg = sqlst;
07018         break;
07019     case SQL_DIAG_MESSAGE_TEXT:
07020         clrmsg = logmsg;
07021         break;
07022     case SQL_DIAG_NUMBER:
07023         naterr = 1;
07024         /* fall through */
07025     case SQL_DIAG_NATIVE:
07026         len = strlen(logmsg);
07027         if (len == 0) {
07028             ret = SQL_NO_DATA;
07029             goto done;
07030         }
07031         if (info) {
07032             *((SQLINTEGER *) info) = naterr;
07033         }
07034         ret = SQL_SUCCESS;
07035         goto done;
07036     default:
07037         goto done;
07038     }
07039     if (info && buflen > 0) {
07040         ((char *) info)[0] = '\0';
07041     }
07042     len = strlen(logmsg);
07043     if (len == 0) {
07044         ret = SQL_NO_DATA;
07045         goto done;
07046     }
07047     if (stringlen) {
07048         *stringlen = len;
07049     }
07050     if (len >= buflen) {
07051         if (info && buflen > 0) {
07052             if (stringlen) {
07053                 *stringlen = buflen - 1;
07054             }
07055             strncpy((char *) info, logmsg, buflen);
07056             ((char *) info)[buflen - 1] = '\0';
07057         }
07058     } else if (info) {
07059         strcpy((char *) info, logmsg);
07060     }
07061     if (clrmsg) {
07062         *clrmsg = '\0';
07063     }
07064     ret = SQL_SUCCESS;
07065 done:
07066     switch (htype) {
07067     case SQL_HANDLE_DBC:
07068         HDBC_UNLOCK((SQLHDBC) handle);
07069         break;
07070     case SQL_HANDLE_STMT:
07071         HSTMT_UNLOCK((SQLHSTMT) handle);
07072         break;
07073     }
07074     return ret;
07075 }
07076 
07077 #ifndef WINTERFACE
07078 
07090 SQLRETURN SQL_API
07091 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
07092                 SQLSMALLINT id, SQLPOINTER info, 
07093                 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
07094 {
07095     return drvgetdiagfield(htype, handle, recno, id, info, buflen, stringlen);
07096 }
07097 #endif
07098 
07099 #ifdef WINTERFACE
07100 
07112 SQLRETURN SQL_API
07113 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
07114                  SQLSMALLINT id, SQLPOINTER info, 
07115                  SQLSMALLINT buflen, SQLSMALLINT *stringlen)
07116 {
07117     SQLSMALLINT len;
07118     SQLRETURN ret;
07119     
07120     ret = drvgetdiagfield(htype, handle, recno, id, info, buflen, &len);
07121     if (ret == SQL_SUCCESS) {
07122         if (info) {
07123             switch (id) {
07124             case SQL_DIAG_CLASS_ORIGIN:
07125             case SQL_DIAG_SUBCLASS_ORIGIN:
07126             case SQL_DIAG_CONNECTION_NAME:
07127             case SQL_DIAG_SERVER_NAME:
07128             case SQL_DIAG_SQLSTATE:
07129             case SQL_DIAG_MESSAGE_TEXT:
07130                 if (len > 0) {
07131                     SQLWCHAR *m = NULL;
07132 
07133                     m = uc_from_utf((unsigned char *) info, len);
07134                     if (m) {
07135                         if (buflen) {
07136                             buflen /= sizeof (SQLWCHAR);
07137                             uc_strncpy(info, m, buflen);
07138                             m[len] = 0;
07139                             len = min(buflen, uc_strlen(m));
07140                         } else {
07141                             len = uc_strlen(m);
07142                         }
07143                         uc_free(m);
07144                         len *= sizeof (SQLWCHAR);
07145                     } else {
07146                         len = 0;
07147                     }
07148                 }
07149                 if (len <= 0) {
07150                     len = 0;
07151                     if (buflen > 0) {
07152                         ((SQLWCHAR *) info)[0] = 0;
07153                     }
07154                 }
07155             }
07156         } else {
07157             switch (id) {
07158             case SQL_DIAG_CLASS_ORIGIN:
07159             case SQL_DIAG_SUBCLASS_ORIGIN:
07160             case SQL_DIAG_CONNECTION_NAME:
07161             case SQL_DIAG_SERVER_NAME:
07162             case SQL_DIAG_SQLSTATE:
07163             case SQL_DIAG_MESSAGE_TEXT:
07164                 len *= sizeof (SQLWCHAR);
07165                 break;
07166             }
07167         }
07168         if (stringlen) {
07169             *stringlen = len;
07170         }
07171     }
07172     return ret;
07173 }
07174 #endif
07175 
07186 static SQLRETURN
07187 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
07188                SQLINTEGER bufmax, SQLINTEGER *buflen)
07189 {
07190     STMT *s = (STMT *) stmt;
07191     SQLUINTEGER *uval = (SQLUINTEGER *) val;
07192 
07193     switch (attr) {
07194     case SQL_QUERY_TIMEOUT:
07195         *uval = 0;
07196         return SQL_SUCCESS;
07197     case SQL_ATTR_CURSOR_TYPE:
07198         *uval = s->curtype;
07199         return SQL_SUCCESS;
07200     case SQL_ATTR_CURSOR_SCROLLABLE:
07201         *uval = (s->curtype != SQL_CURSOR_FORWARD_ONLY) ?
07202             SQL_SCROLLABLE : SQL_NONSCROLLABLE;
07203         return SQL_SUCCESS;
07204 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
07205     case SQL_ATTR_CURSOR_SENSITIVITY:
07206         *uval = SQL_UNSPECIFIED;
07207         return SQL_SUCCESS;
07208 #endif
07209     case SQL_ATTR_ROW_NUMBER:
07210         if (s->s3stmt) {
07211             *uval = (s->s3stmt_rownum < 0) ?
07212                     SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
07213         } else {
07214             *uval = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
07215         }
07216         return SQL_SUCCESS;
07217     case SQL_ATTR_ASYNC_ENABLE:
07218         *uval = SQL_ASYNC_ENABLE_OFF;
07219         return SQL_SUCCESS;
07220     case SQL_CONCURRENCY:
07221         *uval = SQL_CONCUR_LOCK;
07222         return SQL_SUCCESS;
07223     case SQL_ATTR_RETRIEVE_DATA:
07224         *uval = s->retr_data;
07225         return SQL_SUCCESS;
07226     case SQL_ROWSET_SIZE:
07227     case SQL_ATTR_ROW_ARRAY_SIZE:
07228         *uval = s->rowset_size;
07229         return SQL_SUCCESS;
07230     /* Needed for some driver managers, but dummies for now */
07231     case SQL_ATTR_IMP_ROW_DESC:
07232     case SQL_ATTR_APP_ROW_DESC:
07233     case SQL_ATTR_IMP_PARAM_DESC:
07234     case SQL_ATTR_APP_PARAM_DESC:
07235         *((SQLHDESC *) val) = (SQLHDESC) DEAD_MAGIC;
07236         return SQL_SUCCESS;
07237     case SQL_ATTR_ROW_STATUS_PTR:
07238         *((SQLUSMALLINT **) val) = s->row_status;
07239         return SQL_SUCCESS;
07240     case SQL_ATTR_ROWS_FETCHED_PTR:
07241         *((SQLUINTEGER **) val) = s->row_count;
07242         return SQL_SUCCESS;
07243     case SQL_ATTR_USE_BOOKMARKS: {
07244         STMT *s = (STMT *) stmt;
07245 
07246         *(SQLUINTEGER *) val = s->bkmrk ? SQL_UB_ON : SQL_UB_OFF;
07247         return SQL_SUCCESS;
07248     }
07249     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
07250         *((SQLUINTEGER **) val) = s->parm_bind_offs;
07251         return SQL_SUCCESS;
07252     case SQL_ATTR_PARAM_BIND_TYPE:
07253         *((SQLUINTEGER *) val) = s->parm_bind_type;
07254         return SQL_SUCCESS;
07255     case SQL_ATTR_PARAM_OPERATION_PTR:
07256         *((SQLUSMALLINT **) val) = s->parm_oper;
07257         return SQL_SUCCESS;
07258     case SQL_ATTR_PARAM_STATUS_PTR:
07259         *((SQLUSMALLINT **) val) = s->parm_status;
07260         return SQL_SUCCESS;
07261     case SQL_ATTR_PARAMS_PROCESSED_PTR:
07262         *((SQLUINTEGER **) val) = s->parm_proc;
07263         return SQL_SUCCESS;
07264     case SQL_ATTR_PARAMSET_SIZE:
07265         *((SQLUINTEGER *) val) = s->paramset_size;
07266         return SQL_SUCCESS;
07267     case SQL_ATTR_ROW_BIND_TYPE:
07268         *(SQLUINTEGER *) val = s->bind_type;
07269         return SQL_SUCCESS;
07270     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
07271         *((SQLUINTEGER **) val) = s->bind_offs;
07272         return SQL_SUCCESS;
07273     case SQL_ATTR_MAX_ROWS:
07274         *((SQLUINTEGER *) val) = s->max_rows;
07275     case SQL_ATTR_MAX_LENGTH:
07276         *((SQLINTEGER *) val) = 1000000000;
07277         return SQL_SUCCESS;
07278     }
07279     return drvunimplstmt(stmt);
07280 }
07281 
07282 #if (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC) || !defined(WINTERFACE)
07283 
07293 SQLRETURN SQL_API
07294 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
07295                SQLINTEGER bufmax, SQLINTEGER *buflen)
07296 {
07297     SQLRETURN ret;
07298 
07299     HSTMT_LOCK(stmt);
07300     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
07301     HSTMT_UNLOCK(stmt);
07302     return ret;
07303 }
07304 #endif
07305 
07306 #ifdef WINTERFACE
07307 
07317 SQLRETURN SQL_API
07318 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
07319                 SQLINTEGER bufmax, SQLINTEGER *buflen)
07320 {
07321     SQLRETURN ret;
07322 
07323     HSTMT_LOCK(stmt);
07324     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
07325     HSTMT_UNLOCK(stmt);
07326     return ret;
07327 }
07328 #endif
07329 
07339 static SQLRETURN
07340 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
07341                SQLINTEGER buflen)
07342 {
07343     STMT *s = (STMT *) stmt;
07344 
07345     switch (attr) {
07346     case SQL_ATTR_CURSOR_TYPE:
07347         if (val == (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY) {
07348             s->curtype = SQL_CURSOR_FORWARD_ONLY;
07349         } else {
07350             s->curtype = SQL_CURSOR_STATIC;
07351         }
07352         if (val != (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY &&
07353             val != (SQLPOINTER) SQL_CURSOR_STATIC) {
07354             goto e01s02;
07355         }
07356         return SQL_SUCCESS;
07357     case SQL_ATTR_CURSOR_SCROLLABLE:
07358         if (val == (SQLPOINTER) SQL_NONSCROLLABLE) {
07359             s->curtype = SQL_CURSOR_FORWARD_ONLY;
07360         } else {
07361             s->curtype = SQL_CURSOR_STATIC;
07362         }
07363         return SQL_SUCCESS;
07364     case SQL_ATTR_ASYNC_ENABLE:
07365         if (val != (SQLPOINTER) SQL_ASYNC_ENABLE_OFF) {
07366     e01s02:
07367             setstat(s, -1, "option value changed", "01S02");
07368             return SQL_SUCCESS_WITH_INFO;
07369         }
07370         return SQL_SUCCESS;
07371     case SQL_CONCURRENCY:
07372         if (val != (SQLPOINTER) SQL_CONCUR_LOCK) {
07373             goto e01s02;
07374         }
07375         return SQL_SUCCESS;
07376 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
07377     case SQL_ATTR_CURSOR_SENSITIVITY:
07378         if (val != (SQLPOINTER) SQL_UNSPECIFIED) {
07379             goto e01s02;
07380         }
07381         return SQL_SUCCESS;
07382 #endif
07383     case SQL_ATTR_QUERY_TIMEOUT:
07384         return SQL_SUCCESS;
07385     case SQL_ATTR_RETRIEVE_DATA:
07386         if (val != (SQLPOINTER) SQL_RD_ON &&
07387             val != (SQLPOINTER) SQL_RD_OFF) {
07388             goto e01s02;
07389         }
07390         s->retr_data = (PTRDIFF_T) val;
07391         return SQL_SUCCESS;
07392     case SQL_ROWSET_SIZE:
07393     case SQL_ATTR_ROW_ARRAY_SIZE:
07394         if ((PTRDIFF_T) val < 1) {
07395             setstat(s, -1, "invalid rowset size", "HY000");
07396             return SQL_ERROR;
07397         } else {
07398             SQLUSMALLINT *rst = &s->row_status1;
07399 
07400             if ((PTRDIFF_T) val > 1) {
07401                 rst = xmalloc(sizeof (SQLUSMALLINT) * (PTRDIFF_T) val);
07402                 if (!rst) {
07403                     return nomem(s);
07404                 }
07405             }
07406             if (s->row_status0 != &s->row_status1) {
07407                 freep(&s->row_status0);
07408             }
07409             s->row_status0 = rst;
07410             s->rowset_size = (PTRDIFF_T) val;
07411         }
07412         return SQL_SUCCESS;
07413     case SQL_ATTR_ROW_STATUS_PTR:
07414         s->row_status = (SQLUSMALLINT *) val;
07415         return SQL_SUCCESS;
07416     case SQL_ATTR_ROWS_FETCHED_PTR:
07417         s->row_count = (SQLUINTEGER *) val;
07418         return SQL_SUCCESS;
07419     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
07420         s->parm_bind_offs = (SQLUINTEGER *) val;
07421         return SQL_SUCCESS;
07422     case SQL_ATTR_PARAM_BIND_TYPE:
07423         s->parm_bind_type = (PTRDIFF_T) val;
07424         return SQL_SUCCESS;
07425     case SQL_ATTR_PARAM_OPERATION_PTR:
07426         s->parm_oper = (SQLUSMALLINT *) val;
07427         return SQL_SUCCESS;
07428     case SQL_ATTR_PARAM_STATUS_PTR:
07429         s->parm_status = (SQLUSMALLINT *) val;
07430         return SQL_SUCCESS;
07431     case SQL_ATTR_PARAMS_PROCESSED_PTR:
07432         s->parm_proc = (SQLUINTEGER *) val;
07433         return SQL_SUCCESS;
07434     case SQL_ATTR_PARAMSET_SIZE:
07435         if ((PTRDIFF_T) val < 1) {
07436             goto e01s02;
07437         }
07438         s->paramset_size = (PTRDIFF_T) val;
07439         s->paramset_count = 0;
07440         return SQL_SUCCESS;
07441     case SQL_ATTR_ROW_BIND_TYPE:
07442         s->bind_type = (PTRDIFF_T) val;
07443         return SQL_SUCCESS;
07444     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
07445         s->bind_offs = (SQLUINTEGER *) val;
07446         return SQL_SUCCESS;
07447     case SQL_ATTR_USE_BOOKMARKS:
07448         if (val != (SQLPOINTER) SQL_UB_OFF &&
07449             val != (SQLPOINTER) SQL_UB_ON) {
07450             goto e01s02;
07451         }
07452         s->bkmrk = val == (SQLPOINTER) SQL_UB_ON;
07453         return SQL_SUCCESS;
07454     case SQL_ATTR_MAX_ROWS:
07455         s->max_rows = (PTRDIFF_T) val;
07456         return SQL_SUCCESS;
07457     case SQL_ATTR_MAX_LENGTH:
07458         if (val != (SQLPOINTER) 1000000000) {
07459             goto e01s02;
07460         }
07461         return SQL_SUCCESS;
07462     }
07463     return drvunimplstmt(stmt);
07464 }
07465 
07466 #if (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC) || !defined(WINTERFACE)
07467 
07476 SQLRETURN SQL_API
07477 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
07478                SQLINTEGER buflen)
07479 {
07480     SQLRETURN ret;
07481 
07482     HSTMT_LOCK(stmt);
07483     ret = drvsetstmtattr(stmt, attr, val, buflen);
07484     HSTMT_UNLOCK(stmt);
07485     return ret;
07486 }
07487 #endif
07488 
07489 #ifdef WINTERFACE
07490 
07499 SQLRETURN SQL_API
07500 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
07501                 SQLINTEGER buflen)
07502 {
07503     SQLRETURN ret;
07504 
07505     HSTMT_LOCK(stmt);
07506     ret = drvsetstmtattr(stmt, attr, val, buflen);
07507     HSTMT_UNLOCK(stmt);
07508     return ret;
07509 }
07510 #endif
07511 
07520 static SQLRETURN
07521 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
07522 {
07523     STMT *s = (STMT *) stmt;
07524     SQLUINTEGER *ret = (SQLUINTEGER *) param;
07525 
07526     switch (opt) {
07527     case SQL_QUERY_TIMEOUT:
07528         *ret = 0;
07529         return SQL_SUCCESS;
07530     case SQL_CURSOR_TYPE:
07531         *ret = s->curtype;
07532         return SQL_SUCCESS;
07533     case SQL_ROW_NUMBER:
07534         if (s->s3stmt) {
07535             *ret = (s->s3stmt_rownum < 0) ?
07536                    SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
07537         } else {
07538             *ret = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
07539         }
07540         return SQL_SUCCESS;
07541     case SQL_ASYNC_ENABLE:
07542         *ret = SQL_ASYNC_ENABLE_OFF;
07543         return SQL_SUCCESS;
07544     case SQL_CONCURRENCY:
07545         *ret = SQL_CONCUR_LOCK;
07546         return SQL_SUCCESS;
07547     case SQL_ATTR_RETRIEVE_DATA:
07548         *ret = s->retr_data;
07549         return SQL_SUCCESS;
07550     case SQL_ROWSET_SIZE:
07551     case SQL_ATTR_ROW_ARRAY_SIZE:
07552         *ret = s->rowset_size;
07553         return SQL_SUCCESS;
07554     case SQL_ATTR_MAX_ROWS:
07555         *ret = s->max_rows;
07556         return SQL_SUCCESS;
07557     case SQL_ATTR_MAX_LENGTH:
07558         *ret = 1000000000;
07559         return SQL_SUCCESS;
07560     }
07561     return drvunimplstmt(stmt);
07562 }
07563 
07572 SQLRETURN SQL_API
07573 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
07574 {
07575     SQLRETURN ret;
07576 
07577     HSTMT_LOCK(stmt);
07578     ret = drvgetstmtoption(stmt, opt, param);
07579     HSTMT_UNLOCK(stmt);
07580     return ret;
07581 }
07582 
07583 #ifdef WINTERFACE
07584 
07592 SQLRETURN SQL_API
07593 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
07594 {
07595     SQLRETURN ret;
07596 
07597     HSTMT_LOCK(stmt);
07598     ret = drvgetstmtoption(stmt, opt, param);
07599     HSTMT_UNLOCK(stmt);
07600     return ret;
07601 }
07602 #endif
07603 
07612 static SQLRETURN
07613 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
07614 {
07615     STMT *s = (STMT *) stmt;
07616 
07617     switch (opt) {
07618     case SQL_CURSOR_TYPE:
07619         if (param == SQL_CURSOR_FORWARD_ONLY) {
07620             s->curtype = param;
07621         } else {
07622             s->curtype = SQL_CURSOR_STATIC;
07623         }
07624         if (param != SQL_CURSOR_FORWARD_ONLY &&
07625             param != SQL_CURSOR_STATIC) {
07626             goto e01s02;
07627         }
07628         return SQL_SUCCESS;
07629     case SQL_ASYNC_ENABLE:
07630         if (param != SQL_ASYNC_ENABLE_OFF) {
07631             goto e01s02;
07632         }
07633         return SQL_SUCCESS;
07634     case SQL_CONCURRENCY:
07635         if (param != SQL_CONCUR_LOCK) {
07636             goto e01s02;
07637         }
07638         return SQL_SUCCESS;
07639     case SQL_QUERY_TIMEOUT:
07640         return SQL_SUCCESS;
07641     case SQL_RETRIEVE_DATA:
07642         if (param != SQL_RD_ON && param != SQL_RD_OFF) {
07643     e01s02:
07644             setstat(s, -1, "option value changed", "01S02");
07645             return SQL_SUCCESS_WITH_INFO;
07646         }
07647         s->retr_data = (int) param;
07648         return SQL_SUCCESS;
07649     case SQL_ROWSET_SIZE:
07650     case SQL_ATTR_ROW_ARRAY_SIZE:
07651         if (param < 1) {
07652             setstat(s, -1, "invalid rowset size", "HY000");
07653             return SQL_ERROR;
07654         } else {
07655             SQLUSMALLINT *rst = &s->row_status1;
07656 
07657             if (param > 1) {
07658                 rst = xmalloc(sizeof (SQLUSMALLINT) * param);
07659                 if (!rst) {
07660                     return nomem(s);
07661                 }
07662             }
07663             if (s->row_status0 != &s->row_status1) {
07664                 freep(&s->row_status0);
07665             }
07666             s->row_status0 = rst;
07667             s->rowset_size = param;
07668         }
07669         return SQL_SUCCESS;
07670     case SQL_ATTR_MAX_ROWS:
07671         s->max_rows = param;
07672         return SQL_SUCCESS;
07673     case SQL_ATTR_MAX_LENGTH:
07674         if (param != 1000000000) {
07675             goto e01s02;
07676         }
07677         return SQL_SUCCESS;
07678     }
07679     return drvunimplstmt(stmt);
07680 }
07681 
07690 SQLRETURN SQL_API
07691 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt,
07692                  SETSTMTOPTION_LAST_ARG_TYPE param)
07693 {
07694     SQLRETURN ret;
07695 
07696     HSTMT_LOCK(stmt);
07697     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
07698     HSTMT_UNLOCK(stmt);
07699     return ret;
07700 }
07701 
07702 #ifdef WINTERFACE
07703 
07711 SQLRETURN SQL_API
07712 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt,
07713                   SETSTMTOPTION_LAST_ARG_TYPE param)
07714 {
07715     SQLRETURN ret;
07716 
07717     HSTMT_LOCK(stmt);
07718     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
07719     HSTMT_UNLOCK(stmt);
07720     return ret;
07721 }
07722 #endif
07723 
07733 static SQLRETURN
07734 drvsetpos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
07735 {
07736     STMT *s = (STMT *) stmt;
07737 
07738     if (op != SQL_POSITION) {
07739         return drvunimplstmt(stmt);
07740     }
07741     if (!s->rows || row <= 0 || row > s->nrows) {
07742         setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
07743         return SQL_ERROR;
07744     }
07745     s->rowp = row - 1;
07746     return SQL_SUCCESS;
07747 }
07748 
07758 SQLRETURN SQL_API
07759 SQLSetPos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
07760 {
07761     SQLRETURN ret;
07762 
07763     HSTMT_LOCK(stmt);
07764     ret = drvsetpos(stmt, row, op, lock);
07765     HSTMT_UNLOCK(stmt);
07766     return ret;
07767 }
07768 
07773 SQLRETURN SQL_API
07774 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
07775                     SQLUSMALLINT rowset)
07776 {
07777     SQLRETURN ret;
07778 
07779     HSTMT_LOCK(stmt);
07780     ret = drvunimplstmt(stmt);
07781     HSTMT_UNLOCK(stmt);
07782     return ret;
07783 }
07784 
07785 #define strmak(dst, src, max, lenp) { \
07786     int len = strlen(src); \
07787     int cnt = min(len + 1, max); \
07788     strncpy(dst, src, cnt); \
07789     *lenp = (cnt > len) ? len : cnt; \
07790 }
07791 
07802 static SQLRETURN
07803 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
07804            SQLSMALLINT *valLen)
07805 {
07806     DBC *d;
07807     char dummyc[16];
07808     SQLSMALLINT dummy;
07809 #if defined(_WIN32) || defined(_WIN64)
07810     char drvname[301];
07811 #else
07812     static char drvname[] = "sqlite3odbc.so";
07813 #endif
07814 
07815     if (dbc == SQL_NULL_HDBC) {
07816         return SQL_INVALID_HANDLE;
07817     }
07818     d = (DBC *) dbc;
07819     if (valMax) {
07820         valMax--;
07821     }
07822     if (!valLen) {
07823         valLen = &dummy;
07824     }
07825     if (!val) {
07826         val = dummyc;
07827         valMax = sizeof (dummyc) - 1;
07828     }
07829     switch (type) {
07830     case SQL_MAX_USER_NAME_LEN:
07831         *((SQLSMALLINT *) val) = 16;
07832         *valLen = sizeof (SQLSMALLINT);
07833         break;
07834     case SQL_USER_NAME:
07835         strmak(val, "", valMax, valLen);
07836         break;
07837     case SQL_DRIVER_ODBC_VER:
07838 #if 0
07839         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
07840 #else
07841         strmak(val, "03.00", valMax, valLen);
07842 #endif
07843         break;
07844     case SQL_ACTIVE_CONNECTIONS:
07845     case SQL_ACTIVE_STATEMENTS:
07846         *((SQLSMALLINT *) val) = 0;
07847         *valLen = sizeof (SQLSMALLINT);
07848         break;
07849 #ifdef SQL_ASYNC_MODE
07850     case SQL_ASYNC_MODE:
07851         *((SQLUINTEGER *) val) = SQL_AM_NONE;
07852         *valLen = sizeof (SQLUINTEGER);
07853         break;
07854 #endif
07855 #ifdef SQL_CREATE_TABLE
07856     case SQL_CREATE_TABLE:
07857         *((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
07858                                  SQL_CT_COLUMN_DEFAULT |
07859                                  SQL_CT_COLUMN_CONSTRAINT |
07860                                  SQL_CT_CONSTRAINT_NON_DEFERRABLE;
07861         *valLen = sizeof (SQLUINTEGER);
07862         break;
07863 #endif
07864 #ifdef SQL_CREATE_VIEW
07865     case SQL_CREATE_VIEW:
07866         *((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
07867         *valLen = sizeof (SQLUINTEGER);
07868         break;
07869 #endif
07870 #ifdef SQL_DDL_INDEX
07871     case SQL_DDL_INDEX:
07872         *((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
07873         *valLen = sizeof (SQLUINTEGER);
07874         break;
07875 #endif
07876 #ifdef SQL_DROP_TABLE
07877     case SQL_DROP_TABLE:
07878         *((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
07879         *valLen = sizeof (SQLUINTEGER);
07880         break;
07881 #endif
07882 #ifdef SQL_DROP_VIEW
07883     case SQL_DROP_VIEW:
07884         *((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
07885         *valLen = sizeof (SQLUINTEGER);
07886         break;
07887 #endif
07888 #ifdef SQL_INDEX_KEYWORDS
07889     case SQL_INDEX_KEYWORDS:
07890         *((SQLUINTEGER *) val) = SQL_IK_ALL;
07891         *valLen = sizeof (SQLUINTEGER);
07892         break;
07893 #endif
07894     case SQL_DATA_SOURCE_NAME:
07895         strmak(val, d->dsn ? d->dsn : "", valMax, valLen);
07896         break;
07897     case SQL_DRIVER_NAME:
07898 #if defined(_WIN32) || defined(_WIN64)
07899         GetModuleFileName(hModule, drvname, sizeof (drvname));
07900 #endif
07901         strmak(val, drvname, valMax, valLen);
07902         break;
07903     case SQL_DRIVER_VER:
07904         strmak(val, DRIVER_VER_INFO, valMax, valLen);
07905         break;
07906     case SQL_FETCH_DIRECTION:
07907         *((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
07908             SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
07909         *valLen = sizeof (SQLUINTEGER);
07910         break;
07911     case SQL_ODBC_VER:
07912         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
07913         break;
07914     case SQL_ODBC_SAG_CLI_CONFORMANCE:
07915         *((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
07916         *valLen = sizeof (SQLSMALLINT);
07917         break;
07918     case SQL_STANDARD_CLI_CONFORMANCE:
07919         *((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
07920         *valLen = sizeof (SQLUINTEGER);
07921         break;
07922     case SQL_SERVER_NAME:
07923     case SQL_DATABASE_NAME:
07924         strmak(val, d->dbname ? d->dbname : "", valMax, valLen);
07925         break;
07926     case SQL_SEARCH_PATTERN_ESCAPE:
07927         strmak(val, "\\", valMax, valLen);
07928         break;
07929     case SQL_ODBC_SQL_CONFORMANCE:
07930         *((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
07931         *valLen = sizeof (SQLSMALLINT);
07932         break;
07933     case SQL_ODBC_API_CONFORMANCE:
07934         *((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
07935         *valLen = sizeof (SQLSMALLINT);
07936         break;
07937     case SQL_DBMS_NAME:
07938         strmak(val, "SQLite", valMax, valLen);
07939         break;
07940     case SQL_DBMS_VER:
07941         strmak(val, SQLITE_VERSION, valMax, valLen);
07942         break;
07943     case SQL_COLUMN_ALIAS:
07944     case SQL_NEED_LONG_DATA_LEN:
07945         strmak(val, "Y", valMax, valLen);
07946         break;
07947     case SQL_ROW_UPDATES:
07948     case SQL_ACCESSIBLE_PROCEDURES:
07949     case SQL_PROCEDURES:
07950     case SQL_EXPRESSIONS_IN_ORDERBY:
07951     case SQL_ODBC_SQL_OPT_IEF:
07952     case SQL_LIKE_ESCAPE_CLAUSE:
07953     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
07954     case SQL_OUTER_JOINS:
07955     case SQL_ACCESSIBLE_TABLES:
07956     case SQL_MULT_RESULT_SETS:
07957     case SQL_MULTIPLE_ACTIVE_TXN:
07958     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
07959         strmak(val, "N", valMax, valLen);
07960         break;
07961 #ifdef SQL_CATALOG_NAME
07962     case SQL_CATALOG_NAME:
07963 #if defined(_WIN32) || defined(_WIN64)
07964         strmak(val, d->xcelqrx ? "Y" : "N", valMax, valLen);
07965 #else
07966         strmak(val, "N", valMax, valLen);
07967 #endif
07968         break;
07969 #endif
07970     case SQL_DATA_SOURCE_READ_ONLY:
07971         strmak(val, "N", valMax, valLen);
07972         break;
07973 #ifdef SQL_OJ_CAPABILITIES
07974     case SQL_OJ_CAPABILITIES:
07975         *((SQLUINTEGER *) val) = 0;
07976         *valLen = sizeof (SQLUINTEGER);
07977         break;
07978 #endif
07979 #ifdef SQL_MAX_IDENTIFIER_LEN
07980     case SQL_MAX_IDENTIFIER_LEN:
07981         *((SQLUSMALLINT *) val) = 255;
07982         *valLen = sizeof (SQLUSMALLINT);
07983         break;
07984 #endif
07985     case SQL_CONCAT_NULL_BEHAVIOR:
07986         *((SQLSMALLINT *) val) = SQL_CB_NULL;
07987         *valLen = sizeof (SQLSMALLINT);
07988         break;
07989     case SQL_CURSOR_COMMIT_BEHAVIOR:
07990     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
07991         *((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
07992         *valLen = sizeof (SQLSMALLINT);
07993         break;
07994 #ifdef SQL_CURSOR_SENSITIVITY
07995     case SQL_CURSOR_SENSITIVITY:
07996         *((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
07997         *valLen = sizeof (SQLUINTEGER);
07998         break;
07999 #endif
08000     case SQL_DEFAULT_TXN_ISOLATION:
08001         *((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
08002         *valLen = sizeof (SQLUINTEGER);
08003         break;
08004 #ifdef SQL_DESCRIBE_PARAMETER
08005     case SQL_DESCRIBE_PARAMETER:
08006         strmak(val, "Y", valMax, valLen);
08007         break;
08008 #endif
08009     case SQL_TXN_ISOLATION_OPTION:
08010         *((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
08011         *valLen = sizeof (SQLUINTEGER);
08012         break;
08013     case SQL_IDENTIFIER_CASE:
08014         *((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
08015         *valLen = sizeof (SQLSMALLINT);
08016         break;
08017     case SQL_IDENTIFIER_QUOTE_CHAR:
08018         strmak(val, "\"", valMax, valLen);
08019         break;
08020     case SQL_MAX_TABLE_NAME_LEN:
08021     case SQL_MAX_COLUMN_NAME_LEN:
08022         *((SQLSMALLINT *) val) = 255;
08023         *valLen = sizeof (SQLSMALLINT);
08024         break;
08025     case SQL_MAX_CURSOR_NAME_LEN:
08026         *((SQLSMALLINT *) val) = 255;
08027         *valLen = sizeof (SQLSMALLINT);
08028         break;
08029     case SQL_MAX_PROCEDURE_NAME_LEN:
08030         *((SQLSMALLINT *) val) = 0;
08031         break;
08032     case SQL_MAX_QUALIFIER_NAME_LEN:
08033     case SQL_MAX_OWNER_NAME_LEN:
08034         *((SQLSMALLINT *) val) = 255;
08035         break;
08036     case