Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

sqliteodbc.c

Go to the documentation of this file.
00001 
00014 #include "sqliteodbc.h"
00015 
00016 #ifdef SQLITE_UTF8
00017 #include <sqlucode.h>
00018 #endif
00019 
00020 #ifdef _WIN32
00021 #include "resource.h"
00022 #define ODBC_INI "ODBC.INI"
00023 #define DRIVER_VER_INFO VERSION
00024 #else
00025 #define ODBC_INI ".odbc.ini"
00026 #endif
00027 
00028 #ifndef DRIVER_VER_INFO
00029 #define DRIVER_VER_INFO "0.0"
00030 #endif
00031 
00032 #undef min
00033 #define min(a, b) ((a) < (b) ? (a) : (b))
00034 #undef max
00035 #define max(a, b) ((a) < (b) ? (b) : (a))
00036 
00037 #define array_size(x) (sizeof (x) / sizeof (x[0]))
00038 
00039 #define stringify1(s) #s
00040 #define stringify(s) stringify1(s)
00041 
00042 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
00043 
00044 /* Column types for static string column descriptions (SQLTables etc.) */
00045 
00046 #ifdef SQLITE_UTF8
00047 #define SCOL_VARCHAR SQL_WVARCHAR
00048 #define SCOL_CHAR SQL_WCHAR
00049 #else
00050 #define SCOL_VARCHAR SQL_VARCHAR
00051 #define SCOL_CHAR SQL_CHAR
00052 #endif
00053 
00054 #define ENV_MAGIC  0x53544145
00055 #define DBC_MAGIC  0x53544144
00056 #define DEAD_MAGIC 0xdeadbeef
00057 
00058 #ifdef MEMORY_DEBUG
00059 
00060 static void *
00061 xmalloc_(int n, char *file, int line)
00062 {
00063     int nn = n + 4 * sizeof (long);
00064     long *p;
00065 
00066     p = malloc(nn);
00067     if (!p) {
00068 #if (MEMORY_DEBUG > 1)
00069         fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
00070 #endif
00071         return NULL;
00072     }
00073     p[0] = 0xdead1234;
00074     nn = nn / sizeof (long) - 1;
00075     p[1] = n;
00076     p[nn] = 0xdead5678;
00077 #if (MEMORY_DEBUG > 1)
00078     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
00079 #endif
00080     return (void *) &p[2];
00081 }
00082 
00083 static void *
00084 xrealloc_(void *old, int n, char *file, int line)
00085 {
00086     int nn = n + 4 * sizeof (long), nnn;
00087     long *p, *pp;
00088 
00089     if (n == 0) {
00090         return xmalloc_(n, file, line);
00091     }
00092     p = &((long *) old)[-2];
00093     if (p[0] != 0xdead1234) {
00094         fprintf(stderr, "*** low end corruption @ %p\n", old);
00095         abort();
00096     }
00097     nnn = p[1] + 4 * sizeof (long);
00098     nnn = nnn / sizeof (long) - 1;
00099     if (p[nnn] != 0xdead5678) {
00100         fprintf(stderr, "*** high end corruption @ %p\n", old);
00101         abort();
00102     }
00103     pp = realloc(p, nn);
00104     if (!pp) {
00105 #if (MEMORY_DEBUG > 1)
00106         fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
00107 #endif
00108         return NULL;
00109     }
00110 #if (MEMORY_DEBUG > 1)
00111     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
00112 #endif
00113     p = pp;
00114     if (n > p[1]) {
00115         memset(p + p[1], 0, 3 * sizeof (long));
00116     }
00117     p[1] = n;
00118     nn = nn / sizeof (long) - 1;
00119     p[nn] = 0xdead5678;
00120     return (void *) &p[2];
00121 }
00122 
00123 static void
00124 xfree_(void *x, char *file, int line)
00125 {
00126     long *p;
00127     int n;
00128 
00129     p = &((long *) x)[-2];
00130     if (p[0] != 0xdead1234) {
00131         fprintf(stderr, "*** low end corruption @ %p\n", x);
00132         abort();
00133     }
00134     n = p[1] + 4 * sizeof (long);
00135     n = n / sizeof (long) - 1;
00136     if (p[n] != 0xdead5678) {
00137         fprintf(stderr, "*** high end corruption @ %p\n", x);
00138         abort();
00139     }
00140 #if (MEMORY_DEBUG > 1)
00141     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
00142 #endif
00143     free(p);
00144 }
00145 
00146 static void
00147 xfree__(void *x)
00148 {
00149     xfree_(x, "unknown location", 0);
00150 }
00151 
00152 static char *
00153 xstrdup_(char *str, char *file, int line)
00154 {
00155     char *p;
00156 
00157     if (!str) {
00158 #if (MEMORY_DEBUG > 1)
00159         fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
00160 #endif
00161         return NULL;
00162     }
00163     p = xmalloc_(strlen(str) + 1, file, line);
00164     if (p) {
00165         strcpy(p, str);
00166     }
00167 #if (MEMORY_DEBUG > 1)
00168     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
00169 #endif
00170     return p;
00171 }
00172 
00173 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
00174 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
00175 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
00176 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
00177 
00178 #else
00179 
00180 #define xmalloc(x)    malloc(x)
00181 #define xrealloc(x,y) realloc(x, y)
00182 #define xfree(x)      free(x)
00183 #define xstrdup(x)    strdup_(x)
00184 
00185 #endif
00186 
00187 #ifdef _WIN32
00188 #define vsnprintf   _vsnprintf
00189 #define snprintf    _snprintf
00190 #define strncasecmp _strnicmp
00191 #endif
00192 
00193 /*
00194  * tolower() replacement w/o locale
00195  */
00196 
00197 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00198 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
00199 
00200 static int
00201 TOLOWER(int c)
00202 {
00203     if (c) {
00204         char *p = strchr(upper_chars, c);
00205 
00206         if (p) {
00207             c = lower_chars[p - upper_chars];
00208         }
00209     }
00210     return c;
00211 }
00212 
00213 /*
00214  * isdigit() replacement w/o ctype.h
00215  */
00216 
00217 static const char digit_chars[] = "0123456789";
00218 
00219 #define ISDIGIT(c) \
00220     ((c) && strchr(digit_chars, (c)) != NULL)
00221 
00222 /*
00223  * isspace() replacement w/o ctype.h
00224  */
00225 
00226 static const char space_chars[] = " \f\n\r\t\v";
00227 
00228 #define ISSPACE(c) \
00229     ((c) && strchr(space_chars, (c)) != NULL)
00230 
00231 /*
00232  * Characters in named parameters
00233  */
00234 
00235 static const char id_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00236                                "abcdefghijklmnopqrstuvwxyz"
00237                                "_0123456789";
00238 
00239 #define ISIDCHAR(c) \
00240     ((c) && strchr(id_chars, (c)) != NULL)
00241 
00247 static void unbindcols(STMT *s);
00248 
00256 static SQLRETURN mkbindcols(STMT *s, int ncols);
00257 
00269 static void freeresult(STMT *s, int clrcols);
00270 
00277 static SQLRETURN freestmt(HSTMT stmt);
00278 
00293 static SQLRETURN substparam(STMT *s, int pnum, char **out, int *size);
00294 
00300 static void freedyncols(STMT *s);
00301 
00308 static SQLRETURN drvexecute(SQLHSTMT stmt);
00309 
00310 #if (MEMORY_DEBUG < 1)
00311 
00317 static char *
00318 strdup_(const char *str)
00319 {
00320     char *p = NULL;
00321 
00322     if (str) {
00323         p = xmalloc(strlen(str) + 1);
00324         if (p) {
00325             strcpy(p, str);
00326         }
00327     }
00328     return p;
00329 }
00330 #endif
00331 
00332 #ifdef SQLITE_UTF8
00333 
00339 static int
00340 uc_strlen(SQLWCHAR *str)
00341 {
00342     int len = 0;
00343 
00344     if (str) {
00345         while (*str) {
00346             ++len;
00347             ++str;
00348         }
00349     }
00350     return len;
00351 }
00352 
00361 static SQLWCHAR *
00362 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
00363 {
00364     int i = 0;
00365 
00366     while (i < len) {
00367         if (!src[i]) {
00368             break;
00369         }
00370         dest[i] = src[i];
00371         ++i;
00372     }
00373     if (i < len) {
00374         dest[i] = 0;
00375     }
00376     return dest;
00377 }
00378 
00386 static void
00387 uc_from_utf_buf(unsigned char *str, SQLWCHAR *uc, int ucLen)
00388 {
00389     ucLen = ucLen / sizeof (SQLWCHAR);
00390     if (!uc || ucLen < 0) {
00391         return;
00392     }
00393     uc[0] = 0;
00394     if (str) {
00395         int i = 0;
00396 
00397         while (*str && i < ucLen) {
00398             unsigned char c = str[0];
00399 
00400             if (c < 0xc0) {
00401                 uc[i++] = c;
00402                 ++str;
00403             } else if (c < 0xe0) {
00404                 if ((str[1] & 0xc0) == 0x80) {
00405                     unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
00406 
00407                     uc[i++] = t;
00408                     str += 2;
00409                 } else {
00410                     uc[i++] = c;
00411                     ++str;
00412                 }
00413             } else if (c < 0xf0) {
00414                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
00415                     unsigned long t = ((c & 0x0f) << 12) |
00416                         ((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
00417 
00418                     uc[i++] = t;
00419                     str += 3;
00420                 } else {
00421                     uc[i++] = c;
00422                     ++str;
00423                 }
00424             } else if (c < 0xf8) {
00425                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
00426                     (str[3] & 0xc0) == 0x80) {
00427                     unsigned long t = ((c & 0x03) << 18) |
00428                         ((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
00429                         (str[4] & 0x3f);
00430 
00431                     uc[i++] = t;
00432                     str += 4;
00433                 } else {
00434                     uc[i++] = c;
00435                     ++str;
00436                 }
00437             } else if (c < 0xfc) {
00438                 if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
00439                     (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80) {
00440                     unsigned long t = ((c & 0x01) << 24) |
00441                         ((str[1] & 0x3f) << 18) | ((str[2] & 0x3f) << 12) |
00442                         ((str[4] & 0x3f) << 6) | (str[5] & 0x3f);
00443 
00444                     uc[i++] = t;
00445                     str += 5;
00446                 } else {
00447                     uc[i++] = c;
00448                     ++str;
00449                 }
00450             } else {
00451                 /* ignore */
00452                 ++str;
00453             }
00454         }
00455         if (i < ucLen) {
00456             uc[i] = 0;
00457         }
00458     }
00459 }
00460 
00468 static SQLWCHAR *
00469 uc_from_utf(unsigned char *str, int len)
00470 {
00471     SQLWCHAR *uc = NULL;
00472 
00473     if (str) {
00474         if (len == SQL_NTS) {
00475             len = strlen(str);
00476         }
00477         len = sizeof (SQLWCHAR) * (len + 1);
00478         uc = xmalloc(len);
00479         if (uc) {
00480             uc_from_utf_buf(str, uc, len);
00481         }
00482     }
00483     return uc;
00484 }
00485 
00493 static char *
00494 uc_to_utf(SQLWCHAR *str, int len)
00495 {
00496     int i;
00497     char *cp, *ret = NULL;
00498 
00499     if (!str) {
00500         return ret;
00501     }
00502     if (len == SQL_NTS) {
00503         len = uc_strlen(str);
00504     } else {
00505         len = len / sizeof (SQLWCHAR);
00506     }
00507     cp = xmalloc(len * 6 + 1);
00508     if (!cp) {
00509         return ret;
00510     }
00511     ret = cp;
00512     for (i = 0; i < len; i++) {
00513         unsigned long c = str[i];
00514 
00515         if (c < 0xc0) {
00516             *cp++ = c;
00517         } else if (c < 0x800) {
00518             *cp++ = 0xc0 | ((c >> 6) & 0x1f);
00519             *cp++ = 0x80 | (c & 0x3f);
00520         } else if (c < 0x10000) {
00521             *cp++ = 0xe0 | ((c >> 12) & 0x0f);
00522             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00523             *cp++ = 0x80 | (c & 0x3f);
00524         } else if (c < 0x200000) {
00525             *cp++ = 0xf0 | ((c >> 18) & 0x07);
00526             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00527             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00528             *cp++ = 0x80 | (c & 0x3f);
00529         } else if (c < 0x4000000) {
00530             *cp++ = 0xf8 | ((c >> 24) & 0x03);
00531             *cp++ = 0x80 | ((c >> 18) & 0x3f);
00532             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00533             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00534             *cp++ = 0x80 | (c & 0x3f);
00535         } else if (c < 0x80000000) {
00536             *cp++ = 0xfc | ((c >> 31) & 0x01);
00537             *cp++ = 0x80 | ((c >> 24) & 0x3f);
00538             *cp++ = 0x80 | ((c >> 18) & 0x3f);
00539             *cp++ = 0x80 | ((c >> 12) & 0x3f);
00540             *cp++ = 0x80 | ((c >> 6) & 0x3f);
00541             *cp++ = 0x80 | (c & 0x3f);
00542         }
00543     }
00544     *cp = '\0';
00545     return ret;
00546 }
00547 
00555 static char *
00556 uc_to_utf_c(SQLWCHAR *str, int len)
00557 {
00558     if (len != SQL_NTS) {
00559         len = len * sizeof (SQLWCHAR);
00560     }
00561     return uc_to_utf(str, len);
00562 }
00563 
00568 static void
00569 uc_free(void *str)
00570 {
00571     if (str) {
00572         xfree(str);
00573     }
00574 }
00575 #endif
00576 
00577 #ifdef USE_DLOPEN_FOR_GPPS
00578 
00579 #include <dlfcn.h>
00580 
00581 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
00582 
00583 /*
00584  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
00585  * dlopen(), in theory this makes the driver independent from the
00586  * driver manager, i.e. the same driver binary can run with iODBC
00587  * and unixODBC.
00588  */
00589 
00590 static void
00591 drvgetgpps(DBC *d)
00592 {
00593     void *lib;
00594     int (*gpps)();
00595 
00596     lib = dlopen("libodbcinst.so", RTLD_LAZY);
00597     if (!lib) {
00598         lib = dlopen("libiodbcinst.so", RTLD_LAZY);
00599     }
00600     if (lib) {
00601         gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
00602         if (!gpps) {
00603             dlclose(lib);
00604             return;
00605         }
00606         d->instlib = lib;
00607         d->gpps = gpps;
00608     }
00609 }
00610 
00611 static void
00612 drvrelgpps(DBC *d)
00613 {
00614     if (d->instlib) {
00615         dlclose(d->instlib);
00616         d->instlib = 0;
00617     }
00618 }
00619 
00620 static int
00621 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
00622         int bufsiz, char *fname)
00623 {
00624     if (d->gpps) {
00625         return d->gpps(sect, ent, def, buf, bufsiz, fname);
00626     }
00627     strncpy(buf, def, bufsiz);
00628     buf[bufsiz - 1] = '\0';
00629     return 1;
00630 }
00631 #else
00632 #define drvgetgpps(d)
00633 #define drvrelgpps(d)
00634 #endif
00635 
00644 #if defined(__GNUC__) && (__GNUC__ >= 2)
00645 static void setstatd(DBC *, int, char *, char *, ...)
00646     __attribute__((format (printf, 3, 5)));
00647 #endif
00648 
00649 static void
00650 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
00651 {
00652     va_list ap;
00653 
00654     if (!d) {
00655         return;
00656     }
00657     d->naterr = naterr;
00658     d->logmsg[0] = '\0';
00659     if (msg) {
00660         int count;
00661 
00662         va_start(ap, st);
00663         count = vsnprintf(d->logmsg, sizeof (d->logmsg), msg, ap);
00664         va_end(ap);
00665         if (count < 0) {
00666             d->logmsg[sizeof (d->logmsg) - 1] = '\0';
00667         }
00668     }
00669     if (!st) {
00670         st = "?????";
00671     }
00672     strncpy(d->sqlstate, st, 5);
00673     d->sqlstate[5] = '\0';
00674 }
00675 
00684 #if defined(__GNUC__) && (__GNUC__ >= 2)
00685 static void setstat(STMT *, int, char *, char *, ...)
00686     __attribute__((format (printf, 3, 5)));
00687 #endif
00688 
00689 static void
00690 setstat(STMT *s, int naterr, char *msg, char *st, ...)
00691 {
00692     va_list ap;
00693 
00694     if (!s) {
00695         return;
00696     }
00697     s->naterr = naterr;
00698     s->logmsg[0] = '\0';
00699     if (msg) {
00700         int count;
00701 
00702         va_start(ap, st);
00703         count = vsnprintf(s->logmsg, sizeof (s->logmsg), msg, ap);
00704         va_end(ap);
00705         if (count < 0) {
00706             s->logmsg[sizeof (s->logmsg) - 1] = '\0';
00707         }
00708     }
00709     if (!st) {
00710         st = "?????";
00711     }
00712     strncpy(s->sqlstate, st, 5);
00713     s->sqlstate[5] = '\0';
00714 }
00715 
00722 static SQLRETURN
00723 drvunimpldbc(HDBC dbc)
00724 {
00725     DBC *d;
00726 
00727     if (dbc == SQL_NULL_HDBC) {
00728         return SQL_INVALID_HANDLE;
00729     }
00730     d = (DBC *) dbc;
00731     setstatd(d, -1, "not supported", "IM001");
00732     return SQL_ERROR;
00733 }
00734 
00741 static SQLRETURN
00742 drvunimplstmt(HSTMT stmt)
00743 {
00744     STMT *s;
00745 
00746     if (stmt == SQL_NULL_HSTMT) {
00747         return SQL_INVALID_HANDLE;
00748     }
00749     s = (STMT *) stmt;
00750     setstat(s, -1, "not supported", "IM001");
00751     return SQL_ERROR;
00752 }
00753 
00759 static void
00760 freep(void *x)
00761 {
00762     if (x && ((char **) x)[0]) {
00763         xfree(((char **) x)[0]);
00764         ((char **) x)[0] = NULL;
00765     }
00766 }
00767 
00774 static SQLRETURN
00775 nomem(STMT *s)
00776 {
00777     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
00778     return SQL_ERROR;
00779 }
00780 
00787 static SQLRETURN
00788 noconn(STMT *s)
00789 {
00790     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
00791     return SQL_ERROR;
00792 }
00793 
00801 #if defined(HAVE_SQLITEATOF) && HAVE_SQLITEATOF
00802 
00803 extern double sqliteAtoF(char *data, char **endp);
00804 
00805 #define ln_strtod sqliteAtoF
00806 
00807 #else
00808 
00809 static double
00810 ln_strtod(const char *data, char **endp)
00811 {
00812 #if defined(HAVE_LOCALECONV) || defined(_WIN32)
00813     struct lconv *lc;
00814     char buf[128], *p, *end;
00815     double value;
00816 
00817     lc = localeconv();
00818     if (lc && lc->decimal_point && lc->decimal_point[0] &&
00819         lc->decimal_point[0] != '.') {
00820         strncpy(buf, data, sizeof (buf) - 1);
00821         buf[sizeof (buf) - 1] = '\0';
00822         p = strchr(buf, '.');
00823         if (p) {
00824             *p = lc->decimal_point[0];
00825         }
00826         p = buf;
00827     } else {
00828         p = (char *) data;
00829     }
00830     value = strtod(p, &end);
00831     end = (char *) data + (end - p);
00832     if (endp) {
00833         *endp = end;
00834     }
00835     return value;
00836 #else
00837     return strtod(data, endp);
00838 #endif
00839 }
00840 
00841 #endif
00842 
00843 #if !defined(HAVE_SQLITEMPRINTF) || !HAVE_SQLITEMPRINTF
00844 
00850 static void
00851 ln_sprintfg(char *buf, double value)
00852 {
00853 #if defined(HAVE_LOCALECONV) || defined(_WIN32)
00854     struct lconv *lc;
00855     char *p;
00856 
00857     sprintf(buf, "%.16g", value);
00858     lc = localeconv();
00859     if (lc && lc->decimal_point && lc->decimal_point[0] &&
00860         lc->decimal_point[0] != '.') {
00861         p = strchr(buf, lc->decimal_point[0]);
00862         if (p) {
00863             *p = '.';
00864         }
00865     }
00866 #else
00867     sprintf(buf, "%.16g", value);
00868 #endif
00869 }
00870 #endif
00871 
00880 static int
00881 busy_handler(void *udata, const char *table, int count)
00882 {
00883     DBC *d = (DBC *) udata;
00884     long t1;
00885     int ret = 0;
00886 #ifndef _WIN32
00887     struct timeval tv;
00888 #endif
00889 
00890     if (d->timeout <= 0) {
00891         return ret;
00892     }
00893     if (count <= 1) {
00894 #ifdef _WIN32
00895         d->t0 = GetTickCount();
00896 #else
00897         gettimeofday(&tv, NULL);
00898         d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00899 #endif
00900     }
00901 #ifdef _WIN32
00902     t1 = GetTickCount();
00903 #else
00904     gettimeofday(&tv, NULL);
00905     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00906 #endif
00907     if (t1 - d->t0 > d->timeout) {
00908         goto done;
00909         return 0;
00910     }
00911 #ifdef _WIN32
00912     Sleep(10);
00913 #else
00914 #ifdef HAVE_USLEEP
00915     usleep(10000);
00916 #else
00917     tv.tv_sec = 0;
00918     tv.tv_usec = 10000;
00919     select(0, NULL, NULL, NULL, &tv);
00920 #endif
00921 #endif
00922     ret = 1;
00923 done:
00924     return ret;
00925 }
00926 
00943 static int
00944 setsqliteopts(sqlite *x, DBC *d)
00945 {
00946     int count = 0, step = 0, rc;
00947 
00948     while (step < 4) {
00949         if (step < 1) {
00950             rc = sqlite_exec(x, "PRAGMA full_column_names = on;",
00951                              NULL, NULL, NULL);
00952         } else if (step < 2) {
00953             rc = sqlite_exec(x, "PRAGMA count_changes = on;",
00954                              NULL, NULL, NULL);
00955         } else if (step < 3) {
00956             rc = sqlite_exec(x, "PRAGMA empty_result_callbacks = on;",
00957                              NULL, NULL, NULL);
00958         } else {
00959             rc = sqlite_exec(x, "PRAGMA show_datatypes = on;",
00960                              NULL, NULL, NULL);
00961         }
00962         if (rc != SQLITE_OK) {
00963             if (rc != SQLITE_BUSY ||
00964                 !busy_handler((void *) d, NULL, ++count)) {
00965                 return rc;
00966             }
00967             continue;
00968         }
00969         count = 0;
00970         ++step;
00971     }
00972     sqlite_busy_handler(x, busy_handler, (void *) d);
00973 #if HAVE_ENCDEC
00974     {
00975         char *fname;
00976         static void hextobin_func(sqlite_func *context,
00977                                   int argc, const char **argv);
00978         static void bintohex_func(sqlite_func *context,
00979                                   int argc, const char **argv);
00980 
00981         fname = "hextobin";
00982         sqlite_create_function(x, fname, 1, hextobin_func, 0);
00983         sqlite_function_type(x, fname, SQLITE_TEXT);
00984         fname = "bintohex";
00985         sqlite_create_function(x, fname, 1, bintohex_func, 0);
00986         sqlite_function_type(x, fname, SQLITE_TEXT);
00987     }
00988 #endif
00989     {
00990         char *fname;
00991         static void time_func(sqlite_func *context,
00992                               int argc, const char **argv);
00993 
00994         fname = "current_time_local";
00995         sqlite_create_function(x, fname, 0, time_func, (void *) 0);
00996         sqlite_function_type(x, fname, SQLITE_TEXT);
00997         fname = "current_time_utc";
00998         sqlite_create_function(x, fname, 0, time_func, (void *) 1);
00999         sqlite_function_type(x, fname, SQLITE_TEXT);
01000         fname = "current_date_local";
01001         sqlite_create_function(x, fname, 0, time_func, (void *) 2);
01002         sqlite_function_type(x, fname, SQLITE_TEXT);
01003         fname = "current_date_utc";
01004         sqlite_create_function(x, fname, 0, time_func, (void *) 3);
01005         sqlite_function_type(x, fname, SQLITE_TEXT);
01006         fname = "current_datetime_local";
01007         sqlite_create_function(x, fname, 0, time_func, (void *) 4);
01008         sqlite_function_type(x, fname, SQLITE_TEXT);
01009         fname = "current_datetime_utc";
01010         sqlite_create_function(x, fname, 0, time_func, (void *) 5);
01011         sqlite_function_type(x, fname, SQLITE_TEXT);
01012         fname = "current_timestamp_local";
01013         sqlite_create_function(x, fname, 0, time_func, (void *) 4);
01014         sqlite_function_type(x, fname, SQLITE_TEXT);
01015         fname = "current_timestamp_utc";
01016         sqlite_create_function(x, fname, 0, time_func, (void *) 5);
01017         sqlite_function_type(x, fname, SQLITE_TEXT);
01018     }
01019     return SQLITE_OK;
01020 }
01021 
01031 static void
01032 freerows(char **rowp)
01033 {
01034     int size, i;
01035 
01036     if (!rowp) {
01037         return;
01038     }
01039     --rowp;
01040     size = (int) rowp[0];
01041     for (i = 1; i <= size; i++) {
01042         freep(&rowp[i]);
01043     }
01044     freep(&rowp);
01045 }
01046 
01056 static int
01057 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar)
01058 {
01059     char *p, *q;
01060     int testsign = 0, result;
01061 
01062 #ifdef SQLITE_UTF8
01063     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
01064 #else
01065     result = SQL_VARCHAR;
01066 #endif
01067     if (!typename) {
01068         return result;
01069     }
01070     q = p = xmalloc(strlen(typename) + 1);
01071     if (!p) {
01072         return result;
01073     }
01074     strcpy(p, typename);
01075     while (*q) {
01076         *q = TOLOWER(*q);
01077         ++q;
01078     }
01079     if (strncmp(p, "inter", 5) == 0) {
01080     } else if (strncmp(p, "int", 3) == 0 ||
01081         strncmp(p, "mediumint", 9) == 0) {
01082         testsign = 1;
01083         result = SQL_INTEGER;
01084     } else if (strncmp(p, "numeric", 7) == 0) {
01085         result = SQL_DOUBLE;
01086     } else if (strncmp(p, "tinyint", 7) == 0) {
01087         testsign = 1;
01088         result = SQL_TINYINT;
01089     } else if (strncmp(p, "smallint", 8) == 0) {
01090         testsign = 1;
01091         result = SQL_SMALLINT;
01092     } else if (strncmp(p, "float", 5) == 0) {
01093         result = SQL_DOUBLE;
01094     } else if (strncmp(p, "double", 6) == 0 ||
01095         strncmp(p, "real", 4) == 0) {
01096         result = SQL_DOUBLE;
01097     } else if (strncmp(p, "timestamp", 9) == 0) {
01098 #ifdef SQL_TYPE_TIMESTAMP
01099         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
01100 #else
01101         result = SQL_TIMESTAMP;
01102 #endif
01103     } else if (strncmp(p, "datetime", 8) == 0) {
01104 #ifdef SQL_TYPE_TIMESTAMP
01105         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
01106 #else
01107         result = SQL_TIMESTAMP;
01108 #endif
01109     } else if (strncmp(p, "time", 4) == 0) {
01110 #ifdef SQL_TYPE_TIME
01111         result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
01112 #else
01113         result = SQL_TIME;
01114 #endif
01115     } else if (strncmp(p, "date", 4) == 0) {
01116 #ifdef SQL_TYPE_DATE
01117         result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
01118 #else
01119         result = SQL_DATE;
01120 #endif
01121 #ifdef SQL_LONGVARCHAR
01122     } else if (strncmp(p, "text", 4) == 0) {
01123 #ifdef SQLITE_UTF8
01124         result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
01125 #else
01126         result = SQL_LONGVARCHAR;
01127 #endif
01128 #ifdef SQLITE_UTF8
01129     } else if (strncmp(p, "wtext", 5) == 0 ||
01130                strncmp(p, "wvarchar", 8) == 0 ||
01131                strncmp(p, "longwvarchar", 12) == 0) {
01132         result = SQL_WLONGVARCHAR;
01133 #endif
01134 #endif
01135 #if HAVE_ENCDEC
01136     } else if (strncmp(p, "binary", 6) == 0 ||
01137                strncmp(p, "varbinary", 9) == 0 ||
01138                strncmp(p, "bytea", 5) == 0 ||
01139                strncmp(p, "blob", 4) == 0 ||
01140                strncmp(p, "tinyblob", 8) == 0 ||
01141                strncmp(p, "mediumblob", 10) == 0) {
01142         result = SQL_VARBINARY;
01143     } else if (strncmp(p, "longbinary", 10) == 0 ||
01144                strncmp(p, "longvarbinary", 13) == 0 ||
01145                strncmp(p, "longblob", 8) == 0) {
01146         result = SQL_LONGVARBINARY;
01147 #endif
01148     }
01149     if (nosign) {
01150         if (testsign) {
01151             *nosign = strstr(p, "unsigned") != NULL;
01152         } else {
01153             *nosign = 1;
01154         }
01155     }
01156     xfree(p);
01157     return result;
01158 }
01159 
01169 static void
01170 getmd(const char *typename, int sqltype, int *mp, int *dp)
01171 {
01172     int m = 0, d = 0;
01173 
01174     switch (sqltype) {
01175     case SQL_INTEGER:      m = 10; d = 9; break;
01176     case SQL_TINYINT:      m = 4; d = 3; break;
01177     case SQL_SMALLINT:     m = 6; d = 5; break;
01178     case SQL_FLOAT:        m = 25; d = 24; break;
01179     case SQL_DOUBLE:       m = 54; d = 53; break;
01180     case SQL_VARCHAR:      m = 255; d = 0; break;
01181 #ifdef SQLITE_UTF8
01182 #ifdef SQL_WVARCHAR
01183     case SQL_WVARCHAR:     m = 255; d = 0; break;
01184 #endif
01185 #endif
01186 #ifdef SQL_TYPE_DATE
01187     case SQL_TYPE_DATE:
01188 #endif
01189     case SQL_DATE:         m = 10; d = 0; break;
01190 #ifdef SQL_TYPE_TIME
01191     case SQL_TYPE_TIME:
01192 #endif
01193     case SQL_TIME:         m = 8; d = 0; break;
01194 #ifdef SQL_TYPE_TIMESTAMP
01195     case SQL_TYPE_TIMESTAMP:
01196 #endif
01197     case SQL_TIMESTAMP:    m = 32; d = 0; break;
01198 #ifdef SQL_LONGVARCHAR
01199     case SQL_LONGVARCHAR : m = 65536; d = 0; break;
01200 #endif
01201 #ifdef SQLITE_UTF8
01202 #ifdef SQL_WLONGVARCHAR
01203     case SQL_WLONGVARCHAR: m = 65536; d = 0; break;
01204 #endif
01205 #endif
01206 #if HAVE_ENCDEC
01207     case SQL_VARBINARY: m = 255; d = 0; break;
01208     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
01209 #endif
01210     }
01211     if (m && typename) {
01212         int mm, dd;
01213 
01214         if (sscanf(typename, "%*[^(](%d)", &mm) == 1) {
01215             m = d = mm;
01216         } else if (sscanf(typename, "%*[^(](%d,%d)", &mm, &dd) == 2) {
01217             m = mm;
01218             d = dd;
01219         }
01220     }
01221     if (mp) {
01222         *mp = m;
01223     }
01224     if (dp) {
01225         *dp = d;
01226     }
01227 }
01228 
01238 static int
01239 mapdeftype(int type, int stype, int nosign, int nowchar)
01240 {
01241     if (type == SQL_C_DEFAULT) {
01242         switch (stype) {
01243         case SQL_INTEGER:
01244             type = nosign > 0 ? SQL_C_ULONG : SQL_C_LONG;
01245             break;
01246         case SQL_TINYINT:
01247             type = nosign > 0 ? SQL_C_UTINYINT : SQL_C_TINYINT;
01248             break;
01249         case SQL_SMALLINT:
01250             type = nosign > 0 ? SQL_C_USHORT : SQL_C_SHORT;
01251             break;
01252         case SQL_FLOAT:
01253             type = SQL_C_FLOAT;
01254             break;
01255         case SQL_DOUBLE:
01256             type = SQL_C_DOUBLE;
01257             break;
01258         case SQL_TIMESTAMP:
01259             type = SQL_C_TIMESTAMP;
01260             break;
01261         case SQL_TIME:
01262             type = SQL_C_TIME;
01263             break;
01264         case SQL_DATE:
01265             type = SQL_C_DATE;
01266             break;
01267 #ifdef SQL_C_TYPE_TIMESTAMP
01268         case SQL_TYPE_TIMESTAMP:
01269             type = SQL_C_TYPE_TIMESTAMP;
01270             break;
01271 #endif
01272 #ifdef SQL_C_TYPE_TIME
01273         case SQL_TYPE_TIME:
01274             type = SQL_C_TYPE_TIME;
01275             break;
01276 #endif
01277 #ifdef SQL_C_TYPE_DATE
01278         case SQL_TYPE_DATE:
01279             type = SQL_C_TYPE_DATE;
01280             break;
01281 #endif
01282 #ifdef SQLITE_UTF8
01283         case SQL_WVARCHAR:
01284         case SQL_WCHAR:
01285 #ifdef SQL_WLONGVARCHAR
01286         case SQL_WLONGVARCHAR:
01287 #endif
01288             type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
01289             break;
01290 #endif
01291 #if HAVE_ENCDEC
01292         case SQL_BINARY:
01293         case SQL_VARBINARY:
01294         case SQL_LONGVARBINARY:
01295             type = SQL_C_BINARY;
01296             break;
01297 #endif
01298         default:
01299             type = SQL_C_CHAR;
01300         }
01301     }
01302 #ifdef SQLITE_UTF8
01303     if (nowchar) {
01304         switch (type) {
01305         case SQL_C_WCHAR:
01306             type = SQL_C_CHAR;
01307             break;
01308         }
01309     }
01310 #endif
01311     return type;
01312 }
01313 
01326 static char *
01327 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg,
01328          int version, char ***namepp)
01329 {
01330     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
01331     int np = 0, size;
01332     char **npp = NULL, *ncp = NULL;
01333 
01334     *errmsg = NULL;
01335     if (sqlLen != SQL_NTS) {
01336         qz = q = xmalloc(sqlLen + 1);
01337         if (!qz) {
01338             return NULL;
01339         }
01340         memcpy(q, sql, sqlLen);
01341         q[sqlLen] = '\0';
01342         size = sqlLen * 4;
01343     } else {
01344         size = strlen(sql) * 4;
01345     }
01346     size += sizeof (char *) - 1;
01347     size &= ~(sizeof (char *) - 1);
01348     p = xmalloc(2 * size + size * sizeof (char *) / 2);
01349     if (!p) {
01350 errout:
01351         freep(&qz);
01352         return NULL;
01353     }
01354     out = p;
01355     npp = (char **) (out + size);
01356     ncp = (char *) npp + size * sizeof (char *) / 2;
01357     while (*q) {
01358         switch (*q) {
01359         case '\'':
01360         case '\"':
01361             if (q == inq) {
01362                 inq = NULL;
01363             } else if (!inq) {
01364                 inq = q + 1;
01365 
01366                 while (*inq) {
01367                     if (*inq == *q) {
01368                         if (inq[1] == *q) {
01369                             inq++;
01370                         } else {
01371                             break;
01372                         }
01373                     }
01374                     inq++;
01375                 }
01376             }
01377             *p++ = *q;
01378             break;
01379         case '?':
01380             if (inq) {
01381                 *p++ = *q;
01382             } else {
01383                 *p++ = '%';
01384                 *p++ = 'Q';
01385                 npp[np] = ncp;
01386                 *ncp = '\0';
01387                 ++ncp;
01388                 np++;
01389             }
01390             break;
01391         case ':':               /* ORACLE-style named parameter */
01392         case '@':               /* ADO.NET-style named parameter */
01393             if (inq) {
01394                 *p++ = *q;
01395             } else {
01396                 int n = -1;
01397 
01398                 do {
01399                    ++q;
01400                    ++n;
01401                 } while (*q && ISIDCHAR(*q));
01402                 if (n > 0) {
01403                     *p++ = '%';
01404                     *p++ = 'Q';
01405                     npp[np] = ncp;
01406                     memcpy(ncp, q - n, n);
01407                     ncp[n] = '\0';
01408                     ncp += n + 1;
01409                     np++;
01410                 }
01411                 --q;
01412             }
01413             break;
01414         case ';':
01415             if (inq) {
01416                 *p++ = *q;
01417             } else {
01418                 do {
01419                     ++q;
01420                 } while (*q && ISSPACE(*q));
01421                 if (*q) {               
01422                     freep(&out);
01423                     *errmsg = "only one SQL statement allowed";
01424                     goto errout;
01425                 }
01426                 --q;
01427             }
01428             break;
01429         case '%':
01430             *p++ = '%';
01431             *p++ = '%';
01432             break;
01433         case '{':
01434             /* deal with {d 'YYYY-MM-DD'}, {t ...}, and {ts ...} */
01435             if (!inq) {
01436                 char *end = q + 1;
01437 
01438                 while (*end && *end != '}') {
01439                     ++end;
01440                 }
01441                 if (*end == '}') {
01442                     char *start = q + 1;
01443                     char *end2 = end - 1;
01444 
01445                     while (start < end2 && *start != '\'') {
01446                         ++start;
01447                     }
01448                     while (end2 > start && *end2 != '\'') {
01449                         --end2;
01450                     }
01451                     if (*start == '\'' && *end2 == '\'') {
01452                         while (start <= end2) {
01453                             *p++ = *start;
01454                             ++start;
01455                         }
01456                         q = end;
01457                         break;
01458                     }
01459                 }
01460             }
01461             /* FALL THROUGH */
01462         default:
01463             *p++ = *q;
01464         }
01465         ++q;
01466     }
01467     freep(&qz);
01468     *p = '\0';
01469     if (nparam) {
01470         *nparam = np;
01471     }
01472     if (isselect) {
01473         p = out;
01474         while (*p && ISSPACE(*q)) {
01475             ++p;
01476         }
01477         *isselect = strncasecmp(p, "select", 6) == 0;
01478     }
01479     if (namepp) {
01480         *namepp = npp;
01481     }
01482     return out;
01483 }
01484 
01493 static int
01494 findcol(char **cols, int ncols, char *name)
01495 {
01496     int i;
01497 
01498     if (cols) {
01499         for (i = 0; i < ncols; i++) {
01500             if (strcmp(cols[i], name) == 0) {
01501                 return i;
01502             }
01503         }
01504     }
01505     return -1;
01506 }
01507 
01525 static void
01526 fixupdyncols(STMT *s, sqlite *sqlite, const char **types)
01527 {
01528     int i, k, pk, t, r, nrows, ncols, doautoinc = 0;
01529     char **rowp, *flagp, flags[128];
01530 
01531     if (!s->dyncols) {
01532         return;
01533     }
01534     /* fixup labels */
01535     if (s->dcols > 1) {
01536         char *table = s->dyncols[0].table;
01537 
01538         for (i = 1; table[0] && i < s->dcols; i++) {
01539             if (strcmp(s->dyncols[i].table, table)) {
01540                 break;
01541             }
01542         }
01543         if (i >= s->dcols) {
01544             for (i = 0; i < s->dcols; i++) {
01545                 s->dyncols[i].label = s->dyncols[i].column;
01546             }
01547         }
01548     } else if (s->dcols == 1) {
01549         s->dyncols[0].label = s->dyncols[0].column;
01550     }
01551     if (types) {
01552         for (i = 0; i < s->dcols; i++) {
01553             freep(&s->dyncols[i].typename);
01554             s->dyncols[i].typename = xstrdup(types[i] ? types[i] : "text");
01555             s->dyncols[i].type =
01556                 mapsqltype(types[i], &s->dyncols[i].nosign, *s->ov3,
01557                            s->nowchar);
01558             getmd(types[i], s->dyncols[i].type, &s->dyncols[i].size, NULL);
01559 #ifdef SQL_LONGVARCHAR
01560             if (s->dyncols[i].type == SQL_VARCHAR &&
01561                 s->dyncols[i].size > 255) {
01562                 s->dyncols[i].type = SQL_LONGVARCHAR;
01563             }
01564 #endif
01565 #ifdef SQLITE_UTF8
01566 #ifdef SQL_WLONGVARCHAR
01567             if (s->dyncols[i].type == SQL_WVARCHAR &&
01568                 s->dyncols[i].size > 255) {
01569                 s->dyncols[i].type = SQL_WLONGVARCHAR;
01570             }
01571 #endif
01572 #endif
01573 #if HAVE_ENCDEC
01574             if (s->dyncols[i].type == SQL_VARBINARY &&
01575                 s->dyncols[i].size > 255) {
01576                 s->dyncols[i].type = SQL_LONGVARBINARY;
01577             }
01578 #endif
01579             if (types[i] && strlen(types[i]) == 7 &&
01580                 strncasecmp(types[i], "integer", 7) == 0) {
01581                 doautoinc++;
01582                 s->dyncols[i].autoinc = -1;
01583             } else {
01584                 s->dyncols[i].autoinc = 0;
01585             }
01586         }
01587         if (!doautoinc) {
01588             return;
01589         }
01590     }
01591     if (s->dcols > array_size(flags)) {
01592         flagp = xmalloc(sizeof (flags[0]) * s->dcols);
01593         if (flagp == NULL) {
01594             return;
01595         }
01596     } else {
01597         flagp = flags;
01598     }
01599     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
01600     for (i = 0; i < s->dcols; i++) {
01601         s->dyncols[i].autoinc = 0;
01602     }
01603     for (i = 0; i < s->dcols; i++) {
01604         int ret, lastpk = -1, autoinccount = 0;
01605 
01606         if (!s->dyncols[i].table[0]) {
01607             continue;
01608         }
01609         if (flagp[i]) {
01610             continue;
01611         }
01612         ret = sqlite_get_table_printf(sqlite,
01613                                       "PRAGMA table_info('%q')", &rowp,
01614                                       &nrows, &ncols, NULL,
01615                                       s->dyncols[i].table);
01616         if (ret != SQLITE_OK) {
01617             continue;
01618         }
01619         k = findcol(rowp, ncols, "name");
01620         t = findcol(rowp, ncols, "type");
01621         pk = findcol(rowp, ncols, "pk");
01622         if (k < 0 || t < 0) {
01623             goto freet;
01624         }
01625         for (r = 1; r <= nrows; r++) {
01626             int m;
01627 
01628             for (m = i; m < s->dcols; m++) {
01629                 if (!flagp[m] &&
01630                     strcmp(s->dyncols[m].column, rowp[r * ncols + k]) == 0 &&
01631                     strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
01632                     char *typename = rowp[r * ncols + t];
01633 
01634                     flagp[m] = 1;
01635                     freep(&s->dyncols[m].typename);
01636                     s->dyncols[m].typename = xstrdup(typename);
01637                     s->dyncols[m].type =
01638                         mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
01639                                    s->nowchar);
01640                     getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
01641                           NULL);
01642 #ifdef SQL_LONGVARCHAR
01643                     if (s->dyncols[m].type == SQL_VARCHAR &&
01644                         s->dyncols[m].size > 255) {
01645                         s->dyncols[m].type = SQL_LONGVARCHAR;
01646                     }
01647 #endif
01648 #ifdef SQLITE_UTF8
01649 #ifdef SQL_WLONGVARCHAR
01650                     if (s->dyncols[i].type == SQL_WVARCHAR &&
01651                         s->dyncols[i].size > 255) {
01652                         s->dyncols[i].type = SQL_WLONGVARCHAR;
01653                     }
01654 #endif
01655 #endif
01656 #if HAVE_ENCDEC
01657                     if (s->dyncols[i].type == SQL_VARBINARY &&
01658                         s->dyncols[i].size > 255) {
01659                         s->dyncols[i].type = SQL_LONGVARBINARY;
01660                     }
01661 #endif
01662                     if (pk >= 0 && strcmp(rowp[r * ncols + pk], "1") == 0) {
01663                         if (++autoinccount > 1) {
01664                             if (lastpk >= 0) {
01665                                 s->dyncols[lastpk].autoinc = 0;
01666                                 lastpk = -1;
01667                             }
01668                         } else {
01669                             lastpk = m;
01670                             if (strlen(typename) == 7 &&
01671                                 strncasecmp(typename, "integer", 7) == 0) {
01672                                 s->dyncols[m].autoinc = 1;
01673                             }
01674                         }
01675                     }
01676                 }
01677             }
01678         }
01679 freet:
01680         sqlite_free_table(rowp);
01681     }
01682     if (flagp != flags) {
01683         freep(&flagp);
01684     }
01685 }
01686 
01694 static int
01695 getmdays(int year, int month)
01696 {
01697     static const int mdays[] = {
01698         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
01699     };
01700     int mday;
01701 
01702     if (month < 1) {
01703         return 0;
01704     }
01705     mday = mdays[(month - 1) % 12];
01706     if (mday == 28 && year % 4 == 0 &&
01707         (!(year % 100 == 0) || year % 400 == 0)) {
01708         mday++;
01709     }
01710     return mday;
01711 }
01712 
01723 static int
01724 str2date(char *str, DATE_STRUCT *ds)
01725 {
01726     int i, err = 0;
01727     char *p, *q;
01728 
01729     ds->year = ds->month = ds->day = 0;
01730     p = str;
01731     while (*p && !ISDIGIT(*p)) {
01732         ++p;
01733     }
01734     q = p;
01735     i = 0;
01736     while (*q && !ISDIGIT(*q)) {
01737         ++i;
01738         ++q;
01739     }
01740     if (i >= 8) {
01741         char buf[8];
01742 
01743         strncpy(buf, p + 0, 4); buf[4] = '\0';
01744         ds->year = strtol(buf, NULL, 10);
01745         strncpy(buf, p + 4, 2); buf[2] = '\0';
01746         ds->month = strtol(buf, NULL, 10);
01747         strncpy(buf, p + 6, 2); buf[2] = '\0';
01748         ds->day = strtol(buf, NULL, 10);
01749         goto done;
01750     }
01751     i = 0;
01752     while (i < 3) {
01753         int n;
01754 
01755         q = NULL; 
01756         n = strtol(p, &q, 10);
01757         if (!q || q == p) {
01758             if (*q == '\0') {
01759                 if (i == 0) {
01760                     err = 1;
01761                 }
01762                 goto done;
01763             }
01764         }
01765         if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
01766             switch (i) {
01767             case 0: ds->year = n; break;
01768             case 1: ds->month = n; break;
01769             case 2: ds->day = n; break;
01770             }
01771             ++i;
01772             if (*q) {
01773                 ++q;
01774             }
01775         } else {
01776             i = 0;
01777             while (*q && !ISDIGIT(*q)) {
01778                 ++q;
01779             }
01780         }
01781         p = q;
01782     }
01783 done:
01784     /* final check for overflow */
01785     if (err ||
01786         ds->month < 1 || ds->month > 12 ||
01787         ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
01788         return -1;
01789     }
01790     return 0;
01791 }
01792 
01803 static int
01804 str2time(char *str, TIME_STRUCT *ts)
01805 {
01806     int i, err = 0;
01807     char *p, *q;
01808 
01809     ts->hour = ts->minute = ts->second = 0;
01810     p = str;
01811     while (*p && !ISDIGIT(*p)) {
01812         ++p;
01813     }
01814     q = p;
01815     i = 0;
01816     while (*q && ISDIGIT(*q)) {
01817         ++i;
01818         ++q;
01819     }
01820     if (i >= 6) {
01821         char buf[4];
01822 
01823         strncpy(buf, p + 0, 2); buf[2] = '\0';
01824         ts->hour = strtol(buf, NULL, 10);
01825         strncpy(buf, p + 2, 2); buf[2] = '\0';
01826         ts->minute = strtol(buf, NULL, 10);
01827         strncpy(buf, p + 4, 2); buf[2] = '\0';
01828         ts->second = strtol(buf, NULL, 10);
01829         goto done;
01830     }
01831     i = 0;
01832     while (i < 3) {
01833         int n;
01834 
01835         q = NULL; 
01836         n = strtol(p, &q, 10);
01837         if (!q || q == p) {
01838             if (*q == '\0') {
01839                 if (i == 0) {
01840                     err = 1;
01841                 }
01842                 goto done;
01843             }
01844         }
01845         if (*q == ':' || *q == '\0' || i == 2) {
01846             switch (i) {
01847             case 0: ts->hour = n; break;
01848             case 1: ts->minute = n; break;
01849             case 2: ts->second = n; break;
01850             }
01851             ++i;
01852             if (*q) {
01853                 ++q;
01854             }
01855         } else {
01856             i = 0;
01857             while (*q && !ISDIGIT(*q)) {
01858                 ++q;
01859             }
01860         }
01861         p = q;
01862     }
01863 done:
01864     /* final check for overflow */
01865     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
01866         return -1;
01867     }
01868     return 0;
01869 }
01870 
01886 static int
01887 str2timestamp(char *str, TIMESTAMP_STRUCT *tss)
01888 {
01889     int i, m, n, err = 0;
01890     char *p, *q, in = '\0';
01891 
01892     tss->year = tss->month = tss->day = 0;
01893     tss->hour = tss->minute = tss->second = 0;
01894     tss->fraction = 0;
01895     p = str;
01896     while (*p && !ISDIGIT(*p)) {
01897         ++p;
01898     }
01899     q = p;
01900     i = 0;
01901     while (*q && ISDIGIT(*q)) {
01902         ++i;
01903         ++q;
01904     }
01905     if (i >= 14) {
01906         char buf[16];
01907 
01908         strncpy(buf, p + 0, 4); buf[4] = '\0';
01909         tss->year = strtol(buf, NULL, 10);
01910         strncpy(buf, p + 4, 2); buf[2] = '\0';
01911         tss->month = strtol(buf, NULL, 10);
01912         strncpy(buf, p + 6, 2); buf[2] = '\0';
01913         tss->day = strtol(buf, NULL, 10);
01914         strncpy(buf, p + 8, 2); buf[2] = '\0';
01915         tss->hour = strtol(buf, NULL, 10);
01916         strncpy(buf, p + 10, 2); buf[2] = '\0';
01917         tss->minute = strtol(buf, NULL, 10);
01918         strncpy(buf, p + 12, 2); buf[2] = '\0';
01919         tss->second = strtol(buf, NULL, 10);
01920         if (i > 14) {
01921             m = i - 14;
01922             strncpy(buf, p + 14, m);
01923             while (m < 9) {
01924                 buf[m] = '0';
01925                 ++m;
01926             }
01927             buf[m] = '\0';
01928             tss->fraction = strtol(buf, NULL, 0);
01929         }
01930         m = 7;
01931         goto done;
01932     }
01933     m = i = 0;
01934     while ((m & 7) != 7) {
01935         q = NULL; 
01936         n = strtol(p, &q, 10);
01937         if (!q || q == p) {
01938             if (*q == '\0') {
01939                 if (m < 1) {
01940                     err = 1;
01941                 }
01942                 goto done;
01943             }
01944         }
01945         if (in == '\0') {
01946             switch (*q) {
01947             case '-':
01948             case '/':
01949                 if ((m & 1) == 0) {
01950                     in = *q;
01951                     i = 0;
01952                 }
01953                 break;
01954             case ':':
01955                 if ((m & 2) == 0) {
01956                     in = *q;
01957                     i = 0;
01958                 }
01959                 break;
01960             case ' ':
01961             case '.':
01962                 break;
01963             default:
01964                 in = '\0';
01965                 i = 0;
01966                 break;
01967             }
01968         }
01969         switch (in) {
01970         case '-':
01971         case '/':
01972             switch (i) {
01973             case 0: tss->year = n; break;
01974             case 1: tss->month = n; break;
01975             case 2: tss->day = n; break;
01976             }
01977             if (++i >= 3) {
01978                 i = 0;
01979                 m |= 1;
01980                 if (!(m & 2)) {
01981                     m |= 8;
01982                 }
01983                 goto skip;
01984             } else {
01985                 ++q;
01986             }
01987             break;
01988         case ':':
01989             switch (i) {
01990             case 0: tss->hour = n; break;
01991             case 1: tss->minute = n; break;
01992             case 2: tss->second = n; break;
01993             }
01994             if (++i >= 3) {
01995                 i = 0;
01996                 m |= 2;
01997                 if (*q == '.') {
01998                     in = '.';
01999                     goto skip2;
02000                 }
02001                 if (*q == ' ') {
02002                     if ((m & 1) == 0) {
02003                         char *e = NULL;
02004 
02005                         strtol(q + 1, &e, 10);
02006                         if (e && *e == '-') {
02007                             goto skip;
02008                         }
02009                     }
02010                     in = '.';
02011                     goto skip2;
02012                 }
02013                 goto skip;
02014             } else {
02015                 ++q;
02016             }
02017             break;
02018         case '.':
02019             if (++i >= 1) {
02020                 int ndig = q - p;
02021 
02022                 if (p[0] == '+' || p[0] == '-') {
02023                     ndig--;
02024                 }
02025                 while (ndig < 9) {
02026                     n = n * 10;
02027                     ++ndig;
02028                 }
02029                 tss->fraction = n;
02030                 m |= 4;
02031                 i = 0;
02032             }
02033         default:
02034         skip:
02035             in = '\0';
02036         skip2:
02037             while (*q && !ISDIGIT(*q)) {
02038                 ++q;
02039             }
02040         }
02041         p = q;
02042     }
02043     if ((m & 7) > 1 && (m & 8)) {
02044         /* ISO8601 timezone */
02045         if (p > str && ISDIGIT(*p)) {
02046             int nn, sign;
02047 
02048             q = p - 1;
02049             if (*q != '+' && *q != '-') {
02050                 goto done;
02051             }
02052             sign = *q == '+' ? -1 : 1;
02053             q = NULL;
02054             n = strtol(p, &q, 10);
02055             if (!q || *q++ != ':' || !ISDIGIT(*q)) {
02056                 goto done;
02057             }
02058             p = q;
02059             q = NULL;
02060             nn = strtol(p, &q, 0);
02061             tss->minute += nn * sign;
02062             if ((SQLSMALLINT) tss->minute < 0) {
02063                 tss->hour -= 1;
02064                 tss->minute += 60;
02065             } else if (tss->minute >= 60) {
02066                 tss->hour += 1;
02067                 tss->minute -= 60;
02068             }
02069             tss->hour += n * sign;
02070             if ((SQLSMALLINT) tss->hour < 0) {
02071                 tss->day -= 1;
02072                 tss->hour += 24;
02073             } else if (tss->hour >= 24) {
02074                 tss->day += 1;
02075                 tss->hour -= 24;
02076             }
02077             if ((short) tss->day < 1 || tss->day >= 28) {
02078                 int mday, pday, pmon;
02079 
02080                 mday = getmdays(tss->year, tss->month);
02081                 pmon = tss->month - 1;
02082                 if (pmon < 1) {
02083                     pmon = 12;
02084                 }
02085                 pday = getmdays(tss->year, pmon);
02086                 if ((SQLSMALLINT) tss->day < 1) {
02087                     tss->month -= 1;
02088                     tss->day = pday;
02089                 } else if (tss->day > mday) {
02090                     tss->month += 1;
02091                     tss->day = 1;
02092                 }
02093                 if ((SQLSMALLINT) tss->month < 1) {
02094                     tss->year -= 1;
02095                     tss->month = 12;
02096                 } else if (tss->month > 12) {
02097                     tss->year += 1;
02098                     tss->month = 1;
02099                 }
02100             }
02101         }
02102     }
02103 done:
02104     /* final check for overflow */
02105     if (err ||
02106         tss->month < 1 || tss->month > 12 ||
02107         tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
02108         tss->hour > 23 || tss->minute > 60 || tss->second > 60) {
02109         return -1;
02110     }
02111     return (m & 7) < 1 ? -1 : 0;
02112 }
02113 
02120 static int
02121 getbool(char *string)
02122 {
02123     if (string) {
02124         return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
02125     }
02126     return 0;
02127 }
02128 
02129 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
02130 
02135 static void
02136 dbtrace(void *arg, const char *msg)
02137 {
02138     DBC *d = (DBC *) arg;
02139 
02140     if (msg && d->trace) {
02141         int len = strlen(msg);
02142 
02143         if (len > 0) {
02144             char *end = "\n";
02145 
02146             if (msg[len - 1] != ';') {
02147                 end = ";\n";
02148             }
02149             fprintf(d->trace, "%s%s", msg, end);
02150             fflush(d->trace);
02151         }
02152     }
02153 }
02154 
02161 static void
02162 dbtracerc(DBC *d, int rc, char *err)
02163 {
02164     if (rc != SQLITE_OK && d->trace) {
02165         fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
02166         fprintf(d->trace, err ? ": %s\n" : "\n", err);
02167         fflush(d->trace);
02168     }
02169 }
02170 #else
02171 
02172 #define dbtracerc(a,b,c)
02173 
02174 #endif
02175 
02186 static SQLRETURN
02187 dbopen(DBC *d, char *name, char *dsn, char *sflag, char *busy)
02188 {
02189     char *errp = NULL, *endp = NULL;
02190     int tmp, busyto = 1000;
02191 
02192     if (d->sqlite) {
02193         sqlite_close(d->sqlite);
02194         d->sqlite = NULL;
02195     }
02196     d->sqlite = sqlite_open(name, 0, &errp);
02197     if (d->sqlite == NULL) {
02198 connfail:
02199         setstatd(d, -1, errp ? errp : "connect failed",
02200                  (*d->ov3) ? "HY000" : "S1000");
02201         if (errp) {
02202             sqlite_freemem(errp);
02203             errp = NULL;
02204         }
02205         return SQL_ERROR;
02206     }
02207     if (errp) {
02208         sqlite_freemem(errp);
02209         errp = NULL;
02210     }
02211 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
02212     if (d->trace) {
02213         sqlite_trace(d->sqlite, dbtrace, d);
02214     }
02215 #endif
02216     d->step_enable = getbool(sflag);
02217     d->curtype = d->step_enable ?
02218         SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
02219     tmp = strtol(busy, &endp, 0);
02220     if (endp && *endp == '\0' && endp != busy) {
02221         busyto = tmp;
02222     }
02223     if (busyto < 1 || busyto > 1000000) {
02224         busyto = 1000000;
02225     }
02226     d->timeout = busyto;
02227     if (setsqliteopts(d->sqlite, d) != SQLITE_OK) {
02228         sqlite_close(d->sqlite);
02229         d->sqlite = NULL;
02230         goto connfail;
02231     }
02232     freep(&d->dbname);
02233     d->dbname = xstrdup(name);
02234     freep(&d->dsn);
02235     d->dsn = xstrdup(dsn);
02236     return SQL_SUCCESS;
02237 }
02238 
02245 static int
02246 vm_step(STMT *s)
02247 {
02248     DBC *d = (DBC *) s->dbc;
02249     char **rowd = NULL, *errp = NULL;
02250     const char **values, **cols;
02251     int i, ncols, rc;
02252 
02253     if (s != d->vm_stmt || !s->vm) {
02254         setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
02255         return SQL_ERROR;
02256     }
02257     rc = sqlite_step(s->vm, &ncols, &values, &cols);
02258     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
02259         ++d->vm_rownum;
02260         if (d->vm_rownum == 0 && cols && ncols > 0) {
02261             int size;
02262             char *p;
02263             COL *dyncols;
02264 
02265             for (i = size = 0; i < ncols; i++) {
02266                 size += 3 + 3 * strlen(cols[i]);
02267             }
02268             dyncols = xmalloc(ncols * sizeof (COL) + size);
02269             if (!dyncols) {
02270                 freedyncols(s);
02271                 s->ncols = 0;
02272                 sqlite_finalize(s->vm, NULL);
02273                 s->vm = NULL;
02274                 d->vm_stmt = NULL;
02275                 return nomem(s);
02276             }
02277             p = (char *) (dyncols + ncols);
02278             for (i = 0; i < ncols; i++) {
02279                 char *q;
02280 
02281                 dyncols[i].db = ((DBC *) (s->dbc))->dbname;
02282                 strcpy(p, cols[i]);
02283                 dyncols[i].label = p;
02284                 p += strlen(p) + 1;
02285                 q = strchr(cols[i], '.');
02286                 if (q) {
02287                     dyncols[i].table = p;
02288                     strncpy(p, cols[i], q - cols[i]);
02289                     p[q - cols[i]] = '\0';
02290                     p += strlen(p) + 1;
02291                     strcpy(p, q + 1);
02292                     dyncols[i].column = p;
02293                     p += strlen(p) + 1;
02294                 } else {
02295                     dyncols[i].table = "";
02296                     strcpy(p, cols[i]);
02297                     dyncols[i].column = p;
02298                     p += strlen(p) + 1;
02299                 }
02300 #ifdef SQL_LONGVARCHAR
02301                 dyncols[i].type = SQL_LONGVARCHAR;
02302                 dyncols[i].size = 65536;
02303 #else
02304                 dyncols[i].type = SQL_VARCHAR;
02305                 dyncols[i].size = 255;
02306 #endif
02307                 dyncols[i].index = i;
02308                 dyncols[i].scale = 0;
02309                 dyncols[i].prec = 0;
02310                 dyncols[i].nosign = 1;
02311                 dyncols[i].autoinc = -1;
02312                 dyncols[i].typename = NULL;
02313             }
02314             freedyncols(s);
02315             s->ncols = s->dcols = ncols;
02316             s->dyncols = s->cols = dyncols;
02317             fixupdyncols(s, d->sqlite, cols + ncols);
02318             mkbindcols(s, s->ncols);
02319         }
02320         if (!cols || ncols <= 0) {
02321             goto killvm;
02322         }
02323         if (!values) {
02324             if (rc == SQLITE_DONE) {
02325                 freeresult(s, 0);
02326                 s->nrows = 0;
02327                 sqlite_finalize(s->vm, NULL);
02328                 s->vm = NULL;
02329                 d->vm_stmt = NULL;
02330                 return SQL_SUCCESS;
02331             }
02332             goto killvm;
02333         }
02334         rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
02335         if (rowd) {
02336             rowd[0] = (char *) (ncols * 2);
02337             ++rowd;
02338             for (i = 0; i < ncols; i++) {
02339                 rowd[i] = NULL;
02340                 rowd[i + ncols] = xstrdup(values[i]);
02341             }
02342             for (i = 0; i < ncols; i++) {
02343                 if (values[i] && !rowd[i + ncols]) {
02344                     freerows(rowd);
02345                     rowd = 0;
02346                     break;
02347                 }
02348             }
02349         }
02350         if (rowd) {
02351             freeresult(s, 0);
02352             s->nrows = 1;
02353             s->rows = rowd;
02354             if (rc == SQLITE_DONE) {
02355                 sqlite_finalize(s->vm, NULL);
02356                 s->vm = NULL;
02357                 d->vm_stmt = NULL;
02358             }
02359             return SQL_SUCCESS;
02360         }
02361     }
02362 killvm:
02363     sqlite_finalize(s->vm, &errp);
02364     s->vm = NULL;
02365     d->vm_stmt = NULL;
02366     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
02367             errp ? errp : "unknown error", rc);
02368     if (errp) {
02369         sqlite_freemem(errp);
02370         errp = NULL;
02371     }
02372     return SQL_ERROR;   
02373 }
02374 
02380 static void
02381 vm_end(STMT *s)
02382 {
02383     DBC *d;
02384 
02385     if (!s || !s->vm) {
02386         return;
02387     }
02388     d = (DBC *) s->dbc;
02389     sqlite_finalize(s->vm, NULL);
02390     s->vm = NULL;
02391     d->vm_stmt = NULL;
02392 }
02393 
02399 static void
02400 vm_end_if(STMT *s)
02401 {
02402     DBC *d = (DBC *) s->dbc;
02403 
02404     if (d && d->vm_stmt == s) {
02405         vm_end(s);
02406     }
02407 }
02408 
02416 static SQLRETURN
02417 vm_start(STMT *s, char **params)
02418 {
02419     DBC *d = (DBC *) s->dbc;
02420     char *errp = NULL, *sql = NULL;
02421     const char *endp;
02422     sqlite_vm *vm;
02423     int rc;
02424 
02425     sql = sqlite_vmprintf(s->query, (char *) params);
02426     if (!sql) {
02427         return nomem(s);
02428     }
02429     rc = sqlite_compile(d->sqlite, sql, &endp, &vm, &errp);
02430     dbtracerc(d, rc, errp);
02431     sqlite_freemem(sql);
02432     if (rc != SQLITE_OK) {
02433         setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
02434                 errp ? errp : "unknown error", rc);
02435         if (errp) {
02436             sqlite_freemem(errp);
02437             errp = NULL;
02438         }
02439         return SQL_ERROR;
02440     }
02441     s->vm = vm;
02442     d->vm_stmt = s;
02443     d->vm_rownum = -1;
02444     return SQL_SUCCESS;
02445 }
02446 
02451 SQLRETURN SQL_API
02452 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
02453 {
02454     return drvunimplstmt(stmt);
02455 }
02456 
02457 #ifndef SQLITE_UTF8
02458 
02462 SQLRETURN SQL_API
02463 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
02464                SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
02465                SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
02466 {
02467     if (env == SQL_NULL_HENV) {
02468         return SQL_INVALID_HANDLE;
02469     }
02470     return SQL_ERROR;
02471 }
02472 #endif
02473 
02474 #ifdef SQLITE_UTF8
02475 
02479 SQLRETURN SQL_API
02480 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
02481                 SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
02482                 SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
02483 {
02484     if (env == SQL_NULL_HENV) {
02485         return SQL_INVALID_HANDLE;
02486     }
02487     return SQL_ERROR;
02488 }
02489 #endif
02490 
02491 #ifndef SQLITE_UTF8
02492 
02496 SQLRETURN SQL_API
02497 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
02498            SQLSMALLINT descmax, SQLSMALLINT *desclenp,
02499            SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
02500 {
02501     if (env == SQL_NULL_HENV) {
02502         return SQL_INVALID_HANDLE;
02503     }
02504     return SQL_ERROR;
02505 }
02506 #endif
02507 
02508 #ifdef SQLITE_UTF8
02509 
02513 SQLRETURN SQL_API
02514 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
02515             SQLSMALLINT descmax, SQLSMALLINT *desclenp,
02516             SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
02517 {
02518     if (env == SQL_NULL_HENV) {
02519         return SQL_INVALID_HANDLE;
02520     }
02521     return SQL_ERROR;
02522 }
02523 #endif
02524 
02525 #ifndef SQLITE_UTF8
02526 
02530 SQLRETURN SQL_API
02531 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
02532                  SQLCHAR *connout, SQLSMALLINT connoutMax,
02533                  SQLSMALLINT *connoutLen)
02534 {
02535     return drvunimpldbc(dbc);
02536 }
02537 #endif
02538 
02539 #ifdef SQLITE_UTF8
02540 
02544 SQLRETURN SQL_API
02545 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
02546                   SQLWCHAR *connout, SQLSMALLINT connoutMax,
02547                   SQLSMALLINT *connoutLen)
02548 {
02549     return drvunimpldbc(dbc);
02550 }
02551 #endif
02552 
02560 static void
02561 time_func(sqlite_func *context, int argc, const char **argv)
02562 {
02563     char buf[128];
02564     int what = (int) sqlite_user_data(context);
02565 #ifdef _WIN32
02566     SYSTEMTIME st;
02567 
02568     if (what & 1) {
02569         GetSystemTime(&st);
02570     } else {
02571         GetLocalTime(&st);
02572     }
02573     if (what & 4) {
02574         sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
02575                 st.wYear, st.wMonth, st.wDay,
02576                 st.wHour, st.wMinute, st.wSecond);
02577     } else if (what & 2) {
02578         sprintf(buf, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
02579     } else {
02580         sprintf(buf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
02581     }
02582 #else
02583     time_t t;
02584     struct tm tm;
02585 
02586     time(&t);
02587     if (what & 1) {
02588 #ifdef HAVE_GMTIME_R
02589         gmtime_r(&t, &tm);
02590 #else
02591         tm = *gmtime(&t);
02592 #endif
02593     } else {
02594 #ifdef HAVE_LOCALTIME_R
02595         localtime_r(&t, &tm);
02596 #else
02597         tm = *localtime(&t);
02598 #endif
02599     }
02600     if (what & 4) {
02601         sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
02602                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
02603                 tm.tm_hour, tm.tm_min, tm.tm_sec);
02604     } else if (what & 2) {
02605         sprintf(buf, "%04d-%02d-%02d",
02606                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
02607     } else {
02608         sprintf(buf, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
02609     }
02610 #endif
02611     sqlite_set_result_string(context, buf, -1);
02612 }
02613 
02614 #if HAVE_ENCDEC
02615 static const char hexdigits[] = "0123456789ABCDEFabcdef";
02616 
02624 static void
02625 hextobin_func(sqlite_func *context, int argc, const char **argv)
02626 {
02627     int i, len;
02628     char *bin, *p;
02629 
02630     if (argc < 1) {
02631         return;
02632     }
02633     if (!argv[0]) {
02634         sqlite_set_result_string(context, "NULL", 4);
02635         return;
02636     }
02637     len = strlen(argv[0]) / 2;
02638     bin = xmalloc(len + 1);
02639     if (!bin) {
02640 oom:
02641         sqlite_set_result_error(context, "out of memory", -1);
02642         return;
02643     }
02644     if (len <= 0) {
02645         sqlite_set_result_string(context, bin, 0);
02646         freep(&bin);
02647         return;
02648     }
02649     for (i = 0, p = (char *) argv[0]; i < len; i++) {
02650         char *x;
02651         int v;
02652 
02653         if (!*p || !(x = strchr(hexdigits, *p))) {
02654             goto converr;
02655         }
02656         v = x - hexdigits;
02657         bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
02658         ++p;
02659         if (!*p || !(x = strchr(hexdigits, *p))) {
02660 converr:
02661             freep(&bin);
02662             sqlite_set_result_error(context, "conversion error", -1);
02663             return;
02664         }
02665         v = x - hexdigits;
02666         bin[i] |= (v >= 16) ? (v - 6) : v;
02667         ++p;
02668     }
02669     i = sqlite_encode_binary(bin, len, 0);
02670     p = xmalloc(i + 1);
02671     if (!p) {
02672         freep(&bin);
02673         goto oom;
02674     }
02675     i = sqlite_encode_binary(bin, len, p);
02676     sqlite_set_result_string(context, p, i);
02677     freep(&bin);
02678     freep(&p);
02679 }
02680 
02688 static void
02689 bintohex_func(sqlite_func *context, int argc, const char **argv)
02690 {
02691     int i, k, len;
02692     char *bin, *p;
02693 
02694     if (argc < 1) {
02695         return;
02696     }
02697     if (!argv[0]) {
02698 empty:
02699         sqlite_set_result_string(context, "", 0);
02700         return;
02701     }
02702     bin = xmalloc(strlen(argv[0]) + 1);
02703     if (!bin) {
02704 oom:
02705         sqlite_set_result_error(context, "out of memory", -1);
02706         return;
02707     }
02708     len = sqlite_decode_binary(argv[0], bin);
02709     if (len < 0) {
02710         freep(&bin);
02711         sqlite_set_result_error(context, "error decoding binary data", -1);
02712         return;
02713     }
02714     if (len == 0) {
02715         goto empty;
02716     }
02717     p = xmalloc(len * 2 + 1);
02718     if (!p) {
02719         goto oom;
02720     }
02721     for (i = 0, k = 0; i < len; i++) {
02722         p[k++] = hexdigits[(bin[i] >> 4) & 0x0f];
02723         p[k++] = hexdigits[bin[i] & 0x0f];
02724     }
02725     p[k] = '\0';
02726     sqlite_set_result_string(context, p, k);
02727     freep(&bin);
02728     freep(&p);
02729 }
02730 
02738 static SQLRETURN
02739 hextobin(STMT *s, BINDPARM *p)
02740 {
02741     int i, len = strlen(p->param) / 2;
02742     char *bin = xmalloc(len + 1), *pp;
02743 
02744     if (!bin) {
02745         return nomem(s);
02746     }
02747     if (len <= 0) {
02748         bin[0] = '\0';
02749         if (p->param == p->ind) {
02750             freep(&p->param);
02751         }
02752         p->param = p->ind = bin;
02753         p->len = 0;
02754         return SQL_SUCCESS;
02755     }
02756     for (i = 0, pp = (char *) p->param; i < len; i++) {
02757         char *x;
02758         int v;
02759 
02760         if (!*pp || !(x = strchr(hexdigits, *pp))) {
02761             goto converr;
02762         }
02763         v = x - hexdigits;
02764         bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
02765         ++pp;
02766         if (!*pp || !(x = strchr(hexdigits, *pp))) {
02767 converr:
02768             freep(&bin);
02769             setstat(s, -1, "conversion error", (*s->ov3) ? "HY000" : "S1000");
02770             return SQL_ERROR;
02771         }
02772         v = x - hexdigits;
02773         bin[i] |= (v >= 16) ? (v - 6) : v;
02774         ++pp;
02775     }
02776     i = sqlite_encode_binary(bin, len, 0);
02777     pp = xmalloc(i + 1);
02778     if (!pp) {
02779         freep(&bin);
02780         return nomem(s);
02781     }
02782     p->len = sqlite_encode_binary(bin, len, pp);
02783     if (p->param == p->ind) {
02784         freep(&p->param);
02785     }
02786     p->param = p->ind = pp;
02787     freep(&bin);
02788     return SQL_SUCCESS;
02789 }
02790 #endif
02791 
02800 SQLRETURN SQL_API
02801 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLINTEGER len)
02802 {
02803     STMT *s;
02804     int i, dlen, done = 0;
02805     BINDPARM *p;
02806 
02807     if (stmt == SQL_NULL_HSTMT) {
02808         return SQL_INVALID_HANDLE;
02809     }
02810     s = (STMT *) stmt;
02811     if (!s->query || s->nparams <= 0) {
02812 seqerr:
02813         setstat(s, -1, "sequence error", "HY010");
02814         return SQL_ERROR;
02815     }
02816     for (i = 0; i < s->nparams; i++) {
02817         p = &s->bindparms[i];
02818         if (p->need) {
02819             int type = mapdeftype(p->type, p->stype, -1, s->nowchar);
02820 
02821             if (len == SQL_NULL_DATA) {
02822                 freep(&p->param);
02823                 p->ind = &p->len;
02824                 p->len = SQL_NULL_DATA;
02825                 p->need = 0;
02826             } else
02827 #if HAVE_ENCDEC
02828             if (type == SQL_C_BINARY) {
02829                 if (len <= 0) {
02830                     setstat(s, -1, "invalid length", "HY090");
02831                     return SQL_ERROR;
02832                 }
02833                 goto putd;
02834             } else
02835 #endif
02836 #ifdef SQLITE_UTF8
02837             if (type != SQL_C_CHAR && type != SQL_C_WCHAR)
02838 #else
02839             if (type != SQL_C_CHAR)
02840 #endif
02841             {
02842                 int size = 0;
02843 
02844                 switch (type) {
02845                 case SQL_C_TINYINT:
02846                 case SQL_C_UTINYINT:
02847                 case SQL_C_STINYINT:
02848                     size = sizeof (char);
02849                     break;
02850                 case SQL_C_SHORT:
02851                 case SQL_C_USHORT:
02852                 case SQL_C_SSHORT:
02853                     size = sizeof (short);
02854                     break;
02855                 case SQL_C_LONG:
02856                 case SQL_C_ULONG:
02857                 case SQL_C_SLONG:
02858                     size = sizeof (long);
02859                     break;
02860                 case SQL_C_FLOAT:
02861                     size = sizeof (float);
02862                     break;
02863                 case SQL_C_DOUBLE:
02864                     size = sizeof (double);
02865                     break;
02866 #ifdef SQL_C_TYPE_DATE
02867                 case SQL_C_TYPE_DATE:
02868 #endif
02869                 case SQL_C_DATE:
02870                     size = sizeof (DATE_STRUCT);
02871                     break;
02872 #ifdef SQL_C_TYPE_DATE
02873                 case SQL_C_TYPE_TIME:
02874 #endif
02875                 case SQL_C_TIME:
02876                     size = sizeof (TIME_STRUCT);
02877                     break;
02878 #ifdef SQL_C_TYPE_DATE
02879                 case SQL_C_TYPE_TIMESTAMP:
02880 #endif
02881                 case SQL_C_TIMESTAMP:
02882                     size = sizeof (TIMESTAMP_STRUCT);
02883                     break;
02884                 }
02885                 freep(&p->param);
02886                 p->param = xmalloc(size);
02887                 if (!p->param) {
02888                     return nomem(s);
02889                 }
02890                 memcpy(p->param, data, size);
02891                 p->len = size;
02892                 p->need = 0;
02893             } else if (len == SQL_NTS) {
02894                 char *dp = data;
02895 
02896 #ifdef SQLITE_UTF8
02897                 if (p->type == SQL_C_WCHAR) {
02898                     dp = uc_to_utf(data, len);
02899                     if (!dp) {
02900                         return nomem(s);
02901                     }
02902                 }
02903 #endif
02904                 dlen = strlen(dp);
02905                 freep(&p->param);
02906                 p->param = xmalloc(dlen + 1);
02907                 if (!p->param) {
02908 #ifdef SQLITE_UTF8
02909                     if (dp != data) {
02910                         uc_free(dp);
02911                     }
02912 #endif
02913                     return nomem(s);
02914                 }
02915                 strcpy(p->param, dp);
02916 #ifdef SQLITE_UTF8
02917                 if (dp != data) {
02918                     uc_free(dp);
02919                 }
02920 #endif
02921                 p->len = dlen;
02922                 p->need = 0;
02923             } else if (len <= 0) {
02924                 setstat(s, -1, "invalid length", "HY090");
02925                 return SQL_ERROR;
02926             } else {
02927 #if HAVE_ENCDEC
02928 putd:
02929 #endif
02930                 dlen = min(p->len - p->offs, len);
02931                 if (!p->param) {
02932                     setstat(s, -1, "no memory for parameter", "HY013");
02933                     return SQL_ERROR;
02934                 }
02935                 memcpy((char *) p->param + p->offs, data, dlen);
02936                 p->offs += dlen;
02937                 if (p->offs >= p->len) {
02938 #ifdef SQLITE_UTF8
02939                     if (p->type == SQL_C_WCHAR) {
02940                         char *dp = uc_to_utf(p->param, p->len);
02941                         char *np;
02942                         int nlen;
02943 
02944                         if (!dp) {
02945                             return nomem(s);
02946                         }
02947                         nlen = strlen(dp);
02948                         np = xmalloc(nlen + 1);
02949                         if (!np) {
02950                             uc_free(dp);
02951                             return nomem(s);
02952                         }
02953                         strcpy(np, dp);
02954                         uc_free(dp);
02955                         freep(&p->param);
02956                         p->param = p->ind = np;
02957                         p->len = nlen;
02958                     } else {
02959                         *((char *) p->param + p->len) = '\0';
02960                     }
02961 #else
02962                     *((char *) p->param + p->len) = '\0';
02963 #endif
02964 #if HAVE_ENCDEC
02965                     if ((p->stype == SQL_BINARY ||
02966                          p->stype == SQL_VARBINARY ||
02967                          p->stype == SQL_LONGVARBINARY) &&
02968 #ifdef SQLITE_UTF8
02969                         (type == SQL_C_CHAR || type == SQL_C_WCHAR)
02970 #else
02971                         type == SQL_C_CHAR
02972 #endif
02973                        ) {
02974                         if (hextobin(s, p) != SQL_SUCCESS) {
02975                             return SQL_ERROR;
02976                         }
02977                     } else if (type == SQL_C_BINARY) {
02978                         int bsize;
02979                         char *bin;
02980 
02981                         bsize = sqlite_encode_binary(p->param, p->len, 0);
02982                         bin = xmalloc(bsize + 1);
02983                         if (!bin) {
02984                             return nomem(s);
02985                         }
02986                         p->len = sqlite_encode_binary(p->param, p->len, bin);
02987                         freep(&p->param);
02988                         p->param = p->ind = bin;
02989                     }
02990 #endif
02991                     p->need = 0;
02992                 }
02993             }
02994             done = 1;
02995             break;
02996         }
02997     }
02998     if (!done) {
02999         goto seqerr;
03000     }
03001     for (i = 0; i < s->nparams; i++) {
03002         p = &s->bindparms[i];
03003         if (p->need) {
03004             return SQL_NEED_DATA;
03005         }
03006     }
03007     return drvexecute(stmt);
03008 }
03009 
03015 static SQLRETURN
03016 freeparams(STMT *s)
03017 {
03018     if (s->bindparms) {
03019         int n;
03020 
03021         for (n = 0; n < s->nbindparms; n++) {
03022             if (s->bindparms[n].ind && s->bindparms[n].param) {
03023                 freep(&s->bindparms[n].param);
03024             }
03025             memset(&s->bindparms[n], 0, sizeof (BINDPARM));
03026         }
03027     }
03028     return SQL_SUCCESS;
03029 }
03030 
03031 /* see doc on top */
03032 
03033 static SQLRETURN
03034 substparam(STMT *s, int pnum, char **out, int *size)
03035 {
03036     char buf[256];
03037     int type, len = 0;
03038     BINDPARM *p;
03039     double dval;
03040 
03041     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
03042         goto error;
03043     }
03044     p = &s->bindparms[pnum];
03045     type = mapdeftype(p->type, p->stype, -1, s->nowchar);
03046     if (p->need) {
03047         if (!p->param) {
03048             p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
03049             if (p->len <= 0 && p->len != SQL_NTS && p->len != SQL_NULL_DATA) {
03050                 setstat(s, -1, "invalid length", "HY009");
03051                 return SQL_ERROR;
03052             }
03053             if (p->len > 0) {
03054                 p->param = xmalloc(p->len + 1);
03055                 if (!p->param) {
03056                     return nomem(s);
03057                 }
03058             }
03059         }
03060         return SQL_NEED_DATA;
03061     }
03062     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
03063         strcpy(buf, "NULL");
03064         goto bind;
03065     }
03066     switch (type) {
03067     case SQL_C_CHAR:
03068 #ifdef SQLITE_UTF8
03069     case SQL_C_WCHAR:
03070 #endif
03071 #if HAVE_ENCDEC
03072     case SQL_C_BINARY:
03073 #endif
03074         break;
03075     case SQL_C_UTINYINT:
03076         sprintf(buf, "%d", *((unsigned char *) p->param));
03077         goto bind;
03078     case SQL_C_TINYINT:
03079     case SQL_C_STINYINT:
03080         sprintf(buf, "%d", *((char *) p->param));
03081         goto bind;
03082     case SQL_C_USHORT:
03083         sprintf(buf, "%d", *((unsigned short *) p->param));
03084         goto bind;
03085     case SQL_C_SHORT:
03086     case SQL_C_SSHORT:
03087         sprintf(buf, "%d", *((short *) p->param));
03088         goto bind;
03089     case SQL_C_ULONG:
03090     case SQL_C_LONG:
03091     case SQL_C_SLONG:
03092         sprintf(buf, "%ld", *((long *) p->param));
03093         goto bind;
03094     case SQL_C_FLOAT:
03095         dval = *((float *) p->param);
03096         goto dodouble;
03097     case SQL_C_DOUBLE:
03098         dval = *((double *) p->param);
03099     dodouble:
03100 #if defined(HAVE_SQLITEMPRINTF) && HAVE_SQLITEMPRINTF
03101         {
03102             char *buf2 = sqlite_mprintf("%.16g", dval);
03103 
03104             if (buf2) {
03105                 strcpy(buf, buf2);
03106                 sqlite_freemem(buf2);
03107             } else {
03108                 strcpy(buf, "NULL");
03109             }
03110         }
03111 #else
03112         ln_sprintfg(buf, dval);
03113 #endif
03114         goto bind;
03115 #ifdef SQL_C_TYPE_DATE
03116     case SQL_C_TYPE_DATE:
03117 #endif
03118     case SQL_C_DATE:
03119         sprintf(buf, "%04d-%02d-%02d",
03120                 ((DATE_STRUCT *) p->param)->year,
03121                 ((DATE_STRUCT *) p->param)->month,
03122                 ((DATE_STRUCT *) p->param)->day);
03123         goto bind;
03124 #ifdef SQL_C_TYPE_TIME
03125     case SQL_C_TYPE_TIME:
03126 #endif
03127     case SQL_C_TIME:
03128         sprintf(buf, "%02d:%02d:%02d",
03129                 ((TIME_STRUCT *) p->param)->hour,
03130                 ((TIME_STRUCT *) p->param)->minute,
03131                 ((TIME_STRUCT *) p->param)->second);
03132         goto bind;
03133 #ifdef SQL_C_TYPE_TIMESTAMP
03134     case SQL_C_TYPE_TIMESTAMP:
03135 #endif
03136     case SQL_C_TIMESTAMP:
03137         sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%d",
03138                 ((TIMESTAMP_STRUCT *) p->param)->year,
03139                 ((TIMESTAMP_STRUCT *) p->param)->month,
03140                 ((TIMESTAMP_STRUCT *) p->param)->day,
03141                 ((TIMESTAMP_STRUCT *) p->param)->hour,
03142                 ((TIMESTAMP_STRUCT *) p->param)->minute,
03143                 ((TIMESTAMP_STRUCT *) p->param)->second,
03144                 (int) ((TIMESTAMP_STRUCT *) p->param)->fraction);
03145     bind:
03146         if (out) {
03147             strcpy(*out, buf);
03148             *out += strlen(buf) + 1;
03149         }
03150         if (size) {
03151             *size += strlen(buf) + 1;
03152         }
03153         return SQL_SUCCESS;
03154     default:
03155         goto error;
03156     }
03157     if (p->ind) {
03158         len = p->len;
03159     } else if (!p->lenp) {
03160         if (!(p->max != SQL_NTS || p->max == SQL_SETPARAM_VALUE_MAX)) {
03161 error:
03162             setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
03163             return SQL_ERROR;
03164         }
03165     } else {
03166         len = *p->lenp == SQL_NTS ? strlen(p->param) : *p->lenp;
03167     }
03168     if (out) {
03169         if (p->max == SQL_NTS || p->max == SQL_SETPARAM_VALUE_MAX) {
03170             strcpy(*out, p->param);
03171             *out += strlen(p->param) + 1;
03172         } else {
03173             if (len > 0) {
03174                 memcpy(*out, p->param, len);
03175                 *out += len;
03176             }
03177             **out = '\0';
03178             *out += 1;
03179         }
03180     }
03181     if (size) {
03182         if (p->max == SQL_NTS || p->max == SQL_SETPARAM_VALUE_MAX) {
03183             *size += strlen(p->param) + 1;
03184         } else {
03185             *size += len > 0 ? len + 1 : 1;
03186         }
03187     }
03188     return SQL_SUCCESS;
03189 }
03190 
03206 static SQLRETURN
03207 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
03208              SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
03209              SQLSMALLINT scale,
03210              SQLPOINTER data, SQLINTEGER buflen, SQLINTEGER *len)
03211 {
03212     STMT *s;
03213     BINDPARM *p;
03214 
03215     if (stmt == SQL_NULL_HSTMT) {
03216         return SQL_INVALID_HANDLE;
03217     }
03218     s = (STMT *) stmt;
03219     if (pnum == 0) {
03220         setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
03221         return SQL_ERROR;
03222     }
03223     if (!data && (!len || (*len != SQL_NULL_DATA &&
03224                            *len > SQL_LEN_DATA_AT_EXEC_OFFSET))) {
03225         setstat(s, -1, "invalid buffer", "HY003");
03226         return SQL_ERROR;
03227     }
03228     if (len && *len < 0 && *len > SQL_LEN_DATA_AT_EXEC_OFFSET &&
03229         *len != SQL_NTS && *len != SQL_NULL_DATA) {
03230         setstat(s, -1, "invalid length reference", "HY009");
03231         return SQL_ERROR;
03232     }
03233 #if 0
03234     if (iotype != SQL_PARAM_INPUT)
03235         return SQL_ERROR;
03236 #endif
03237     --pnum;
03238     if (s->bindparms) {
03239         if (pnum >= s->nbindparms) {
03240             BINDPARM *newparms;
03241             
03242             newparms = xrealloc(s->bindparms,
03243                                 (pnum + 1) * sizeof (BINDPARM));
03244             if (!newparms) {
03245 outofmem:
03246                 return nomem(s);
03247             }
03248             s->bindparms = newparms;
03249             memset(&s->bindparms[s->nbindparms], 0,
03250                    (pnum - s->nbindparms) * sizeof (BINDPARM));
03251             s->nbindparms = pnum + 1;
03252         }
03253     } else {
03254         int npar = max(10, pnum + 1);
03255 
03256         s->bindparms = xmalloc(npar * sizeof (BINDPARM));
03257         if (!s->bindparms) {
03258             goto outofmem;
03259         }
03260         memset(s->bindparms, 0, npar * sizeof (BINDPARM));
03261         s->nbindparms = npar;
03262     }
03263     p = &s->bindparms[pnum];
03264     p->type = buftype; 
03265     p->stype = ptype; 
03266     p->max = buflen;
03267     p->inc = buflen;
03268     p->lenp = (int *) len;
03269     p->offs = 0;
03270     p->len = 0;
03271     if (p->lenp) {
03272 #ifdef SQLITE_UTF8
03273         if (buftype == SQL_C_WCHAR) {
03274             if (*p->lenp == SQL_NTS) {
03275                 p->max = buflen = uc_strlen(data);
03276             } else if (*p->lenp >= 0) {
03277                 p->max = buflen = *p->lenp;
03278             }
03279         } else
03280 #endif
03281         if (buftype == SQL_C_CHAR) {
03282             if (*p->lenp == SQL_NTS) {
03283                 p->len = p->max = buflen = strlen(data);
03284             } else if (*p->lenp >= 0) {
03285                 p->len = p->max = buflen = *p->lenp;
03286             }
03287         }
03288     }
03289     if (p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
03290         p->param = NULL;
03291         p->ind = data;
03292         p->need = 1;
03293     } else if (p->lenp && *p->lenp == SQL_NULL_DATA) {
03294         p->param = NULL;
03295         p->ind = NULL;
03296         p->need = 0;
03297     } else {
03298 #if HAVE_ENCDEC
03299         int chkbin = 1;
03300 #endif
03301 
03302 #ifdef SQLITE_UTF8
03303         if (buftype == SQL_C_WCHAR) {
03304             p->ind = uc_to_utf(data, buflen);
03305             if (!p->ind) {
03306                 goto outofmem;
03307             }
03308             p->param = p->ind;
03309             p->len = strlen(p->param);
03310         } else
03311 #endif
03312 #if HAVE_ENCDEC
03313         if (buftype == SQL_C_BINARY) {
03314             int bsize;
03315 
03316             p->len = *p->lenp;
03317             if (p->len < 0) {
03318                 setstat(s, -1, "invalid length reference", "HY009");
03319                 return SQL_ERROR;
03320             }
03321             bsize = sqlite_encode_binary(data, p->len, 0);
03322             p->ind = xmalloc(bsize + 1);
03323             if (!p->ind) {
03324                 goto outofmem;
03325             }
03326             p->param = p->ind;
03327             p->len = sqlite_encode_binary(data, p->len, p->param);
03328             chkbin = 0;
03329         } else
03330 #endif
03331         if (buftype == SQL_C_CHAR) {
03332             p->param = data;
03333             p->ind = NULL;
03334         } else {
03335             p->param = data;
03336             p->ind = NULL;
03337 #if HAVE_ENCDEC
03338             chkbin = 0;
03339 #endif
03340         }
03341 #if HAVE_ENCDEC
03342         if (chkbin) {
03343             if (ptype == SQL_BINARY ||
03344                 ptype == SQL_VARBINARY ||
03345                 ptype == SQL_LONGVARBINARY) {
03346                 if (hextobin(s, p) != SQL_SUCCESS) {
03347                     return SQL_ERROR;
03348                 }
03349             }
03350         }
03351 #endif
03352         p->need = 0;
03353     }
03354     p->param0 = p->param;
03355     return SQL_SUCCESS;
03356 }
03357 
03373 SQLRETURN SQL_API
03374 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
03375                  SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
03376                  SQLSMALLINT scale,
03377                  SQLPOINTER data, SQLINTEGER buflen, SQLINTEGER *len)
03378 {
03379     return drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
03380                         scale, data, buflen, len);
03381 }
03382 
03396 SQLRETURN SQL_API
03397 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
03398              SQLSMALLINT ptype, SQLUINTEGER lenprec,
03399              SQLSMALLINT scale, SQLPOINTER val,
03400              SQLINTEGER *lenp)
03401 {
03402     return drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
03403                         lenprec, scale, val, 0, lenp);
03404 }
03405 
03413 SQLRETURN SQL_API
03414 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
03415 {
03416     STMT *s;
03417     SQLSMALLINT dummy;
03418 
03419     if (stmt == SQL_NULL_HSTMT) {
03420         return SQL_INVALID_HANDLE;
03421     }
03422     s = (STMT *) stmt;
03423     if (!nparam) {
03424         nparam = &dummy;
03425     }
03426     *nparam = s->nparams;
03427     return SQL_SUCCESS;
03428 }
03429 
03437 SQLRETURN SQL_API
03438 SQLParamData(SQLHSTMT stmt, SQLPOINTER *p)
03439 {
03440     STMT *s;
03441     int i;
03442     SQLPOINTER dummy;
03443 
03444     if (stmt == SQL_NULL_HSTMT) {
03445         return SQL_INVALID_HANDLE;
03446     }
03447     s = (STMT *) stmt;
03448     if (!p) {
03449         p = &dummy;
03450     }
03451     for (i = 0; i < s->nparams; i++) {
03452         if (s->bindparms[i].need) {
03453             *p = (SQLPOINTER) s->bindparms[i].ind;
03454             return SQL_NEED_DATA;
03455         }
03456     }
03457     return SQL_SUCCESS;
03458 }    
03459 
03471 SQLRETURN SQL_API
03472 SQLDescribeParam(SQLHSTMT stmt, UWORD pnum, SWORD *dtype, UDWORD *size,
03473                  SWORD *decdigits, SWORD *nullable)
03474 {
03475     STMT *s;
03476 
03477     if (stmt == SQL_NULL_HSTMT) {
03478         return SQL_INVALID_HANDLE;
03479     }
03480     s = (STMT *) stmt;
03481     --pnum;
03482     if (pnum >= s->nparams) {
03483         setstat(s, -1, "invalid parameter index",
03484                 (*s->ov3) ? "HY000" : "S1000");
03485         return SQL_ERROR;
03486     }
03487     if (dtype) {
03488 #ifdef SQL_LONGVARCHAR
03489 #ifdef SQLITE_UTF8
03490         *dtype = s->nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
03491 #else
03492         *dtype = SQL_LONGVARCHAR;
03493 #endif
03494 #else
03495 #ifdef SQLITE_UTF8
03496         *dtype = s->nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
03497 #else
03498         *dtype = SQL_VARCHAR;
03499 #endif
03500 #endif
03501     }
03502     if (size) {
03503 #ifdef SQL_LONGVARCHAR
03504         *size = 65536;
03505 #else
03506         *size = 255;
03507 #endif
03508     }
03509     if (decdigits) {
03510         *decdigits = 0;
03511     }
03512     if (nullable) {
03513         *nullable = SQL_NULLABLE;
03514     }
03515     return SQL_SUCCESS;
03516 }
03517 
03531 SQLRETURN SQL_API
03532 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
03533             SQLSMALLINT sqltype, SQLUINTEGER coldef,
03534             SQLSMALLINT scale, SQLPOINTER val, SQLINTEGER *nval)
03535 {
03536     return drvbindparam(stmt, par, SQL_PARAM_INPUT,
03537                         type, sqltype, coldef, scale, val,
03538                         SQL_SETPARAM_VALUE_MAX, nval);
03539 }
03540 
03545 SQLRETURN SQL_API
03546 SQLParamOptions(SQLHSTMT stmt, UDWORD rows, UDWORD *rowp)
03547 {
03548     return drvunimplstmt(stmt);
03549 }
03550 
03551 #ifndef SQLITE_UTF8
03552 
03556 SQLRETURN SQL_API
03557 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
03558                 SQLSMALLINT fieldid, SQLPOINTER value,
03559                 SQLINTEGER buflen, SQLINTEGER *strlen)
03560 {
03561     return SQL_ERROR;
03562 }
03563 #endif
03564 
03565 #ifdef SQLITE_UTF8
03566 
03570 SQLRETURN SQL_API
03571 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
03572                  SQLSMALLINT fieldid, SQLPOINTER value,
03573                  SQLINTEGER buflen, SQLINTEGER *strlen)
03574 {
03575     return SQL_ERROR;
03576 }
03577 #endif
03578 
03579 #ifndef SQLITE_UTF8
03580 
03584 SQLRETURN SQL_API
03585 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
03586                 SQLSMALLINT fieldid, SQLPOINTER value,
03587                 SQLINTEGER buflen)
03588 {
03589     return SQL_ERROR;
03590 }
03591 #endif
03592 
03593 #ifdef SQLITE_UTF8
03594 
03598 SQLRETURN SQL_API
03599 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
03600                  SQLSMALLINT fieldid, SQLPOINTER value,
03601                  SQLINTEGER buflen)
03602 {
03603     return SQL_ERROR;
03604 }
03605 #endif
03606 
03607 #ifndef SQLITE_UTF8
03608 
03612 SQLRETURN SQL_API
03613 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
03614               SQLCHAR *name, SQLSMALLINT buflen,
03615               SQLSMALLINT *strlen, SQLSMALLINT *type,
03616               SQLSMALLINT *subtype, SQLINTEGER *len,
03617               SQLSMALLINT *prec, SQLSMALLINT *scale,
03618               SQLSMALLINT *nullable)
03619 {
03620     return SQL_ERROR;
03621 }
03622 #endif
03623 
03624 #ifdef SQLITE_UTF8
03625 
03629 SQLRETURN SQL_API
03630 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
03631                SQLWCHAR *name, SQLSMALLINT buflen,
03632                SQLSMALLINT *strlen, SQLSMALLINT *type,
03633                SQLSMALLINT *subtype, SQLINTEGER *len,
03634                SQLSMALLINT *prec, SQLSMALLINT *scale,
03635                SQLSMALLINT *nullable)
03636 {
03637     return SQL_ERROR;
03638 }
03639 #endif
03640 
03645 SQLRETURN SQL_API
03646 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
03647               SQLSMALLINT type, SQLSMALLINT subtype,
03648               SQLINTEGER len, SQLSMALLINT prec,
03649               SQLSMALLINT scale, SQLPOINTER data,
03650               SQLINTEGER *strlen, SQLINTEGER *indicator)
03651 {
03652     return SQL_ERROR;
03653 }
03654 
03663 static SQLRETURN
03664 mkresultset(HSTMT stmt, COL *colspec, int ncols)
03665 {
03666     STMT *s;
03667     DBC *d;
03668 
03669     if (stmt == SQL_NULL_HSTMT) {
03670         return SQL_INVALID_HANDLE;
03671     }
03672     s = (STMT *) stmt;
03673     if (s->dbc == SQL_NULL_HDBC) {
03674 noconn:
03675         return noconn(s);
03676     }
03677     d = (DBC *) s->dbc;
03678     if (!d->sqlite) {
03679         goto noconn;
03680     }
03681     vm_end_if(s);
03682     freeresult(s, 0);
03683     s->ncols = ncols;
03684     s->cols = colspec;
03685     mkbindcols(s, s->ncols);
03686     s->nrows = 0;
03687     s->rowp = -1;
03688     return SQL_SUCCESS;
03689 }
03690 
03695 static COL tablePrivSpec[] = {
03696     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03697     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
03698     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
03699     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
03700     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
03701     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
03702     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
03703 };
03704 
03705 #ifndef SQLITE_UTF8
03706 
03718 SQLRETURN SQL_API
03719 SQLTablePrivileges(SQLHSTMT stmt,
03720                    SQLCHAR *catalog, SQLSMALLINT catalogLen,
03721                    SQLCHAR *schema, SQLSMALLINT schemaLen,
03722                    SQLCHAR *table, SQLSMALLINT tableLen)
03723 {
03724     return mkresultset(stmt, tablePrivSpec, array_size(tablePrivSpec));
03725 }
03726 #endif
03727 
03728 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
03729 #ifdef SQLITE_UTF8
03730 
03742 SQLRETURN SQL_API
03743 SQLTablePrivilegesW(SQLHSTMT stmt,
03744                     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
03745                     SQLWCHAR *schema, SQLSMALLINT schemaLen,
03746                     SQLWCHAR *table, SQLSMALLINT tableLen)
03747 {
03748     return mkresultset(stmt, tablePrivSpec, array_size(tablePrivSpec));
03749 }
03750 #endif
03751 #endif
03752 
03757 static COL colPrivSpec[] = {
03758     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03759     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
03760     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
03761     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
03762     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
03763     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
03764     { "SYSTEM", "COLPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
03765 };
03766 
03767 #ifndef SQLITE_UTF8
03768 
03782 SQLRETURN SQL_API
03783 SQLColumnPrivileges(SQLHSTMT stmt,
03784                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
03785                     SQLCHAR *schema, SQLSMALLINT schemaLen,
03786                     SQLCHAR *table, SQLSMALLINT tableLen,
03787                     SQLCHAR *column, SQLSMALLINT columnLen)
03788 {
03789     return mkresultset(stmt, colPrivSpec, array_size(colPrivSpec));
03790 }
03791 #endif
03792 
03793 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
03794 #ifdef SQLITE_UTF8
03795 
03809 SQLRETURN SQL_API
03810 SQLColumnPrivilegesW(SQLHSTMT stmt,
03811                      SQLWCHAR *catalog, SQLSMALLINT catalogLen,
03812                      SQLWCHAR *schema, SQLSMALLINT schemaLen,
03813                      SQLWCHAR *table, SQLSMALLINT tableLen,
03814                      SQLWCHAR *column, SQLSMALLINT columnLen)
03815 {
03816     return mkresultset(stmt, colPrivSpec, array_size(colPrivSpec));
03817 }
03818 #endif
03819 #endif
03820 
03825 static COL pkeySpec[] = {
03826     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03827     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
03828     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
03829     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
03830     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
03831     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
03832 };
03833 
03846 static SQLRETURN
03847 drvprimarykeys(SQLHSTMT stmt,
03848                SQLCHAR *cat, SQLSMALLINT catLen,
03849                SQLCHAR *schema, SQLSMALLINT schemaLen,
03850                SQLCHAR *table, SQLSMALLINT tableLen)
03851 {
03852     STMT *s;
03853     DBC *d;
03854     SQLRETURN sret;
03855     int i, size, ret, nrows, ncols, offs, namec, uniquec;
03856     char **rowp, *errp = NULL, tname[512];
03857 
03858     sret = mkresultset(stmt, pkeySpec, array_size(pkeySpec));
03859     if (sret != SQL_SUCCESS) {
03860         return sret;
03861     }
03862     s = (STMT *) stmt;
03863     d = (DBC *) s->dbc;
03864     if (!table || table[0] == '\0' || table[0] == '%') {
03865         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
03866         return SQL_ERROR;
03867     }
03868     if (tableLen == SQL_NTS) {
03869         size = sizeof (tname) - 1;
03870     } else {
03871         size = min(sizeof (tname) - 1, tableLen);
03872     }
03873     strncpy(tname, table, size);
03874     tname[size] = '\0';
03875     ret = sqlite_get_table_printf(d->sqlite,
03876                                   "PRAGMA index_list('%q')", &rowp,
03877                                   &nrows, &ncols, &errp, tname);
03878     if (ret != SQLITE_OK) {
03879         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
03880                 errp ? errp : "unknown error", ret);
03881         if (errp) {
03882             sqlite_freemem(errp);
03883             errp = NULL;
03884         }
03885         return SQL_ERROR;
03886     }
03887     if (errp) {
03888         sqlite_freemem(errp);
03889         errp = NULL;
03890     }
03891     if (ncols * nrows <= 0) {
03892 nodata:
03893         sqlite_free_table(rowp);
03894         /* try table_info for integer primary keys */
03895         ret = sqlite_get_table_printf(d->sqlite,
03896                                       "PRAGMA table_info('%q')", &rowp,
03897                                       &nrows, &ncols, NULL, tname);
03898         if (ret == SQLITE_OK) {
03899             int typec, roffs;
03900 
03901             namec = findcol(rowp, ncols, "name");
03902             uniquec = findcol(rowp, ncols, "pk");
03903             typec = findcol(rowp, ncols, "type");
03904             if (namec < 0 || uniquec < 0 || typec < 0) {
03905                 goto nodata2;
03906             }
03907             for (i = 1; i <= nrows; i++) {
03908                 if (*rowp[i * ncols + uniquec] != '0' &&
03909                     strlen(rowp[i * ncols + typec]) == 7 &&
03910                     strncasecmp(rowp[i * ncols + typec], "integer", 7) == 0) {
03911                     break;
03912                 }
03913             }
03914             if (i > nrows) {
03915                 goto nodata2;
03916             }
03917             size = (1 + 1) * array_size(pkeySpec);
03918             s->rows = xmalloc((size + 1) * sizeof (char *));
03919             if (!s->rows) {
03920                 s->nrows = 0;
03921                 return nomem(s);
03922             }
03923             s->rows[0] = (char *) size;
03924             s->rows += 1;
03925             memset(s->rows, 0, sizeof (char *) * size);
03926             s->rowfree = freerows;
03927             s->nrows = 1;
03928             roffs = s->ncols;
03929             s->rows[roffs + 0] = xstrdup("");
03930             s->rows[roffs + 1] = xstrdup("");
03931             s->rows[roffs + 2] = xstrdup(tname);
03932             s->rows[roffs + 3] = xstrdup(rowp[i * ncols + namec]);
03933             s->rows[roffs + 4] = xstrdup("1");
03934 nodata2:
03935             sqlite_free_table(rowp);
03936         }
03937         return SQL_SUCCESS;
03938     }
03939     size = 0;
03940     namec = findcol(rowp, ncols, "name");
03941     uniquec = findcol(rowp, ncols, "unique");
03942     if (namec < 0 || uniquec < 0) {
03943         goto nodata;
03944     }
03945     for (i = 1; i <= nrows; i++) {
03946         int nnrows, nncols;
03947         char **rowpp;
03948 
03949         if (*rowp[i * ncols + uniquec] != '0') {
03950             ret = sqlite_get_table_printf(d->sqlite,
03951                                           "PRAGMA index_info('%q')", &rowpp,
03952                                           &nnrows, &nncols, NULL,
03953                                           rowp[i * ncols + namec]);
03954             if (ret == SQLITE_OK) {
03955                 size += nnrows;
03956                 sqlite_free_table(rowpp);
03957             }
03958         }
03959     }
03960     if (size == 0) {
03961         goto nodata;
03962     }
03963     s->nrows = size;
03964     size = (size + 1) * array_size(pkeySpec);
03965     s->rows = xmalloc((size + 1) * sizeof (char *));
03966     if (!s->rows) {
03967         s->nrows = 0;
03968         return nomem(s);
03969     }
03970     s->rows[0] = (char *) size;
03971     s->rows += 1;
03972     memset(s->rows, 0, sizeof (char *) * size);
03973     s->rowfree = freerows;
03974     offs = 0;
03975     for (i = 1; i <= nrows; i++) {
03976         int nnrows, nncols;
03977         char **rowpp;
03978 
03979         if (*rowp[i * ncols + uniquec] != '0') {
03980             int k;
03981 
03982             ret = sqlite_get_table_printf(d->sqlite,
03983                                           "PRAGMA index_info('%q')", &rowpp,
03984                                           &nnrows, &nncols, NULL,
03985                                           rowp[i * ncols + namec]);
03986             if (ret != SQLITE_OK) {
03987                 continue;
03988             }
03989             for (k = 0; nnrows && k < nncols; k++) {
03990                 if (strcmp(rowpp[k], "name") == 0) {
03991                     int m;
03992 
03993                     for (m = 1; m <= nnrows; m++) {
03994                         int roffs = (offs + m) * s->ncols;
03995 
03996                         s->rows[roffs + 0] = xstrdup("");
03997                         s->rows[roffs + 1] = xstrdup("");
03998                         s->rows[roffs + 2] = xstrdup(tname);
03999                         s->rows[roffs + 3] = xstrdup(rowpp[m * nncols + k]);
04000                         s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
04001                     }
04002                 } else if (strcmp(rowpp[k], "seqno") == 0) {
04003                     int m;
04004 
04005                     for (m = 1; m <= nnrows; m++) {
04006                         int roffs = (offs + m) * s->ncols;
04007                         int pos = m - 1;
04008                         char buf[32];
04009 
04010                         sscanf(rowpp[m * nncols + k], "%d", &pos);
04011                         sprintf(buf, "%d", pos + 1);
04012                         s->rows[roffs + 4] = xstrdup(buf);
04013                     }
04014                 }
04015             }
04016             offs += nnrows;
04017             sqlite_free_table(rowpp);
04018         }
04019     }
04020     sqlite_free_table(rowp);
04021     return SQL_SUCCESS;
04022 }
04023 
04024 #ifndef SQLITE_UTF8
04025 
04037 SQLRETURN SQL_API
04038 SQLPrimaryKeys(SQLHSTMT stmt,
04039                SQLCHAR *cat, SQLSMALLINT catLen,
04040                SQLCHAR *schema, SQLSMALLINT schemaLen,
04041                SQLCHAR *table, SQLSMALLINT tableLen)
04042 {
04043     return drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
04044                           table, tableLen);
04045 }
04046 #endif
04047 
04048 #ifdef SQLITE_UTF8
04049 
04061 SQLRETURN SQL_API
04062 SQLPrimaryKeysW(SQLHSTMT stmt,
04063                 SQLWCHAR *cat, SQLSMALLINT catLen,
04064                 SQLWCHAR *schema, SQLSMALLINT schemaLen,
04065                 SQLWCHAR *table, SQLSMALLINT tableLen)
04066 {
04067     char *c = NULL, *s = NULL, *t = NULL;
04068     SQLRETURN ret;
04069 
04070     if (cat) {
04071         c = uc_to_utf_c(cat, catLen);
04072         if (!c) {
04073             ret = nomem((STMT *) stmt);
04074             goto done;
04075         }
04076     }
04077     if (schema) {
04078         s = uc_to_utf_c(schema, schemaLen);
04079         if (!s) {
04080             ret = nomem((STMT *) stmt);
04081             goto done;
04082         }
04083     }
04084     if (table) {
04085         t = uc_to_utf_c(table, tableLen);
04086         if (!t) {
04087             ret = nomem((STMT *) stmt);
04088             goto done;
04089         }
04090     }
04091     ret = drvprimarykeys(stmt, c, SQL_NTS, s, SQL_NTS, t, SQL_NTS);
04092 done:
04093     uc_free(t);
04094     uc_free(s);
04095     uc_free(c);
04096     return ret;
04097 }
04098 #endif
04099 
04104 static COL scolSpec[] = {
04105     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
04106     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
04107     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
04108     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
04109     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
04110     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
04111     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
04112     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
04113     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
04114 };
04115 
04131 static SQLRETURN
04132 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
04133                   SQLCHAR *cat, SQLSMALLINT catLen,
04134                   SQLCHAR *schema, SQLSMALLINT schemaLen,
04135                   SQLCHAR *table, SQLSMALLINT tableLen,
04136                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
04137 {
04138     STMT *s;
04139     DBC *d;
04140     SQLRETURN sret;
04141     int i, size, ret, nrows, ncols, nnnrows, nnncols, offs;
04142     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
04143     int notnullcc = -1, mkrowid = 0;
04144     char *errp = NULL, tname[512];
04145     char **rowp = NULL, **rowppp = NULL;
04146 
04147     sret = mkresultset(stmt, scolSpec, array_size(scolSpec));
04148     if (sret != SQL_SUCCESS) {
04149         return sret;
04150     }
04151     s = (STMT *) stmt;
04152     d = (DBC *) s->dbc;
04153     if (!table || table[0] == '\0' || table[0] == '%') {
04154         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
04155         return SQL_ERROR;
04156     }
04157     if (tableLen == SQL_NTS) {
04158         size = sizeof (tname) - 1;
04159     } else {
04160         size = min(sizeof (tname) - 1, tableLen);
04161     }
04162     strncpy(tname, table, size);
04163     tname[size] = '\0';
04164     if (id != SQL_BEST_ROWID) {
04165         return SQL_SUCCESS;
04166     }
04167     ret = sqlite_get_table_printf(d->sqlite, "PRAGMA index_list('%q')",
04168                                   &rowp, &nrows, &ncols, &errp, tname);
04169     if (ret != SQLITE_OK) {
04170 doerr:
04171         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04172                 errp ? errp : "unknown error", ret);
04173         if (errp) {
04174             sqlite_freemem(errp);
04175             errp = NULL;
04176         }
04177         return SQL_ERROR;       
04178     }
04179     if (errp) {
04180         sqlite_freemem(errp);
04181         errp = NULL;
04182     }
04183     size = 0;   /* number result rows */
04184     if (ncols * nrows <= 0) {
04185         goto nodata_but_rowid;
04186     }
04187     ret = sqlite_get_table_printf(d->sqlite, "PRAGMA table_info('%q')",
04188                                   &rowppp, &nnnrows, &nnncols, &errp, tname);
04189     if (ret != SQLITE_OK) {
04190         sqlite_free_table(rowp);
04191         goto doerr;
04192     }
04193     if (errp) {
04194         sqlite_freemem(errp);
04195         errp = NULL;
04196     }
04197     namec = findcol(rowp, ncols, "name");
04198     uniquec = findcol(rowp, ncols, "unique");
04199     if (namec < 0 || uniquec < 0) {
04200         goto nodata_but_rowid;
04201     }
04202     namecc = findcol(rowppp, nnncols, "name");
04203     typecc = findcol(rowppp, nnncols, "type");
04204     notnullcc = findcol(rowppp, nnncols, "notnull");
04205     for (i = 1; i <= nrows; i++) {
04206         int nnrows, nncols;
04207         char **rowpp;
04208 
04209         if (*rowp[i * ncols + uniquec] != '0') {
04210             ret = sqlite_get_table_printf(d->sqlite,
04211                                           "PRAGMA index_info('%q')", &rowpp,
04212                                           &nnrows, &nncols, NULL,
04213                                           rowp[i * ncols + namec]);
04214             if (ret == SQLITE_OK) {
04215                 size += nnrows;
04216                 sqlite_free_table(rowpp);
04217             }
04218         }
04219     }
04220 nodata_but_rowid:
04221     if (size == 0) {
04222         size = 1;
04223         mkrowid = 1;
04224     }
04225     s->nrows = size;
04226     size = (size + 1) * array_size(scolSpec);
04227     s->rows = xmalloc((size + 1) * sizeof (char *));
04228     if (!s->rows) {
04229         s->nrows = 0;
04230         sqlite_free_table(rowp);
04231         sqlite_free_table(rowppp);
04232         return nomem(s);
04233     }
04234     s->rows[0] = (char *) size;
04235     s->rows += 1;
04236     memset(s->rows, 0, sizeof (char *) * size);
04237     s->rowfree = freerows;
04238     if (mkrowid) {
04239         s->nrows = 0;
04240         goto mkrowid;
04241     }
04242     offs = 0;
04243     for (i = 1; i <= nrows; i++) {
04244         int nnrows, nncols;
04245         char **rowpp;
04246 
04247         if (*rowp[i * ncols + uniquec] != '0') {
04248             int k;
04249 
04250             ret = sqlite_get_table_printf(d->sqlite,
04251                                           "PRAGMA index_info('%q')", &rowpp,
04252                                           &nnrows, &nncols, NULL,
04253                                           rowp[i * ncols + namec]);
04254             if (ret != SQLITE_OK) {
04255                 continue;
04256             }
04257             for (k = 0; nnrows && k < nncols; k++) {
04258                 if (strcmp(rowpp[k], "name") == 0) {
04259                     int m;
04260 
04261                     for (m = 1; m <= nnrows; m++) {
04262                         int roffs = (offs + m) * s->ncols;
04263 
04264                         s->rows[roffs + 0] =
04265                             xstrdup(stringify(SQL_SCOPE_SESSION));
04266                         s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
04267                         s->rows[roffs + 4] = xstrdup("0");
04268                         s->rows[roffs + 7] =
04269                             xstrdup(stringify(SQL_PC_NOT_PSEUDO));
04270                         if (namecc >= 0 && typecc >= 0) {
04271                             int ii;
04272 
04273                             for (ii = 1; ii <= nnnrows; ii++) {
04274                                 if (strcmp(rowppp[ii * nnncols + namecc],
04275                                            rowpp[m * nncols + k]) == 0) {
04276                                     char *typen = rowppp[ii * nnncols + typecc];
04277                                     int sqltype, mm, dd, isnullable = 0;
04278                                     char buf[32];
04279                                         
04280                                     s->rows[roffs + 3] = xstrdup(typen);
04281                                     sqltype = mapsqltype(typen, NULL, *s->ov3,
04282                                                          s->nowchar);
04283                                     getmd(typen, sqltype, &mm, &dd);
04284 #ifdef SQL_LONGVARCHAR
04285                                     if (sqltype == SQL_VARCHAR && mm > 255) {
04286                                         sqltype = SQL_LONGVARCHAR;
04287                                     }
04288 #endif
04289 #ifdef SQLITE_UTF8
04290 #ifdef SQL_WLONGVARCHAR
04291                                     if (sqltype == SQL_WVARCHAR && mm > 255) {
04292                                         sqltype = SQL_WLONGVARCHAR;
04293                                     }
04294 #endif
04295 #endif
04296 #if HAVE_ENCDEC
04297                                     if (sqltype == SQL_VARBINARY && mm > 255) {
04298                                         sqltype = SQL_LONGVARBINARY;
04299                                     }
04300 #endif
04301                                     sprintf(buf, "%d", sqltype);
04302                                     s->rows[roffs + 2] = xstrdup(buf);
04303                                     sprintf(buf, "%d", mm);
04304                                     s->rows[roffs + 5] = xstrdup(buf);
04305                                     sprintf(buf, "%d", dd);
04306                                     s->rows[roffs + 6] = xstrdup(buf);
04307                                     if (notnullcc >= 0) {
04308                                         char *inp =
04309                                            rowppp[ii * nnncols + notnullcc];
04310 
04311                                         isnullable = inp[0] != '0';
04312                                     }
04313                                     sprintf(buf, "%d", isnullable);
04314                                     s->rows[roffs + 8] = xstrdup(buf);
04315                                 }
04316                             }
04317                         }
04318                     }
04319                 }
04320             }
04321             offs += nnrows;
04322             sqlite_free_table(rowpp);
04323         }
04324     }
04325     if (nullable == SQL_NO_NULLS) {
04326         for (i = 1; i < s->nrows; i++) {
04327             if (s->rows[i * s->ncols + 8][0] == '0') {
04328                 int m, i1 = i + 1;
04329 
04330                 for (m = 0; m < s->ncols; m++) {
04331                     freep(&s->rows[i * s->ncols + m]);
04332                 }
04333                 size = s->ncols * sizeof (char *) * (s->nrows - i1);
04334                 if (size > 0) {
04335                     memmove(s->rows + i * s->ncols,
04336                             s->rows + i1 * s->ncols,
04337                             size);
04338                     memset(s->rows + s->nrows * s->ncols, 0,
04339                            s->ncols * sizeof (char *));
04340                 }
04341                 s->nrows--;
04342                 --i;
04343             }
04344         }
04345     }
04346 mkrowid:
04347     sqlite_free_table(rowp);
04348     sqlite_free_table(rowppp);
04349     if (s->nrows == 0) {
04350         s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
04351         s->rows[s->ncols + 1] = xstrdup("_ROWID_");
04352         s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
04353         s->rows[s->ncols + 3] = xstrdup("integer");
04354         s->rows[s->ncols + 4] = xstrdup("0");
04355         s->rows[s->ncols + 5] = xstrdup("10");
04356         s->rows[s->ncols + 6] = xstrdup("9");
04357         s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
04358         s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
04359         s->nrows = 1;
04360     }
04361     return SQL_SUCCESS;
04362 }
04363 
04364 #ifndef SQLITE_UTF8
04365 
04380 SQLRETURN SQL_API
04381 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
04382                   SQLCHAR *cat, SQLSMALLINT catLen,
04383                   SQLCHAR *schema, SQLSMALLINT schemaLen,
04384                   SQLCHAR *table, SQLSMALLINT tableLen,
04385                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
04386 {
04387     return drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
04388                              table, tableLen, scope, nullable);
04389 }
04390 #endif
04391 
04392 #ifdef SQLITE_UTF8
04393 
04408 SQLRETURN SQL_API
04409 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
04410                    SQLWCHAR *cat, SQLSMALLINT catLen,
04411                    SQLWCHAR *schema, SQLSMALLINT schemaLen,
04412                    SQLWCHAR *table, SQLSMALLINT tableLen,
04413                    SQLUSMALLINT scope, SQLUSMALLINT nullable)
04414 {
04415     char *c = NULL, *s = NULL, *t = NULL;
04416     SQLRETURN ret;
04417 
04418     if (cat) {
04419         c = uc_to_utf_c(cat, catLen);
04420         if (!c) {
04421             ret = nomem((STMT *) stmt);
04422             goto done;
04423         }
04424     }
04425     if (schema) {
04426         s = uc_to_utf_c(schema, schemaLen);
04427         if (!s) {
04428             ret = nomem((STMT *) stmt);
04429             goto done;
04430         }
04431     }
04432     if (table) {
04433         t = uc_to_utf_c(table, tableLen);
04434         if (!t) {
04435             ret = nomem((STMT *) stmt);
04436             goto done;
04437         }
04438     }
04439     ret = drvspecialcolumns(stmt, id, c, SQL_NTS, s, SQL_NTS, t, SQL_NTS,
04440                             scope, nullable);
04441 done:
04442     uc_free(t);
04443     uc_free(s);
04444     uc_free(c);
04445     return ret;
04446 }
04447 #endif
04448 
04453 static COL fkeySpec[] = {
04454     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
04455     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
04456     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
04457     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
04458     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
04459     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
04460     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
04461     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
04462     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
04463     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
04464     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
04465     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
04466     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
04467     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
04468 };
04469 
04488 static SQLRETURN SQL_API
04489 drvforeignkeys(SQLHSTMT stmt,
04490                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
04491                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
04492                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
04493                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
04494                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
04495                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
04496 {
04497     STMT *s;
04498     DBC *d;
04499     SQLRETURN sret;
04500     int i, size, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
04501     char **rowp, *errp = NULL, pname[512], fname[512];
04502 
04503     sret = mkresultset(stmt, fkeySpec, array_size(fkeySpec));
04504     if (sret != SQL_SUCCESS) {
04505         return sret;
04506     }
04507     s = (STMT *) stmt;
04508     d = (DBC *) s->dbc;
04509     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
04510         (!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
04511         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
04512         return SQL_ERROR;
04513     }
04514     size = 0;
04515     if (PKtable) {
04516         if (PKtableLen == SQL_NTS) {
04517             size = sizeof (pname) - 1;
04518         } else {
04519             size = min(sizeof (pname) - 1, PKtableLen);
04520         }
04521         strncpy(pname, PKtable, size);
04522     }
04523     pname[size] = '\0';
04524     size = 0;
04525     if (FKtable) {
04526         if (FKtableLen == SQL_NTS) {
04527             size = sizeof (fname) - 1;
04528         } else {
04529             size = min(sizeof (fname) - 1, FKtableLen);
04530         }
04531         strncpy(fname, FKtable, size);
04532     }
04533     fname[size] = '\0';
04534     if (fname[0] != '\0') {
04535         int plen;
04536 
04537         ret = sqlite_get_table_printf(d->sqlite,
04538                                       "PRAGMA foreign_key_list('%q')", &rowp,
04539                                       &nrows, &ncols, &errp, fname);
04540         if (ret != SQLITE_OK) {
04541             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04542                     errp ? errp : "unknown error", ret);
04543             if (errp) {
04544                 sqlite_freemem(errp);
04545                 errp = NULL;
04546             }
04547             return SQL_ERROR;
04548         }
04549         if (errp) {
04550             sqlite_freemem(errp);
04551             errp = NULL;
04552         }
04553         if (ncols * nrows <= 0) {
04554 nodata:
04555             sqlite_free_table(rowp);
04556             return SQL_SUCCESS;
04557         }
04558         size = 0;
04559         namec = findcol(rowp, ncols, "table");
04560         seqc = findcol(rowp, ncols, "seq");
04561         fromc = findcol(rowp, ncols, "from");
04562         toc = findcol(rowp, ncols, "to");
04563         if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
04564             goto nodata;
04565         }
04566         plen = strlen(pname);
04567         for (i = 1; i <= nrows; i++) {
04568             char *ptab = rowp[i * ncols + namec];
04569 
04570             if (plen && ptab) {
04571                 int len = strlen(ptab);
04572 
04573                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
04574                     continue;
04575                 }
04576             }
04577             size++;
04578         }
04579         if (size == 0) {
04580             goto nodata;
04581         }
04582         s->nrows = size;
04583         size = (size + 1) * array_size(fkeySpec);
04584         s->rows = xmalloc((size + 1) * sizeof (char *));
04585         if (!s->rows) {
04586             s->nrows = 0;
04587             return nomem(s);
04588         }
04589         s->rows[0] = (char *) size;
04590         s->rows += 1;
04591         memset(s->rows, 0, sizeof (char *) * size);
04592         s->rowfree = freerows;
04593         offs = 0;
04594         for (i = 1; i <= nrows; i++) {
04595             int pos = 0, roffs = (offs + 1) * s->ncols;
04596             char *ptab = rowp[i * ncols + namec];
04597             char buf[32];
04598 
04599             if (plen && ptab) {
04600                 int len = strlen(ptab);
04601 
04602                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
04603                     continue;
04604                 }
04605             }
04606             s->rows[roffs + 0] = xstrdup("");
04607             s->rows[roffs + 1] = xstrdup("");
04608             s->rows[roffs + 2] = xstrdup(ptab);
04609             s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
04610             s->rows[roffs + 4] = xstrdup("");
04611             s->rows[roffs + 5] = xstrdup("");
04612             s->rows[roffs + 6] = xstrdup(fname);
04613             s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
04614             sscanf(rowp[i * ncols + seqc], "%d", &pos);
04615             sprintf(buf, "%d", pos + 1);
04616             s->rows[roffs + 8] = xstrdup(buf);
04617             s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
04618             s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
04619             s->rows[roffs + 11] = NULL;
04620             s->rows[roffs + 12] = NULL;
04621             s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
04622             offs++;
04623         }
04624         sqlite_free_table(rowp);
04625     } else {
04626         int nnrows, nncols, plen = strlen(pname);
04627         char **rowpp;
04628 
04629         ret = sqlite_get_table(d->sqlite,
04630                                "select name from sqlite_master "
04631                                "where type='table'", &rowp,
04632                                &nrows, &ncols, &errp);
04633         if (ret != SQLITE_OK) {
04634             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04635                     errp ? errp : "unknown error", ret);
04636             if (errp) {
04637                 sqlite_freemem(errp);
04638                 errp = NULL;
04639             }
04640             return SQL_ERROR;
04641         }
04642         if (errp) {
04643             sqlite_freemem(errp);
04644             errp = NULL;
04645         }
04646         if (ncols * nrows <= 0) {
04647             goto nodata;
04648         }
04649         size = 0;
04650         for (i = 1; i <= nrows; i++) {
04651             int k, len;
04652 
04653             if (!rowp[i]) {
04654                 continue;
04655             }
04656             len = strlen(rowp[i]);
04657             if (len == plen && strncasecmp(pname, rowp[i], plen) == 0) {
04658                 continue;
04659             }
04660             ret = sqlite_get_table_printf(d->sqlite,
04661                                           "PRAGMA foreign_key_list('%q')",
04662                                           &rowpp,
04663                                           &nnrows, &nncols, NULL, rowp[i]);
04664             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
04665                 sqlite_free_table(rowpp);
04666                 continue;
04667             }
04668             namec = findcol(rowpp, nncols, "table");
04669             seqc = findcol(rowpp, nncols, "seq");
04670             fromc = findcol(rowpp, nncols, "from");
04671             toc = findcol(rowpp, nncols, "to");
04672             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
04673                 sqlite_free_table(rowpp);
04674                 continue;
04675             }
04676             for (k = 1; k <= nnrows; k++) {
04677                 char *ptab = rowpp[k * nncols + namec];
04678 
04679                 if (plen && ptab) {
04680                     len = strlen(ptab);
04681                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
04682                         continue;
04683                     }
04684                 }
04685                 size++;
04686             }
04687             sqlite_free_table(rowpp);
04688         }
04689         if (size == 0) {
04690             goto nodata;
04691         }
04692         s->nrows = size;
04693         size = (size + 1) * array_size(fkeySpec);
04694         s->rows = xmalloc((size + 1) * sizeof (char *));
04695         if (!s->rows) {
04696             s->nrows = 0;
04697             return nomem(s);
04698         }
04699         s->rows[0] = (char *) size;
04700         s->rows += 1;
04701         memset(s->rows, 0, sizeof (char *) * size);
04702         s->rowfree = freerows;
04703         offs = 0;
04704         for (i = 1; i <= nrows; i++) {
04705             int k, len;
04706 
04707             if (!rowp[i]) {
04708                 continue;
04709             }
04710             len = strlen(rowp[i]);
04711             if (len == plen && strncasecmp(pname, rowp[i], plen) == 0) {
04712                 continue;
04713             }
04714             ret = sqlite_get_table_printf(d->sqlite,
04715                                           "PRAGMA foreign_key_list('%q')",
04716                                           &rowpp,
04717                                           &nnrows, &nncols, NULL, rowp[i]);
04718             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
04719                 sqlite_free_table(rowpp);
04720                 continue;
04721             }
04722             namec = findcol(rowpp, nncols, "table");
04723             seqc = findcol(rowpp, nncols, "seq");
04724             fromc = findcol(rowpp, nncols, "from");
04725             toc = findcol(rowpp, nncols, "to");
04726             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
04727                 sqlite_free_table(rowpp);
04728                 continue;
04729             }
04730             for (k = 1; k <= nnrows; k++) {
04731                 int pos = 0, roffs = (offs + 1) * s->ncols;
04732                 char *ptab = rowpp[k * nncols + namec];
04733                 char buf[32];
04734 
04735                 if (plen && ptab) {
04736                     len = strlen(ptab);
04737                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
04738                         continue;
04739                     }
04740                 }
04741                 s->rows[roffs + 0] = xstrdup("");
04742                 s->rows[roffs + 1] = xstrdup("");
04743                 s->rows[roffs + 2] = xstrdup(ptab);
04744                 s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
04745                 s->rows[roffs + 4] = xstrdup("");
04746                 s->rows[roffs + 5] = xstrdup("");
04747                 s->rows[roffs + 6] = xstrdup(rowp[i]);
04748                 s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
04749                 sscanf(rowpp[k * nncols + seqc], "%d", &pos);
04750                 sprintf(buf, "%d", pos + 1);
04751                 s->rows[roffs + 8] = xstrdup(buf);
04752                 s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
04753                 s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
04754                 s->rows[roffs + 11] = NULL;
04755                 s->rows[roffs + 12] = NULL;
04756                 s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
04757                 offs++;
04758             }
04759             sqlite_free_table(rowpp);
04760         }
04761         sqlite_free_table(rowp);
04762     }
04763     return SQL_SUCCESS;
04764 }
04765 
04766 #ifndef SQLITE_UTF8
04767 
04785 SQLRETURN SQL_API
04786 SQLForeignKeys(SQLHSTMT stmt,
04787                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
04788                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
04789                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
04790                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
04791                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
04792                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
04793 {
04794     return drvforeignkeys(stmt,
04795                           PKcatalog, PKcatalogLen,
04796                           PKschema, PKschemaLen, PKtable, PKtableLen,
04797                           FKcatalog, FKcatalogLen,
04798                           FKschema, FKschemaLen,
04799                           FKtable, FKtableLen);
04800 }
04801 #endif
04802 
04803 #ifdef SQLITE_UTF8
04804 
04822 SQLRETURN SQL_API
04823 SQLForeignKeysW(SQLHSTMT stmt,
04824                 SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
04825                 SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
04826                 SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
04827                 SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
04828                 SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
04829                 SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
04830 {
04831     char *pc = NULL, *ps = NULL, *pt = NULL;
04832     char *fc = NULL, *fs = NULL, *ft = NULL;
04833     SQLRETURN ret;
04834 
04835     if (PKcatalog) {
04836         pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
04837         if (!pc) {
04838             ret = nomem((STMT *) stmt);
04839             goto done;
04840         }
04841     }
04842     if (PKschema) {
04843         ps = uc_to_utf_c(PKschema, PKschemaLen);
04844         if (!ps) {
04845             ret = nomem((STMT *) stmt);
04846             goto done;
04847         }
04848     }
04849     if (PKtable) {
04850         pt = uc_to_utf_c(PKtable, PKtableLen);
04851         if (!pt) {
04852             ret = nomem((STMT *) stmt);
04853             goto done;
04854         }
04855     }
04856     if (FKcatalog) {
04857         fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
04858         if (!fc) {
04859             ret = nomem((STMT *) stmt);
04860             goto done;
04861         }
04862     }
04863     if (FKschema) {
04864         fs = uc_to_utf_c(FKschema, FKschemaLen);
04865         if (!fs) {
04866             ret = nomem((STMT *) stmt);
04867             goto done;
04868         }
04869     }
04870     if (FKtable) {
04871         ft = uc_to_utf_c(FKtable, FKtableLen);
04872         if (!ft) {
04873             ret = nomem((STMT *) stmt);
04874             goto done;
04875         }
04876     }
04877     ret = drvforeignkeys(stmt, pc, SQL_NTS, ps, SQL_NTS, pt, SQL_NTS,
04878                          fc, SQL_NTS, fs, SQL_NTS, ft, SQL_NTS);
04879 done:
04880     uc_free(ft);
04881     uc_free(fs);
04882     uc_free(fc);
04883     uc_free(pt);
04884     uc_free(ps);
04885     uc_free(pc);
04886     return ret;
04887 }
04888 #endif
04889 
04897 static SQLRETURN
04898 endtran(DBC *d, SQLSMALLINT comptype)
04899 {
04900     int fail = 0, ret;
04901     char *sql, *errp = NULL;
04902 
04903     if (!d->sqlite) {
04904         setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
04905         return SQL_ERROR;
04906     }
04907     if (d->autocommit || !d->intrans) {
04908         return SQL_SUCCESS;
04909     }
04910     switch (comptype) {
04911     case SQL_COMMIT:
04912         sql = "COMMIT TRANSACTION";
04913         goto doit;
04914     case SQL_ROLLBACK:
04915     rollback:
04916         sql = "ROLLBACK TRANSACTION";
04917     doit:
04918         d->intrans = 0;
04919         ret = sqlite_exec(d->sqlite, sql, NULL, NULL, &errp);
04920         dbtracerc(d, ret, errp);
04921         if (ret != SQLITE_OK) {
04922             if (!fail) {
04923                 setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
04924                          errp ? errp : "transaction failed");
04925                 if (errp) {
04926                     sqlite_freemem(errp);
04927                     errp = NULL;
04928                 }
04929                 fail = 1;
04930                 goto rollback;
04931             }
04932             if (errp) {
04933                 sqlite_freemem(errp);
04934                 errp = NULL;
04935             }
04936             return SQL_ERROR;
04937         }
04938         if (errp) {
04939             sqlite_freemem(errp);
04940             errp = NULL;
04941         }
04942         return SQL_SUCCESS;
04943     }
04944     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
04945     return SQL_ERROR;
04946 }
04947 
04956 static SQLRETURN
04957 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
04958 {
04959     DBC *d;
04960     int fail = 0;
04961 
04962     switch (type) {
04963     case SQL_HANDLE_DBC:
04964         if (handle == SQL_NULL_HDBC) {
04965             return SQL_INVALID_HANDLE;
04966         }
04967         d = (DBC *) handle;
04968         return endtran(d, comptype);
04969     case SQL_HANDLE_ENV:
04970         if (handle == SQL_NULL_HENV) {
04971             return SQL_INVALID_HANDLE;
04972         }
04973         d = ((ENV *) handle)->dbcs;
04974         while (d) {
04975             SQLRETURN ret;
04976 
04977             ret = endtran(d, comptype);
04978             if (ret != SQL_SUCCESS) {
04979                 fail++;
04980                 comptype = SQL_ROLLBACK;
04981             }
04982             d = d->next;
04983         }
04984         return fail ? SQL_ERROR : SQL_SUCCESS;
04985     }
04986     return SQL_INVALID_HANDLE;
04987 }
04988 
04997 SQLRETURN SQL_API
04998 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
04999 {
05000     return drvendtran(type, handle, comptype);
05001 }
05002 
05011 SQLRETURN SQL_API
05012 SQLTransact(SQLHENV env, SQLHDBC dbc, UWORD type)
05013 {
05014     if (env != SQL_NULL_HENV) {
05015         return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
05016     }
05017     return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
05018 }
05019 
05024 SQLRETURN SQL_API
05025 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
05026 {
05027     return SQL_ERROR;
05028 }
05029 
05030 #ifndef SQLITE_UTF8
05031 
05042 SQLRETURN SQL_API
05043 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
05044              SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
05045 {
05046     int outLen = 0;
05047 
05048     if (sqlinLen == SQL_NTS) {
05049         sqlinLen = strlen(sqlin);
05050     }
05051     if (sql) {
05052         if (sqlMax > 0) {
05053             strncpy(sql, sqlin, sqlMax - 1);
05054             sqlin[sqlMax - 1] = '\0';
05055             outLen = min(sqlMax - 1, sqlinLen);
05056         }
05057     } else {
05058         outLen = sqlinLen;
05059     }
05060     if (sqlLen) {
05061         *sqlLen = outLen;
05062     }
05063     if (sql && outLen < sqlinLen) {
05064         setstat((STMT *) stmt, -1, "data right truncated", "01004");
05065         return SQL_SUCCESS_WITH_INFO;
05066     }
05067     return SQL_SUCCESS;
05068 }
05069 #endif
05070 
05071 #ifdef SQLITE_UTF8
05072 
05083 SQLRETURN SQL_API
05084 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
05085               SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
05086 {
05087     int outLen = 0;
05088 
05089     if (sqlinLen == SQL_NTS) {
05090         sqlinLen = uc_strlen(sqlin);
05091     }
05092     if (sql) {
05093         if (sqlMax > 0) {
05094             uc_strncpy(sql, sqlin, sqlMax - 1);
05095             sqlin[sqlMax - 1] = 0;
05096             outLen = min(sqlMax  - 1, sqlinLen);
05097         }
05098     } else {
05099         outLen = sqlinLen;
05100     }
05101     if (sqlLen) {
05102         *sqlLen = outLen;
05103     }
05104     if (sql && outLen < sqlinLen) {
05105         setstat((STMT *) stmt, -1, "data right truncated", "01004");
05106         return SQL_SUCCESS_WITH_INFO;
05107     }
05108     return SQL_SUCCESS;
05109 }
05110 #endif
05111 
05116 static COL procSpec[] = {
05117     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
05118     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
05119     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
05120     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
05121     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
05122     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
05123     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
05124     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
05125 };
05126 
05127 #ifndef SQLITE_UTF8
05128 
05140 SQLRETURN SQL_API
05141 SQLProcedures(SQLHSTMT stmt,
05142               SQLCHAR *catalog, SQLSMALLINT catalogLen,
05143               SQLCHAR *schema, SQLSMALLINT schemaLen,
05144               SQLCHAR *proc, SQLSMALLINT procLen)
05145 {
05146     return mkresultset(stmt, procSpec, array_size(procSpec));
05147 }
05148 #endif
05149 
05150 #ifdef SQLITE_UTF8
05151 
05163 SQLRETURN SQL_API
05164 SQLProceduresW(SQLHSTMT stmt,
05165                SQLWCHAR *catalog, SQLSMALLINT catalogLen,
05166                SQLWCHAR *schema, SQLSMALLINT schemaLen,
05167                SQLWCHAR *proc, SQLSMALLINT procLen)
05168 {
05169     return mkresultset(stmt, procSpec, array_size(procSpec));
05170 }
05171 #endif
05172 
05177 static COL procColSpec[] = {
05178     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
05179     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
05180     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
05181     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
05182     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
05183     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
05184     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
05185     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
05186     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
05187     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
05188     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
05189     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
05190     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
05191     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
05192     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
05193     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
05194     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
05195     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
05196     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
05197 };
05198 
05199 #ifndef SQLITE_UTF8
05200 
05214 SQLRETURN SQL_API
05215 SQLProcedureColumns(SQLHSTMT stmt,
05216                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
05217                     SQLCHAR *schema, SQLSMALLINT schemaLen,
05218                     SQLCHAR *proc, SQLSMALLINT procLen,
05219                     SQLCHAR *column, SQLSMALLINT columnLen)
05220 {
05221     return mkresultset(stmt, procColSpec, array_size(procColSpec));
05222 
05223 }
05224 #endif
05225 
05226 #ifdef SQLITE_UTF8
05227 
05242 SQLRETURN SQL_API
05243 SQLProcedureColumnsW(SQLHSTMT stmt,
05244                      SQLWCHAR *catalog, SQLSMALLINT catalogLen,
05245                      SQLWCHAR *schema, SQLSMALLINT schemaLen,
05246                      SQLWCHAR *proc, SQLSMALLINT procLen,
05247                      SQLWCHAR *column, SQLSMALLINT columnLen)
05248 {
05249     return mkresultset(stmt, procColSpec, array_size(procColSpec));
05250 }
05251 #endif
05252 
05263 SQLRETURN SQL_API
05264 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
05265               SQLINTEGER len, SQLINTEGER *lenp)
05266 {
05267     ENV *e;
05268 
05269     if (env == SQL_NULL_HENV) {
05270         return SQL_INVALID_HANDLE;
05271     }
05272     e = (ENV *) env;
05273     if (!e || e->magic != ENV_MAGIC) {
05274         return SQL_INVALID_HANDLE;
05275     }
05276     switch (attr) {
05277     case SQL_ATTR_CONNECTION_POOLING:
05278         return SQL_ERROR;
05279     case SQL_ATTR_CP_MATCH:
05280         return SQL_NO_DATA;
05281     case SQL_ATTR_OUTPUT_NTS:
05282         if (val) {
05283             *((SQLINTEGER *) val) = SQL_TRUE;
05284         }
05285         if (lenp) {
05286             *lenp = sizeof (SQLINTEGER);
05287         }
05288         return SQL_SUCCESS;
05289     case SQL_ATTR_ODBC_VERSION:
05290         if (val) {
05291             *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
05292         }
05293         if (lenp) {
05294             *lenp = sizeof (SQLINTEGER);
05295         }
05296         return SQL_SUCCESS;
05297     }
05298     return SQL_ERROR;
05299 }
05300 
05310 SQLRETURN SQL_API
05311 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
05312 {
05313     ENV *e;
05314 
05315     if (env == SQL_NULL_HENV) {
05316         return SQL_INVALID_HANDLE;
05317     }
05318     e = (ENV *) env;
05319     if (!e || e->magic != ENV_MAGIC) {
05320         return SQL_INVALID_HANDLE;
05321     }
05322     switch (attr) {
05323     case SQL_ATTR_CONNECTION_POOLING:
05324         return SQL_SUCCESS;
05325     case SQL_ATTR_CP_MATCH:
05326         return SQL_NO_DATA;
05327     case SQL_ATTR_OUTPUT_NTS:
05328         if ((SQLINTEGER) val == SQL_TRUE) {
05329             return SQL_SUCCESS;
05330         }
05331         return SQL_ERROR;
05332     case SQL_ATTR_ODBC_VERSION:
05333         if (!val) {
05334             return SQL_ERROR;
05335         }
05336         if ((SQLINTEGER) val == SQL_OV_ODBC2) {
05337             e->ov3 = 0;
05338             return SQL_SUCCESS;
05339         }
05340         if ((SQLINTEGER) val == SQL_OV_ODBC3) {
05341             e->ov3 = 1;
05342             return SQL_SUCCESS;
05343         }
05344         return SQL_ERROR;
05345     }
05346     return SQL_ERROR;
05347 }
05348 
05362 static SQLRETURN
05363 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
05364               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
05365               SQLSMALLINT buflen, SQLSMALLINT *msglen)
05366 {
05367     DBC *d = NULL;
05368     STMT *s = NULL;
05369     int len, naterr;
05370     char *logmsg, *sqlst;
05371 
05372     if (handle == SQL_NULL_HANDLE) {
05373         return SQL_INVALID_HANDLE;
05374     }
05375     if (sqlstate) {
05376         sqlstate[0] = '\0';
05377     }
05378     if (msg && buflen > 0) {
05379         msg[0] = '\0';
05380     }
05381     if (msglen) {
05382         *msglen = 0;
05383     }
05384     if (nativeerr) {
05385         *nativeerr = 0;
05386     }
05387     switch (htype) {
05388     case SQL_HANDLE_ENV:
05389     case SQL_HANDLE_DESC:
05390         return SQL_NO_DATA;
05391     case SQL_HANDLE_DBC:
05392         d = (DBC *) handle;
05393         logmsg = d->logmsg;
05394         sqlst = d->sqlstate;
05395         naterr = d->naterr;
05396         break;
05397     case SQL_HANDLE_STMT:
05398         s = (STMT *) handle;
05399         logmsg = s->logmsg;
05400         sqlst = s->sqlstate;
05401         naterr = s->naterr;
05402         break;
05403     default:
05404         return SQL_INVALID_HANDLE;
05405     }
05406     if (buflen < 0) {
05407         return SQL_ERROR;
05408     }
05409     if (recno > 1) {
05410         return SQL_NO_DATA;
05411     }
05412     len = strlen(logmsg);
05413     if (len == 0) {
05414         return SQL_NO_DATA;
05415     }
05416     if (nativeerr) {
05417         *nativeerr = naterr;
05418     }
05419     if (sqlstate) {
05420         strcpy(sqlstate, sqlst);
05421     }
05422     if (msglen) {
05423         *msglen = len;
05424     }
05425     if (len >= buflen) {
05426         if (msg && buflen > 0) {
05427             strncpy(msg, logmsg, buflen);
05428             msg[buflen - 1] = '\0';
05429             logmsg[0] = '\0';
05430         }
05431     } else if (msg) {
05432         strcpy(msg, logmsg);
05433         logmsg[0] = '\0';
05434     }
05435     return SQL_SUCCESS;
05436 }
05437 
05438 #ifndef SQLITE_UTF8
05439 
05452 SQLRETURN SQL_API
05453 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
05454               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
05455               SQLSMALLINT buflen, SQLSMALLINT *msglen)
05456 {
05457     return drvgetdiagrec(htype, handle, recno, sqlstate,
05458                          nativeerr, msg, buflen, msglen);
05459 }
05460 #endif
05461 
05462 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
05463 #ifdef SQLITE_UTF8
05464 
05478 SQLRETURN SQL_API
05479 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
05480               SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
05481               SQLSMALLINT buflen, SQLSMALLINT *msglen)
05482 {
05483     char state[16];
05484     SQLSMALLINT len;
05485     SQLRETURN ret;
05486     
05487     ret = drvgetdiagrec(htype, handle, recno, state,
05488                         nativeerr, (char *) msg, buflen, &len);
05489     if (ret == SQL_SUCCESS) {
05490         if (sqlstate) {
05491             uc_from_utf_buf(state, sqlstate, 6 * sizeof (SQLWCHAR));
05492         }
05493         if (msg) {
05494             if (len > 0) {
05495                 SQLWCHAR *m = NULL;
05496 
05497                 m = uc_from_utf((char *) msg, len);
05498                 if (m) {
05499                     if (buflen) {
05500                         uc_strncpy(msg, m, buflen);
05501                         len = min(buflen, uc_strlen(m));
05502                     } else {
05503                         len = uc_strlen(m);
05504                     }
05505                     uc_free(m);
05506                 } else {
05507                     len = 0;
05508                 }
05509             }
05510             if (len <= 0) {
05511                 len = 0;
05512                 if (buflen > 0) {
05513                     msg[0] = 0;
05514                 }
05515             }
05516         } else {
05517             len = 0;
05518         }
05519         if (msglen) {
05520             *msglen = len;
05521         }
05522     } else if (ret == SQL_NO_DATA) {
05523         if (sqlstate) {
05524             sqlstate[0] = 0;
05525         }
05526         if (msg) {
05527             if (buflen > 0) {
05528                 msg[0] = 0;
05529             }
05530         }
05531         if (msglen) {
05532             *msglen = 0;
05533         }
05534     }
05535     return ret;
05536 }
05537 #endif
05538 #endif
05539 
05540 #ifndef SQLITE_UTF8
05541 
05545 SQLRETURN SQL_API
05546 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
05547                 SQLSMALLINT id, SQLPOINTER info, 
05548                 SQLSMALLINT buflen, SQLSMALLINT *strlen)
05549 {
05550     return SQL_ERROR;
05551 }
05552 #endif
05553 
05554 #ifdef SQLITE_UTF8
05555 
05559 SQLRETURN SQL_API
05560 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
05561                  SQLSMALLINT id, SQLPOINTER info, 
05562                  SQLSMALLINT buflen, SQLSMALLINT *strlen)
05563 {
05564     return SQL_ERROR;
05565 }
05566 #endif
05567 
05578 static SQLRETURN
05579 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
05580                SQLINTEGER bufmax, SQLINTEGER *buflen)
05581 {
05582     STMT *s = (STMT *) stmt;
05583     SQLUINTEGER *uval = (SQLUINTEGER *) val;
05584 
05585     switch (attr) {
05586     case SQL_QUERY_TIMEOUT:
05587         *uval = 0;
05588         return SQL_SUCCESS;
05589     case SQL_ATTR_CURSOR_TYPE:
05590         *uval = s->curtype;
05591         return SQL_SUCCESS;
05592     case SQL_ATTR_CURSOR_SCROLLABLE:
05593         *uval = s->curtype != SQL_CURSOR_FORWARD_ONLY ?
05594             SQL_SCROLLABLE : SQL_NONSCROLLABLE;
05595         return SQL_SUCCESS;
05596 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
05597     case SQL_ATTR_CURSOR_SENSITIVITY:
05598         *uval = SQL_UNSPECIFIED;
05599         return SQL_SUCCESS;
05600 #endif
05601     case SQL_ATTR_ROW_NUMBER:
05602         {
05603             STMT *s = (STMT *) stmt;
05604             DBC *d = (DBC *) s->dbc;
05605 
05606             if (s == d->vm_stmt) {
05607                 *uval = d->vm_rownum < 0 ?
05608                     SQL_ROW_NUMBER_UNKNOWN : d->vm_rownum;
05609             }
05610         }
05611         *uval = s->rowp < 0 ? SQL_ROW_NUMBER_UNKNOWN : s->rowp;
05612         return SQL_SUCCESS;
05613     case SQL_ATTR_ASYNC_ENABLE:
05614         *uval = SQL_ASYNC_ENABLE_OFF;
05615         return SQL_SUCCESS;
05616     case SQL_CONCURRENCY:
05617         *uval = SQL_CONCUR_LOCK;
05618         return SQL_SUCCESS;
05619     case SQL_ATTR_RETRIEVE_DATA:
05620         *uval = s->retr_data;
05621         return SQL_SUCCESS;
05622     case SQL_ROWSET_SIZE:
05623     case SQL_ATTR_ROW_ARRAY_SIZE:
05624         *uval = s->rowset_size;
05625         return SQL_SUCCESS;
05626     /* Needed for some driver managers, but dummies for now */
05627     case SQL_ATTR_IMP_ROW_DESC:
05628     case SQL_ATTR_APP_ROW_DESC:
05629     case SQL_ATTR_IMP_PARAM_DESC:
05630     case SQL_ATTR_APP_PARAM_DESC:
05631         *((SQLHDESC *) val) = (SQLHDESC) DEAD_MAGIC;
05632         return SQL_SUCCESS;
05633     case SQL_ATTR_ROW_STATUS_PTR:
05634         *((SQLUSMALLINT **) val) = s->row_status;
05635         return SQL_SUCCESS;
05636     case SQL_ATTR_ROWS_FETCHED_PTR:
05637         *((SQLUINTEGER **) val) = s->row_count;
05638         return SQL_SUCCESS;
05639     case SQL_ATTR_USE_BOOKMARKS: {
05640         STMT *s = (STMT *) stmt;
05641 
05642         *(SQLUINTEGER *) val = s->bkmrk ? SQL_UB_ON : SQL_UB_OFF;
05643         return SQL_SUCCESS;
05644     }
05645     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
05646         *((SQLUINTEGER **) val) = s->parm_bind_offs;
05647         return SQL_SUCCESS;
05648     case SQL_ATTR_PARAM_BIND_TYPE:
05649         *((SQLUINTEGER *) val) = SQL_PARAM_BIND_BY_COLUMN;
05650         return SQL_SUCCESS;
05651     case SQL_ATTR_PARAM_OPERATION_PTR:
05652         *((SQLUSMALLINT **) val) = s->parm_oper;
05653         return SQL_SUCCESS;
05654     case SQL_ATTR_PARAM_STATUS_PTR:
05655         *((SQLUSMALLINT **) val) = s->parm_status;
05656         return SQL_SUCCESS;
05657     case SQL_ATTR_PARAMS_PROCESSED_PTR:
05658         *((SQLUINTEGER **) val) = s->parm_proc;
05659         return SQL_SUCCESS;
05660     case SQL_ATTR_PARAMSET_SIZE:
05661         *((SQLUINTEGER *) val) = s->paramset_size;
05662         return SQL_SUCCESS;
05663     case SQL_ATTR_ROW_BIND_TYPE:
05664         *(SQLUINTEGER *) val = s->bind_type;
05665         return SQL_SUCCESS;
05666     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
05667         *((SQLUINTEGER **) val) = s->bind_offs;
05668         return SQL_SUCCESS;
05669     }
05670     return drvunimplstmt(stmt);
05671 }
05672 
05673 #if (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC) || !defined(SQLITE_UTF8)
05674 
05684 SQLRETURN SQL_API
05685 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
05686                SQLINTEGER bufmax, SQLINTEGER *buflen)
05687 {
05688     return drvgetstmtattr(stmt, attr, val, bufmax, buflen);
05689 }
05690 #endif
05691 
05692 #ifdef SQLITE_UTF8
05693 
05703 SQLRETURN SQL_API
05704 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
05705                 SQLINTEGER bufmax, SQLINTEGER *buflen)
05706 {
05707     return drvgetstmtattr(stmt, attr, val, bufmax, buflen);
05708 }
05709 #endif
05710 
05720 static SQLRETURN
05721 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
05722                SQLINTEGER buflen)
05723 {
05724     STMT *s = (STMT *) stmt;
05725 
05726     switch (attr) {
05727     case SQL_ATTR_CURSOR_TYPE:
05728         if ((SQLUINTEGER) val == SQL_CURSOR_FORWARD_ONLY) {
05729             s->curtype = SQL_CURSOR_FORWARD_ONLY;
05730         } else {
05731             s->curtype = SQL_CURSOR_STATIC;
05732         }
05733         if ((SQLUINTEGER) val != SQL_CURSOR_FORWARD_ONLY &&
05734             (SQLUINTEGER) val != SQL_CURSOR_STATIC) {
05735             goto e01s02;
05736         }
05737         return SQL_SUCCESS;
05738     case SQL_ATTR_CURSOR_SCROLLABLE:
05739         if ((SQLUINTEGER) val == SQL_NONSCROLLABLE) {
05740             s->curtype = SQL_CURSOR_FORWARD_ONLY;
05741         } else {
05742             s->curtype = SQL_CURSOR_STATIC;
05743         }
05744         return SQL_SUCCESS;
05745     case SQL_ATTR_ASYNC_ENABLE:
05746         if ((SQLUINTEGER) val != SQL_ASYNC_ENABLE_OFF) {
05747     e01s02:
05748             setstat(s, -1, "option value changed", "01S02");
05749             return SQL_SUCCESS_WITH_INFO;
05750         }
05751         return SQL_SUCCESS;
05752     case SQL_CONCURRENCY:
05753         if ((SQLUINTEGER) val != SQL_CONCUR_LOCK) {
05754             goto e01s02;
05755         }
05756         return SQL_SUCCESS;
05757     case SQL_ATTR_QUERY_TIMEOUT:
05758         return SQL_SUCCESS;
05759     case SQL_ATTR_RETRIEVE_DATA:
05760         if ((SQLUINTEGER) val != SQL_RD_ON &&
05761             (SQLUINTEGER) val != SQL_RD_OFF) {
05762             goto e01s02;
05763         }
05764         s->retr_data = (int) val;
05765         return SQL_SUCCESS;
05766     case SQL_ROWSET_SIZE:
05767     case SQL_ATTR_ROW_ARRAY_SIZE:
05768         if ((SQLUINTEGER) val < 1) {
05769             setstat(s, -1, "invalid rowset size", "HY000");
05770             return SQL_ERROR;
05771         } else {
05772             SQLUSMALLINT *rst = &s->row_status1;
05773 
05774             if ((SQLUINTEGER) val > 1) {
05775                 rst = xmalloc(sizeof (SQLUSMALLINT) * (SQLUINTEGER) val);
05776                 if (!rst) {
05777                     return nomem(s);
05778                 }
05779             }
05780             if (s->row_status0 != &s->row_status1) {
05781                 freep(&s->row_status0);
05782             }
05783             s->row_status0 = rst;
05784             s->rowset_size = (SQLUINTEGER) val;
05785         }
05786         return SQL_SUCCESS;
05787     case SQL_ATTR_ROW_STATUS_PTR:
05788         s->row_status = (SQLUSMALLINT *) val;
05789         return SQL_SUCCESS;
05790     case SQL_ATTR_ROWS_FETCHED_PTR:
05791         s->row_count = (SQLUINTEGER *) val;
05792         return SQL_SUCCESS;
05793     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
05794         s->parm_bind_offs = (SQLUINTEGER *) val;
05795         return SQL_SUCCESS;
05796     case SQL_ATTR_PARAM_BIND_TYPE:
05797         if ((SQLUINTEGER) val != SQL_PARAM_BIND_BY_COLUMN) {
05798             goto e01s02;
05799         }
05800         return SQL_SUCCESS;
05801     case SQL_ATTR_PARAM_OPERATION_PTR:
05802         s->parm_oper = (SQLUSMALLINT *) val;
05803         return SQL_SUCCESS;
05804     case SQL_ATTR_PARAM_STATUS_PTR:
05805         s->parm_status = (SQLUSMALLINT *) val;
05806         return SQL_SUCCESS;
05807     case SQL_ATTR_PARAMS_PROCESSED_PTR:
05808         s->parm_proc = (SQLUINTEGER *) val;
05809         return SQL_SUCCESS;
05810     case SQL_ATTR_PARAMSET_SIZE:
05811         if ((SQLUINTEGER) val < 1) {
05812             goto e01s02;
05813         }
05814         s->paramset_size = (SQLUINTEGER) val;
05815         s->paramset_count = 0;
05816         return SQL_SUCCESS;
05817     case SQL_ATTR_ROW_BIND_TYPE:
05818         s->bind_type = (SQLUINTEGER) val;
05819         return SQL_SUCCESS;
05820     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
05821         s->bind_offs = (SQLUINTEGER *) val;
05822         return SQL_SUCCESS;
05823     case SQL_ATTR_USE_BOOKMARKS:
05824         if ((SQLUINTEGER) val != SQL_UB_OFF &&
05825             (SQLUINTEGER) val != SQL_UB_ON) {
05826             goto e01s02;
05827         }
05828         s->bkmrk = (SQLUINTEGER) val == SQL_UB_ON;
05829         return SQL_SUCCESS;
05830     }
05831     return drvunimplstmt(stmt);
05832 }
05833 
05834 #if (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC) || !defined(SQLITE_UTF8)
05835 
05844 SQLRETURN SQL_API
05845 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
05846                SQLINTEGER buflen)
05847 {
05848     return drvsetstmtattr(stmt, attr, val, buflen);
05849 }
05850 #endif
05851 
05852 #ifdef SQLITE_UTF8
05853 
05862 SQLRETURN SQL_API
05863 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
05864                 SQLINTEGER buflen)
05865 {
05866     return drvsetstmtattr(stmt, attr, val, buflen);
05867 }
05868 #endif
05869 
05878 static SQLRETURN
05879 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
05880 {
05881     STMT *s = (STMT *) stmt;
05882     SQLUINTEGER *ret = (SQLUINTEGER *) param;
05883 
05884     switch (opt) {
05885     case SQL_QUERY_TIMEOUT:
05886         *ret = 0;
05887         return SQL_SUCCESS;
05888     case SQL_CURSOR_TYPE:
05889         *ret = s->curtype;
05890         return SQL_SUCCESS;
05891     case SQL_ROW_NUMBER:
05892         {
05893             DBC *d = (DBC *) s->dbc;
05894 
05895             if (s == d->vm_stmt) {
05896                 *ret = d->vm_rownum < 0 ?
05897                     SQL_ROW_NUMBER_UNKNOWN : d->vm_rownum;
05898             }
05899         }
05900         *ret = s->rowp < 0 ? SQL_ROW_NUMBER_UNKNOWN : s->rowp;
05901         return SQL_SUCCESS;
05902     case SQL_ASYNC_ENABLE:
05903         *ret = SQL_ASYNC_ENABLE_OFF;
05904         return SQL_SUCCESS;
05905     case SQL_CONCURRENCY:
05906         *ret = SQL_CONCUR_LOCK;
05907         return SQL_SUCCESS;
05908     case SQL_ATTR_RETRIEVE_DATA:
05909         *ret = s->retr_data;
05910         return SQL_SUCCESS;
05911     case SQL_ROWSET_SIZE:
05912     case SQL_ATTR_ROW_ARRAY_SIZE:
05913         *ret = s->rowset_size;
05914         return SQL_SUCCESS;
05915     }
05916     return drvunimplstmt(stmt);
05917 }
05918 
05927 SQLRETURN SQL_API
05928 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
05929 {
05930     return drvgetstmtoption(stmt, opt, param);
05931 }
05932 
05933 #ifdef SQLITE_UTF8
05934 
05942 SQLRETURN SQL_API
05943 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
05944 {
05945     return drvgetstmtoption(stmt, opt, param);
05946 }
05947 #endif
05948 
05957 static SQLRETURN
05958 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
05959 {
05960     STMT *s = (STMT *) stmt;
05961 
05962     switch (opt) {
05963     case SQL_CURSOR_TYPE:
05964         if (param == SQL_CURSOR_FORWARD_ONLY) {
05965             s->curtype = param;
05966         } else {
05967             s->curtype = SQL_CURSOR_STATIC;
05968         }
05969         if (param != SQL_CURSOR_FORWARD_ONLY &&
05970             param != SQL_CURSOR_STATIC) {
05971             goto e01s02;
05972         }
05973         return SQL_SUCCESS;
05974     case SQL_ASYNC_ENABLE:
05975         if (param != SQL_ASYNC_ENABLE_OFF) {
05976             goto e01s02;
05977         }
05978         return SQL_SUCCESS;
05979     case SQL_CONCURRENCY:
05980         if (param != SQL_CONCUR_LOCK) {
05981             goto e01s02;
05982         }
05983         return SQL_SUCCESS;
05984     case SQL_QUERY_TIMEOUT:
05985         return SQL_SUCCESS;
05986     case SQL_RETRIEVE_DATA:
05987         if (param != SQL_RD_ON && param != SQL_RD_OFF) {
05988     e01s02:
05989             setstat(s, -1, "option value changed", "01S02");
05990             return SQL_SUCCESS_WITH_INFO;
05991         }
05992         s->retr_data = (int) param;
05993         return SQL_SUCCESS;
05994     case SQL_ROWSET_SIZE:
05995     case SQL_ATTR_ROW_ARRAY_SIZE:
05996         if (param < 1) {
05997             setstat(s, -1, "invalid rowset size", "HY000");
05998             return SQL_ERROR;
05999         } else {
06000             SQLUSMALLINT *rst = &s->row_status1;
06001 
06002             if (param > 1) {
06003                 rst = xmalloc(sizeof (SQLUSMALLINT) * param);
06004                 if (!rst) {
06005                     return nomem(s);
06006                 }
06007             }
06008             if (s->row_status0 != &s->row_status1) {
06009                 freep(&s->row_status0);
06010             }
06011             s->row_status0 = rst;
06012             s->rowset_size = param;
06013         }
06014         return SQL_SUCCESS;
06015     }
06016     return drvunimplstmt(stmt);
06017 }
06018 
06027 SQLRETURN SQL_API
06028 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
06029 {
06030     return drvsetstmtoption(stmt, opt, param);
06031 }
06032 
06033 #ifdef SQLITE_UTF8
06034 
06042 SQLRETURN SQL_API
06043 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
06044 {
06045     return drvsetstmtoption(stmt, opt, param);
06046 }
06047 #endif
06048 
06053 SQLRETURN SQL_API
06054 SQLSetPos(SQLHSTMT stmt, SQLUSMALLINT row, SQLUSMALLINT op, SQLUSMALLINT lock)
06055 {
06056     return drvunimplstmt(stmt);
06057 }
06058 
06063 SQLRETURN SQL_API
06064 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLINTEGER rowkeyset,
06065                     SQLUSMALLINT rowset)
06066 {
06067     return drvunimplstmt(stmt);
06068 }
06069 
06070 #define strmak(dst, src, max, lenp) { \
06071     int len = strlen(src); \
06072     int cnt = min(len + 1, max); \
06073     strncpy(dst, src, cnt); \
06074     *lenp = (cnt > len) ? len : cnt; \
06075 }
06076 
06087 static SQLRETURN
06088 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
06089            SQLSMALLINT *valLen)
06090 {
06091     DBC *d;
06092     char dummyc[16];
06093     SQLSMALLINT dummy;
06094     static char drvname[] =
06095 #ifdef _WIN32
06096         "sqliteodbc.dll";
06097 #else
06098         "sqliteodbc.so";
06099 #endif
06100 
06101     if (dbc == SQL_NULL_HDBC) {
06102         return SQL_INVALID_HANDLE;
06103     }
06104     d = (DBC *) dbc;
06105     if (valMax) {
06106         valMax--;
06107     }
06108     if (!valLen) {
06109         valLen = &dummy;
06110     }
06111     if (!val) {
06112         val = dummyc;
06113         valMax = sizeof (dummyc) - 1;
06114     }
06115     switch (type) {
06116     case SQL_MAX_USER_NAME_LEN:
06117         *((SQLSMALLINT *) val) = 16;
06118         *valLen = sizeof (SQLSMALLINT);
06119         break;
06120     case SQL_USER_NAME:
06121         strmak(val, "", valMax, valLen);
06122         break;
06123     case SQL_DRIVER_ODBC_VER:
06124 #if 0
06125         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
06126 #else
06127         strmak(val, "03.00", valMax, valLen);
06128 #endif
06129         break;
06130     case SQL_ACTIVE_CONNECTIONS:
06131     case SQL_ACTIVE_STATEMENTS:
06132         *((SQLSMALLINT *) val) = 0;
06133         *valLen = sizeof (SQLSMALLINT);
06134         break;
06135 #ifdef SQL_ASYNC_MODE
06136     case SQL_ASYNC_MODE:
06137         *((SQLUINTEGER *) val) = SQL_AM_NONE;
06138         *valLen = sizeof (SQLUINTEGER);
06139         break;
06140 #endif
06141 #ifdef SQL_CREATE_TABLE
06142     case SQL_CREATE_TABLE:
06143         *((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
06144                                  SQL_CT_COLUMN_DEFAULT |
06145                                  SQL_CT_COLUMN_CONSTRAINT |
06146                                  SQL_CT_CONSTRAINT_NON_DEFERRABLE;
06147         *valLen = sizeof (SQLUINTEGER);
06148         break;
06149 #endif
06150 #ifdef SQL_CREATE_VIEW
06151     case SQL_CREATE_VIEW:
06152         *((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
06153         *valLen = sizeof (SQLUINTEGER);
06154         break;
06155 #endif
06156 #ifdef SQL_DDL_INDEX
06157     case SQL_DDL_INDEX:
06158         *((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
06159         *valLen = sizeof (SQLUINTEGER);
06160         break;
06161 #endif
06162 #ifdef SQL_DROP_TABLE
06163     case SQL_DROP_TABLE:
06164         *((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
06165         *valLen = sizeof (SQLUINTEGER);
06166         break;
06167 #endif
06168 #ifdef SQL_DROP_VIEW
06169     case SQL_DROP_VIEW:
06170         *((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
06171         *valLen = sizeof (SQLUINTEGER);
06172         break;
06173 #endif
06174 #ifdef SQL_INDEX_KEYWORDS
06175     case SQL_INDEX_KEYWORDS:
06176         *((SQLUINTEGER *) val) = SQL_IK_ALL;
06177         *valLen = sizeof (SQLUINTEGER);
06178         break;
06179 #endif
06180     case SQL_DATA_SOURCE_NAME:
06181         strmak(val, (d->dsn ? d->dsn : ""), valMax, valLen);
06182         break;
06183     case SQL_DRIVER_NAME:
06184         strmak(val, drvname, valMax, valLen);
06185         break;
06186     case SQL_DRIVER_VER:
06187         strmak(val, DRIVER_VER_INFO, valMax, valLen);
06188         break;
06189     case SQL_FETCH_DIRECTION:
06190         *((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
06191             SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
06192         *valLen = sizeof (SQLUINTEGER);
06193         break;
06194     case SQL_ODBC_VER:
06195         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
06196         break;
06197     case SQL_ODBC_SAG_CLI_CONFORMANCE:
06198         *((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
06199         *valLen = sizeof (SQLSMALLINT);
06200         break;
06201     case SQL_STANDARD_CLI_CONFORMANCE:
06202         *((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
06203         *valLen = sizeof (SQLUINTEGER);
06204         break;
06205     case SQL_SERVER_NAME:
06206     case SQL_DATABASE_NAME:
06207         strmak(val, (d->dbname ? d->dbname : ""), valMax, valLen);
06208         break;
06209     case SQL_SEARCH_PATTERN_ESCAPE:
06210         strmak(val, "", valMax, valLen);
06211         break;
06212     case SQL_ODBC_SQL_CONFORMANCE:
06213         *((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
06214         *valLen = sizeof (SQLSMALLINT);
06215         break;
06216     case SQL_ODBC_API_CONFORMANCE:
06217         *((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
06218         *valLen = sizeof (SQLSMALLINT);
06219         break;
06220     case SQL_DBMS_NAME:
06221         strmak(val, "SQLite", valMax, valLen);
06222         break;
06223     case SQL_DBMS_VER:
06224         strmak(val, SQLITE_VERSION, valMax, valLen);
06225         break;
06226     case SQL_COLUMN_ALIAS:
06227     case SQL_NEED_LONG_DATA_LEN:
06228         strmak(val, "Y", valMax, valLen);
06229         break;
06230     case SQL_ROW_UPDATES:
06231     case SQL_ACCESSIBLE_PROCEDURES:
06232     case SQL_PROCEDURES:
06233     case SQL_EXPRESSIONS_IN_ORDERBY:
06234     case SQL_ODBC_SQL_OPT_IEF:
06235     case SQL_LIKE_ESCAPE_CLAUSE:
06236     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
06237     case SQL_OUTER_JOINS:
06238     case SQL_ACCESSIBLE_TABLES:
06239     case SQL_MULT_RESULT_SETS:
06240     case SQL_MULTIPLE_ACTIVE_TXN:
06241     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
06242         strmak(val, "N", valMax, valLen);
06243         break;
06244     case SQL_DATA_SOURCE_READ_ONLY:
06245         strmak(val, "N", valMax, valLen);
06246         break;
06247 #ifdef SQL_OJ_CAPABILITIES
06248     case SQL_OJ_CAPABILITIES:
06249         *((SQLUINTEGER *) val) = 0;
06250         *valLen = sizeof (SQLUINTEGER);
06251         break;
06252 #endif
06253 #ifdef SQL_MAX_IDENTIFIER_LEN
06254     case SQL_MAX_IDENTIFIER_LEN:
06255         *((SQLUSMALLINT *) val) = 255;
06256         *valLen = sizeof (SQLUSMALLINT);
06257         break;
06258 #endif
06259     case SQL_CONCAT_NULL_BEHAVIOR:
06260         *((SQLSMALLINT *) val) = SQL_CB_NULL;
06261         *valLen = sizeof (SQLSMALLINT);
06262         break;
06263     case SQL_CURSOR_COMMIT_BEHAVIOR:
06264     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
06265         *((SQLSMALLINT *) val) = SQL_CB_DELETE;
06266         *valLen = sizeof (SQLSMALLINT);
06267         break;
06268 #ifdef SQL_CURSOR_SENSITIVITY
06269     case SQL_CURSOR_SENSITIVITY:
06270         *((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
06271         *valLen = sizeof (SQLUINTEGER);
06272         break;
06273 #endif
06274     case SQL_DEFAULT_TXN_ISOLATION:
06275         *((SQLUINTEGER *) val) = SQL_TXN_READ_UNCOMMITTED;
06276         *valLen = sizeof (SQLUINTEGER);
06277         break;
06278 #ifdef SQL_DESCRIBE_PARAMETER
06279     case SQL_DESCRIBE_PARAMETER:
06280         strmak(val, "Y", valMax, valLen);
06281         break;
06282 #endif
06283     case SQL_TXN_ISOLATION_OPTION:
06284         *((SQLUINTEGER *) val) = SQL_TXN_READ_UNCOMMITTED;
06285         *valLen = sizeof (SQLUINTEGER);
06286         break;
06287     case SQL_IDENTIFIER_CASE:
06288         *((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
06289         *valLen = sizeof (SQLSMALLINT);
06290         break;
06291     case SQL_IDENTIFIER_QUOTE_CHAR:
06292         strmak(val, "\"", valMax, valLen);
06293         break;
06294     case SQL_MAX_TABLE_NAME_LEN:
06295     case SQL_MAX_COLUMN_NAME_LEN:
06296         *((SQLSMALLINT *) val) = 255;
06297         *valLen = sizeof (SQLSMALLINT);
06298         break;
06299     case SQL_MAX_CURSOR_NAME_LEN:
06300         *((SWORD *) val) = 255;
06301         *valLen = sizeof (SWORD);
06302         break;
06303     case SQL_MAX_PROCEDURE_NAME_LEN:
06304         *((SQLSMALLINT *) val) = 0;
06305         break;
06306     case SQL_MAX_QUALIFIER_NAME_LEN:
06307     case SQL_MAX_OWNER_NAME_LEN:
06308         *((SQLSMALLINT *) val) = 255;
06309         break;
06310     case SQL_OWNER_TERM:
06311         strmak(val, "owner", valMax, valLen);
06312         break;
06313     case SQL_PROCEDURE_TERM:
06314         strmak(val, "procedure", valMax, valLen);
06315         break;
06316     case SQL_QUALIFIER_NAME_SEPARATOR:
06317         strmak(val, ".", valMax, valLen);
06318         break;
06319     case SQL_QUALIFIER_TERM:
06320         strmak(val, "database", valMax, valLen);
06321         break;
06322     case SQL_QUALIFIER_USAGE:
06323         *((SQLUINTEGER *) val) = 0;
06324         *valLen = sizeof (SQLUINTEGER);
06325         break;
06326     case SQL_SCROLL_CONCURRENCY:
06327         *((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
06328         *valLen = sizeof (SQLUINTEGER);
06329         break;
06330     case SQL_SCROLL_OPTIONS:
06331         *((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
06332         *valLen = sizeof (SQLUINTEGER);
06333         break;
06334     case SQL_TABLE_TERM:
06335         strmak(val, "table", valMax, valLen);
06336         break;
06337     case SQL_TXN_CAPABLE:
06338         *((SQLSMALLINT *) val) = SQL_TC_ALL;
06339         *valLen = sizeof (SQLSMALLINT);
06340         break;
06341     case SQL_CONVERT_FUNCTIONS:
06342         *((SQLUINTEGER *) val) = 0;
06343         *valLen = sizeof (SQLUINTEGER);
06344        break;
06345     case SQL_SYSTEM_FUNCTIONS:
06346     case SQL_NUMERIC_FUNCTIONS:
06347     case SQL_STRING_FUNCTIONS:
06348     case SQL_TIMEDATE_FUNCTIONS:
06349         *((SQLUINTEGER *) val) = 0;
06350         *valLen = sizeof (SQLUINTEGER);
06351         break;
06352     case SQL_CONVERT_BIGINT:
06353     case SQL_CONVERT_BIT:
06354     case SQL_CONVERT_CHAR:
06355     case SQL_CONVERT_DATE:
06356     case SQL_CONVERT_DECIMAL:
06357     case SQL_CONVERT_DOUBLE:
06358     case SQL_CONVERT_FLOAT:
06359     case SQL_CONVERT_INTEGER:
06360     case SQL_CONVERT_LONGVARCHAR:
06361     case SQL_CONVERT_NUMERIC:
06362     case SQL_CONVERT_REAL:
06363     case SQL_CONVERT_SMALLINT:
06364     case SQL_CONVERT_TIME:
06365     case SQL_CONVERT_TIMESTAMP:
06366     case SQL_CONVERT_TINYINT:
06367     case SQL_CONVERT_VARCHAR:
06368         *((SQLUINTEGER *) val) = 
06369             SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
06370             SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
06371             SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
06372             SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
06373             SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
06374         *valLen = sizeof (SQLUINTEGER);
06375         break;
06376     case SQL_CONVERT_BINARY:
06377     case SQL_CONVERT_VARBINARY:
06378     case SQL_CONVERT_LONGVARBINARY:
06379         *((SQLUINTEGER *) val) = 0;
06380         *valLen = sizeof (SQLUINTEGER);
06381         break;
06382     case SQL_POSITIONED_STATEMENTS:
06383     case SQL_LOCK_TYPES:
06384         *((SQLUINTEGER *) val) = 0;
06385         *valLen = sizeof (SQLUINTEGER);
06386         break;
06387     case SQL_BOOKMARK_PERSISTENCE:
06388         *((SQLUINTEGER *) val) = SQL_BP_SCROLL;
06389         *valLen = sizeof (SQLUINTEGER);
06390         break;
06391     case SQL_UNION:
06392         *((SQLUINTEGER *) val) = SQL_U_UNION;
06393         *valLen = sizeof (SQLUINTEGER);
06394         break;
06395     case SQL_OWNER_USAGE:
06396     case SQL_SUBQUERIES:
06397     case SQL_TIMEDATE_ADD_INTERVALS:
06398     case SQL_TIMEDATE_DIFF_INTERVALS:
06399         *((SQLUINTEGER *) val) = 0;
06400         *valLen = sizeof (SQLUINTEGER);
06401         break;
06402     case SQL_QUOTED_IDENTIFIER_CASE:
06403         *((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
06404         *valLen = sizeof (SQLUSMALLINT);
06405         break;
06406     case SQL_POS_OPERATIONS:
06407         *((SQLUINTEGER *) val) = 0;
06408         *valLen = sizeof (SQLUINTEGER);
06409         break;
06410     case SQL_ALTER_TABLE:
06411         *((SQLUINTEGER *) val) = 0;
06412         *valLen = sizeof (SQLUINTEGER);
06413         break;
06414     case SQL_CORRELATION_NAME:
06415         *((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
06416         *valLen = sizeof (SQLSMALLINT);
06417         break;
06418     case SQL_NON_NULLABLE_COLUMNS:
06419         *((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
06420         *valLen = sizeof (SQLSMALLINT);
06421         break;
06422     case SQL_NULL_COLLATION:
06423         *((SQLSMALLINT *) val) = SQL_NC_START;
06424         *valLen = sizeof(SQLSMALLINT);
06425         break;
06426     case SQL_MAX_COLUMNS_IN_GROUP_BY:
06427     case SQL_MAX_COLUMNS_IN_ORDER_BY:
06428     case SQL_MAX_COLUMNS_IN_SELECT:
06429     case SQL_MAX_COLUMNS_IN_TABLE:
06430     case SQL_MAX_ROW_SIZE:
06431     case SQL_MAX_TABLES_IN_SELECT:
06432         *((SQLSMALLINT *) val) = 0;
06433         *valLen = sizeof (SQLSMALLINT);
06434         break;
06435     case SQL_MAX_BINARY_LITERAL_LEN:
06436     case SQL_MAX_CHAR_LITERAL_LEN:
06437         *((SQLUINTEGER *) val) = 0;
06438         *valLen = sizeof (SQLUINTEGER);
06439         break;
06440     case SQL_MAX_COLUMNS_IN_INDEX:
06441         *((SQLSMALLINT *) val) = 0;
06442         *valLen = sizeof (SQLSMALLINT);
06443         break;
06444     case SQL_MAX_INDEX_SIZE:
06445         *((SQLUINTEGER *) val) = 0;
06446         *valLen = sizeof(SQLUINTEGER);
06447         break;
06448 #ifdef SQL_MAX_IDENTIFIER_LENGTH
06449     case SQL_MAX_IDENTIFIER_LENGTH:
06450         *((SQLUINTEGER *) val) = 255;
06451         *valLen = sizeof (SQLUINTEGER);
06452         break;
06453 #endif
06454     case SQL_MAX_STATEMENT_LEN:
06455         *((SQLUINTEGER *) val) = 16384;
06456         *valLen = sizeof (SQLUINTEGER);
06457         break;
06458     case SQL_QUALIFIER_LOCATION:
06459         *((SQLSMALLINT *) val) = SQL_QL_START;
06460         *valLen = sizeof (SQLSMALLINT);
06461         break;
06462     case SQL_GETDATA_EXTENSIONS:
06463         *((SQLUINTEGER *) val) =
06464             SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
06465         *valLen = sizeof (SQLUINTEGER);
06466         break;
06467     case SQL_STATIC_SENSITIVITY:
06468         *((SQLUINTEGER *) val) = 0;
06469         *valLen = sizeof (SQLUINTEGER);
06470         break;
06471     case SQL_FILE_USAGE:
06472         *((SQLSMALLINT *) val) = SQL_FILE_CATALOG;
06473         *valLen = sizeof (SQLSMALLINT);
06474         break;
06475     case SQL_GROUP_BY:
06476         *((SQLSMALLINT *) val) = 0;
06477         *valLen = sizeof (SQLSMALLINT);
06478         break;
06479     case SQL_KEYWORDS:
06480         strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
06481                "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
06482                valMax, valLen);
06483         break;
06484     case SQL_SPECIAL_CHARACTERS:
06485         strmak(val, "", valMax, valLen);
06486         break;
06487     case SQL_BATCH_SUPPORT:
06488     case SQL_BATCH_ROW_COUNT:
06489     case SQL_PARAM_ARRAY_ROW_COUNTS:
06490         *((SQLUINTEGER *) val) = 0;
06491         *valLen = sizeof (SQLUINTEGER);
06492         break;
06493     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
06494         *((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
06495         *valLen = sizeof (SQLUINTEGER);
06496         break;
06497     case SQL_STATIC_CURSOR_ATTRIBUTES1:
06498         *((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
06499             SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
06500         *valLen = sizeof (SQLUINTEGER);
06501         break;
06502     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
06503     case SQL_STATIC_CURSOR_ATTRIBUTES2:
06504         *((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
06505             SQL_CA2_LOCK_CONCURRENCY;
06506         *valLen = sizeof (SQLUINTEGER);
06507         break;
06508     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
06509     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
06510     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
06511     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
06512         *((SQLUINTEGER *) val) = 0;
06513         *valLen = sizeof (SQLUINTEGER);
06514         break;
06515     case SQL_ODBC_INTERFACE_CONFORMANCE:
06516         *((SQLUINTEGER *) val) = SQL_OIC_CORE;
06517         *valLen = sizeof (SQLUINTEGER);
06518         break;
06519     default:
06520         setstatd(d, -1, "unsupported info option %d",
06521                  (*d->ov3) ? "HYC00" : "S1C00", type);
06522         return SQL_ERROR;
06523     }
06524     return SQL_SUCCESS;
06525 }
06526 
06527 #if (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC) || !defined(SQLITE_UTF8)
06528 
06538 SQLRETURN SQL_API
06539 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
06540            SQLSMALLINT *valLen)
06541 {
06542     return drvgetinfo(dbc, type, val, valMax, valLen);
06543 }
06544 #endif
06545 
06546 #ifdef SQLITE_UTF8
06547 
06557 SQLRETURN SQL_API
06558 SQLGetInfoW(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
06559             SQLSMALLINT *valLen)
06560 {
06561     SQLRETURN ret;
06562     SQLSMALLINT len;
06563 
06564     ret = drvgetinfo(dbc, type, val, valMax, &len);
06565     if (ret == SQL_SUCCESS) {
06566         SQLWCHAR *v = NULL;
06567 
06568         switch (type) {
06569         case SQL_USER_NAME:
06570         case SQL_DRIVER_ODBC_VER:
06571         case SQL_DATA_SOURCE_NAME:
06572         case SQL_DRIVER_NAME:
06573         case SQL_DRIVER_VER:
06574         case SQL_ODBC_VER:
06575         case SQL_SERVER_NAME:
06576         case SQL_DATABASE_NAME:
06577         case SQL_SEARCH_PATTERN_ESCAPE:
06578         case SQL_DBMS_NAME:
06579         case SQL_DBMS_VER:
06580         case SQL_NEED_LONG_DATA_LEN:
06581         case SQL_ROW_UPDATES:
06582         case SQL_ACCESSIBLE_PROCEDURES:
06583         case SQL_PROCEDURES:
06584         case SQL_EXPRESSIONS_IN_ORDERBY:
06585         case SQL_ODBC_SQL_OPT_IEF:
06586         case SQL_LIKE_ESCAPE_CLAUSE:
06587         case SQL_ORDER_BY_COLUMNS_IN_SELECT:
06588         case SQL_OUTER_JOINS:
06589         case SQL_COLUMN_ALIAS:
06590         case SQL_ACCESSIBLE_TABLES:
06591         case SQL_MULT_RESULT_SETS:
06592         case SQL_MULTIPLE_ACTIVE_TXN:
06593         case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
06594         case SQL_DATA_SOURCE_READ_ONLY:
06595 #ifdef SQL_DESCRIBE_PARAMETER
06596         case SQL_DESCRIBE_PARAMETER:
06597 #endif
06598         case SQL_IDENTIFIER_QUOTE_CHAR:
06599         case SQL_OWNER_TERM:
06600         case SQL_PROCEDURE_TERM:
06601         case SQL_QUALIFIER_NAME_SEPARATOR:
06602         case SQL_QUALIFIER_TERM:
06603         case SQL_TABLE_TERM:
06604         case SQL_KEYWORDS:
06605         case SQL_SPECIAL_CHARACTERS:
06606             if (val) {
06607                 if (len > 0) {
06608                     v = uc_from_utf((char *) val, len);
06609                     if (v) {
06610                         int vmax = valMax / sizeof (SQLWCHAR);
06611 
06612                         uc_strncpy(val, v, vmax);
06613                         len = min(vmax, uc_strlen(v));
06614                         uc_free(v);
06615                         len *= sizeof (SQLWCHAR);
06616                     } else {
06617                         len = 0;
06618                     }
06619                 }
06620                 if (len <= 0) {
06621                     len = 0;
06622                     if (valMax >= sizeof (SQLWCHAR)) {
06623                         *((SQLWCHAR *)val) = 0;
06624                     }
06625                 }
06626             } else {
06627                 len = 0;
06628             }
06629             break;
06630         }
06631         if (valLen) {
06632             *valLen = len;
06633         }
06634     }
06635     return ret;
06636 }
06637 #endif
06638 
06647 SQLRETURN SQL_API
06648 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
06649                 SQLUSMALLINT *flags)
06650 {
06651     DBC *d;
06652     int i;
06653     SQLUSMALLINT exists[100];
06654 
06655     if (dbc == SQL_NULL_HDBC) {
06656         return SQL_INVALID_HANDLE;
06657     }
06658     d = (DBC *) dbc;
06659     for (i = 0; i < array_size(exists); i++) {
06660         exists[i] = SQL_FALSE;
06661     }
06662     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
06663     exists[SQL_API_SQLFETCH] = SQL_TRUE;
06664     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
06665     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
06666     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
06667     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
06668     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
06669     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
06670     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
06671     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
06672     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
06673     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
06674     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
06675     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
06676     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
06677     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
06678     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
06679     exists[SQL_API_SQLSETCURSORNAME] = SQL_FALSE;
06680     exists[SQL_API_SQLERROR] = SQL_TRUE;
06681     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
06682     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
06683     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
06684     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
06685     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
06686     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
06687     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
06688     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
06689     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
06690     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
06691     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
06692     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
06693     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
06694     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
06695     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
06696     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
06697     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
06698     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
06699     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
06700     exists[SQL_API_SQLTABLES] = SQL_TRUE;
06701     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
06702     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
06703     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
06704     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
06705     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
06706     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
06707     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
06708     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
06709     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
06710     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
06711     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
06712     exists[SQL_API_SQLSETPOS] = SQL_FALSE;
06713     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
06714     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
06715     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
06716     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_FALSE;
06717     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
06718     if (func == SQL_API_ALL_FUNCTIONS) {
06719         memcpy(flags, exists, sizeof (exists));
06720     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
06721         int i;
06722 #define SET_EXISTS(x) \
06723         flags[(x) >> 4] |= (1 << ((x) & 0xF))
06724 #define CLR_EXISTS(x) \
06725         flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
06726 
06727         memset(flags, 0,
06728                sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
06729         for (i = 0; i < array_size(exists); i++) {
06730             if (exists[i]) {
06731                 flags[i >> 4] |= (1 << (i & 0xF));
06732             }
06733         }
06734         SET_EXISTS(SQL_API_SQLALLOCHANDLE);
06735         SET_EXISTS(SQL_API_SQLFREEHANDLE);
06736         SET_EXISTS(SQL_API_SQLGETSTMTATTR);
06737         SET_EXISTS(SQL_API_SQLSETSTMTATTR);
06738         SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
06739         SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
06740         SET_EXISTS(SQL_API_SQLGETENVATTR);
06741         SET_EXISTS(SQL_API_SQLSETENVATTR);
06742         SET_EXISTS(SQL_API_SQLCLOSECURSOR);
06743         SET_EXISTS(SQL_API_SQLBINDPARAM);
06744 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
06745         /*
06746          * Some unixODBC versions have problems with
06747          * SQLError() vs. SQLGetDiagRec() with loss
06748          * of error/warning messages.
06749          */
06750         SET_EXISTS(SQL_API_SQLGETDIAGREC);
06751 #endif
06752         SET_EXISTS(SQL_API_SQLFETCHSCROLL);
06753         SET_EXISTS(SQL_API_SQLENDTRAN);
06754     } else {
06755         if (func < array_size(exists)) {
06756             *flags = exists[func];
06757         } else {
06758             switch (func) {
06759             case SQL_API_SQLALLOCHANDLE:
06760             case SQL_API_SQLFREEHANDLE:
06761             case SQL_API_SQLGETSTMTATTR:
06762             case SQL_API_SQLSETSTMTATTR:
06763             case SQL_API_SQLGETCONNECTATTR:
06764             case SQL_API_SQLSETCONNECTATTR:
06765             case SQL_API_SQLGETENVATTR:
06766             case SQL_API_SQLSETENVATTR:
06767             case SQL_API_SQLCLOSECURSOR:
06768             case SQL_API_SQLBINDPARAM:
06769 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
06770             /*
06771              * Some unixODBC versions have problems with
06772              * SQLError() vs. SQLGetDiagRec() with loss
06773              * of error/warning messages.
06774              */
06775             case SQL_API_SQLGETDIAGREC:
06776 #endif
06777             case SQL_API_SQLFETCHSCROLL:
06778             case SQL_API_SQLENDTRAN:
06779                 *flags = SQL_TRUE;
06780                 break;
06781             default:
06782                 *flags = SQL_FALSE;
06783             }
06784         }
06785     }
06786     return SQL_SUCCESS;
06787 }
06788 
06795 static SQLRETURN
06796 drvallocenv(SQLHENV *env)
06797 {
06798     ENV *e;
06799 
06800     if (env == NULL) {
06801         return SQL_INVALID_HANDLE;
06802     }
06803     e = (ENV *) xmalloc(sizeof (ENV));
06804     if (e == NULL) {
06805         *env = SQL_NULL_HENV;
06806         return SQL_ERROR;
06807     }
06808     e->magic = ENV_MAGIC;
06809     e->ov3 = 0;
06810     e->dbcs = NULL;
06811     *env = (SQLHENV) e;
06812     return SQL_SUCCESS;
06813 }
06814 
06821 SQLRETURN SQL_API
06822 SQLAllocEnv(SQLHENV *env)
06823 {
06824     return drvallocenv(env);
06825 }
06826 
06833 static SQLRETURN
06834 drvfreeenv(SQLHENV env)
06835 {
06836     ENV *e;
06837 
06838     if (env == SQL_NULL_HENV) {
06839         return SQL_INVALID_HANDLE;
06840     }
06841     e = (ENV *) env;
06842     if (e->magic != ENV_MAGIC) {
06843         return SQL_SUCCESS;
06844     }
06845     if (e->dbcs) {
06846         return SQL_ERROR;
06847     }
06848     e->magic = DEAD_MAGIC;
06849     xfree(e);
06850     return SQL_SUCCESS;
06851 }
06852 
06859 SQLRETURN SQL_API
06860 SQLFreeEnv(SQLHENV env)
06861 {
06862     return drvfreeenv(env);
06863 }
06864 
06872 static SQLRETURN
06873 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
06874 {
06875     DBC *d;
06876     ENV *e;
06877     const char *verstr;
06878     int maj = 0, min = 0, lev = 0;
06879 
06880     if (dbc == NULL) {
06881         return SQL_ERROR;
06882     }
06883     d = (DBC *) xmalloc(sizeof (DBC));
06884     if (d == NULL) {
06885         *dbc = SQL_NULL_HDBC;
06886         return SQL_ERROR;
06887     }
06888     memset(d, 0, sizeof (DBC));
06889     d->curtype = SQL_CURSOR_STATIC;
06890 #if HAVE_LIBVERSION
06891     verstr = sqlite_libversion();
06892 #else
06893     verstr = sqlite_version;
06894 #endif
06895     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
06896     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
06897     if (d->version < verinfo(2, 8, 0)) {
06898         xfree(d);
06899         return SQL_ERROR;
06900     }
06901     d->ov3 = &d->ov3val;
06902     e = (ENV *) env;
06903     if (e->magic == ENV_MAGIC) {
06904         DBC *n, *p;
06905 
06906         d->env = e;
06907         d->ov3 = &e->ov3;
06908         p = NULL;
06909         n = e->dbcs;
06910         while (n) {
06911             p = n;
06912             n = n->next;
06913         }
06914         if (p) {
06915             p->next = d;
06916         } else {
06917             e->dbcs = d;
06918         }
06919     }
06920     d->autocommit = 1;
06921     d->magic = DBC_MAGIC;
06922     *dbc = (SQLHDBC) d;
06923     drvgetgpps(d);
06924     return SQL_SUCCESS;
06925 }
06926 
06934 SQLRETURN SQL_API
06935 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
06936 {
06937     return drvallocconnect(env, dbc);
06938 }
06939 
06946 static SQLRETURN
06947 drvfreeconnect(SQLHDBC dbc)
06948 {
06949     DBC *d;
06950     ENV *e;
06951 
06952     if (dbc == SQL_NULL_HDBC) {
06953         return SQL_INVALID_HANDLE;
06954     }
06955     d = (DBC *) dbc;
06956     if (d->magic != DBC_MAGIC) {
06957         return SQL_INVALID_HANDLE;
06958     }
06959     if (d->sqlite) {
06960         setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
06961         return SQL_ERROR;
06962     }
06963     while (d->stmt) {
06964         freestmt((HSTMT) d->stmt);
06965     }
06966     e = d->env;
06967     if (e && e->magic == ENV_MAGIC) {
06968         DBC *n, *p;
06969 
06970         p = NULL;
06971         n = e->dbcs;
06972         while (n) {
06973             if (n == d) {
06974                 break;
06975             }
06976             p = n;
06977             n = n->next;
06978         }
06979         if (n) {
06980             if (p) {
06981                 p->next = d->next;
06982             } else {
06983                 e->dbcs = d->next;
06984             }
06985         }
06986     }
06987     drvrelgpps(d);
06988     d->magic = DEAD_MAGIC;
06989 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
06990     if (d->trace) {
06991         fclose(d->trace);
06992     }
06993 #endif
06994     xfree(d);
06995     return SQL_SUCCESS;
06996 }
06997 
07004 SQLRETURN SQL_API
07005 SQLFreeConnect(SQLHDBC dbc)
07006 {
07007     return drvfreeconnect(dbc);
07008 }
07009 
07020 static SQLRETURN
07021 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
07022                   SQLINTEGER bufmax, SQLINTEGER *buflen)
07023 {
07024     DBC *d;
07025     SQLINTEGER dummy;
07026 
07027     if (dbc == SQL_NULL_HDBC) {
07028         return SQL_INVALID_HANDLE;
07029     }
07030     d = (DBC *) dbc;
07031     if (!val) {
07032         val = (SQLPOINTER) &dummy;
07033     }
07034     if (!buflen) {
07035         buflen = &dummy;
07036     }
07037     switch (attr) {
07038     case SQL_ATTR_CONNECTION_DEAD:
07039         *((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
07040         *buflen = sizeof (SQLINTEGER);
07041         break;
07042     case SQL_ATTR_ACCESS_MODE:
07043         *((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
07044         *buflen = sizeof (SQLINTEGER);
07045         break;
07046     case SQL_ATTR_AUTOCOMMIT:
07047         *((SQLINTEGER *) val) =
07048             d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
07049         *buflen = sizeof (SQLINTEGER);
07050         break;
07051     case SQL_ATTR_LOGIN_TIMEOUT:
07052         *((SQLINTEGER *) val) = 100;
07053         *buflen = sizeof (SQLINTEGER);
07054         break;
07055     case SQL_ATTR_ODBC_CURSORS:
07056         *((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
07057         *buflen = sizeof (SQLINTEGER);
07058         break;
07059     case SQL_ATTR_PACKET_SIZE:
07060         *((SQLINTEGER *) val) = 16384;
07061         *buflen = sizeof (SQLINTEGER);
07062         break;
07063     case SQL_ATTR_TXN_ISOLATION:
07064         *((SQLINTEGER *) val) = SQL_TXN_READ_UNCOMMITTED;
07065         *buflen = sizeof (SQLINTEGER);
07066         break;
07067     case SQL_ATTR_TRACE:
07068     case SQL_ATTR_TRACEFILE:
07069     case SQL_ATTR_QUIET_MODE:
07070     case SQL_ATTR_TRANSLATE_OPTION:
07071     case SQL_ATTR_KEYSET_SIZE:
07072     case SQL_ATTR_QUERY_TIMEOUT:
07073     case SQL_ATTR_PARAM_BIND_TYPE:
07074     case SQL_ATTR_CURRENT_CATALOG:
07075         *((SQLINTEGER *) val) = 0;
07076         *buflen = sizeof (SQLINTEGER);
07077         break;
07078     case SQL_ATTR_ROW_BIND_TYPE:
07079         *((SQLUINTEGER *) val) = SQL_BIND_BY_COLUMN;
07080         *buflen = sizeof (SQLUINTEGER);
07081         break;
07082     case SQL_ATTR_USE_BOOKMARKS:
07083         *((SQLINTEGER *) val) = SQL_UB_OFF;
07084         *buflen = sizeof (SQLINTEGER);
07085         break;
07086     case SQL_ATTR_ASYNC_ENABLE:
07087         *((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
07088         *buflen = sizeof (SQLINTEGER);
07089         break;
07090     case SQL_ATTR_NOSCAN:
07091         *((SQLINTEGER *) val) = SQL_NOSCAN_ON;
07092         *buflen = sizeof (SQLINTEGER);
07093         break;
07094     case SQL_ATTR_CONCURRENCY:
07095         *((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
07096         *buflen = sizeof (SQLINTEGER);
07097         break;
07098     case SQL_ATTR_SIMULATE_CURSOR:
07099         *((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
07100         *buflen = sizeof (SQLINTEGER);
07101         break;
07102     case SQL_ATTR_MAX_ROWS:
07103     case SQL_ATTR_MAX_LENGTH:
07104         *((SQLINTEGER *) val) = 1000000000;
07105         *buflen = sizeof (SQLINTEGER);
07106         break;
07107     case SQL_ATTR_CURSOR_TYPE:
07108         *((SQLINTEGER *) val) = d->curtype;
07109         *buflen = sizeof (SQLINTEGER);
07110         break;
07111     case SQL_ATTR_RETRIEVE_DATA:
07112         *((SQLINTEGER *) val) = SQL_RD_ON;
07113         *buflen = sizeof (SQLINTEGER);
07114         break;
07115     default:
07116         *((SQLINTEGER *) val) = 0;
07117         *buflen = sizeof (SQLINTEGER);
07118         setstatd(d, -1, "unsupported connect attribute %d",
07119                  (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
07120         return SQL_ERROR;
07121     }
07122     return SQL_SUCCESS;
07123 }
07124 
07125 #ifndef SQLITE_UTF8
07126 
07136 SQLRETURN SQL_API
07137 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
07138                   SQLINTEGER bufmax, SQLINTEGER *buflen)
07139 {
07140     return drvgetconnectattr(dbc, attr, val, bufmax, buflen);
07141 }
07142 #endif
07143 
07144 #ifdef SQLITE_UTF8
07145 
07155 SQLRETURN SQL_API
07156 SQLGetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
07157                    SQLINTEGER bufmax, SQLINTEGER *buflen)
07158 {
07159     return drvgetconnectattr(dbc, attr, val, bufmax, buflen);
07160 }
07161 #endif
07162 
07172 static SQLRETURN
07173 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
07174                   SQLINTEGER len)
07175 {
07176     DBC *d;
07177 
07178     if (dbc == SQL_NULL_HDBC) {
07179         return SQL_INVALID_HANDLE;
07180     }
07181     d = (DBC *) dbc;
07182     switch (attr) {
07183     case SQL_AUTOCOMMIT:
07184         if (len == SQL_IS_INTEGER) {
07185             d->autocommit = (SQLINTEGER) val == SQL_AUTOCOMMIT_ON;
07186             goto doit;
07187         }
07188         if (val && len >= sizeof (SQLINTEGER)) {
07189             d->autocommit = *((SQLINTEGER *) val) == SQL_AUTOCOMMIT_ON;
07190 doit:
07191             if (d->autocommit && d->intrans) {
07192                 return endtran(d, SQL_COMMIT);
07193             } else if (!d->autocommit) {
07194                 vm_end(d->vm_stmt);
07195             }
07196         }
07197         break;
07198     default:
07199         setstatd(d, -1, "option value changed", "01S02");
07200         return SQL_SUCCESS_WITH_INFO;
07201     }
07202     return SQL_SUCCESS;
07203 }
07204 
07205 #ifndef SQLITE_UTF8
07206 
07215 SQLRETURN SQL_API
07216 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
07217                   SQLINTEGER len)
07218 {
07219     return drvsetconnectattr(dbc, attr, val, len);
07220 }
07221 #endif
07222 
07223 #ifdef SQLITE_UTF8
07224 
07233 SQLRETURN SQL_API
07234 SQLSetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
07235                    SQLINTEGER len)
07236 {
07237     return drvsetconnectattr(dbc, attr, val, len);
07238 }
07239 #endif
07240 
07249 static SQLRETURN
07250 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
07251 {
07252     DBC *d;
07253     SQLINTEGER dummy;
07254 
07255     if (dbc == SQL_NULL_HDBC) {
07256         return SQL_INVALID_HANDLE;
07257     }
07258     d = (DBC *) dbc;
07259     if (!param) {
07260         param = (SQLPOINTER) &dummy;
07261     }
07262     switch (opt) {
07263     case SQL_ACCESS_MODE:
07264         *((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
07265         break;
07266     case SQL_AUTOCOMMIT:
07267         *((SQLINTEGER *) param) =
07268             d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
07269         break;
07270     case SQL_LOGIN_TIMEOUT:
07271         *((SQLINTEGER *) param) = 100;
07272         break;
07273     case SQL_ODBC_CURSORS:
07274         *((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
07275         break;
07276     case SQL_PACKET_SIZE:
07277         *((SQLINTEGER *) param) = 16384;
07278         break;
07279     case SQL_TXN_ISOLATION:
07280         *((SQLINTEGER *) param) = SQL_TXN_READ_UNCOMMITTED;
07281         break;
07282     case SQL_OPT_TRACE:
07283     case SQL_OPT_TRACEFILE:
07284     case SQL_QUIET_MODE:
07285     case SQL_TRANSLATE_DLL:
07286     case SQL_TRANSLATE_OPTION:
07287     case SQL_KEYSET_SIZE:
07288     case SQL_QUERY_TIMEOUT:
07289     case SQL_BIND_TYPE:
07290     case SQL_CURRENT_QUALIFIER:
07291         *((SQLINTEGER *) param) = 0;
07292         break;
07293     case SQL_USE_BOOKMARKS:
07294         *((SQLINTEGER *) param) = SQL_UB_OFF;
07295         break;
07296     case SQL_ASYNC_ENABLE:
07297         *((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
07298         break;
07299     case SQL_NOSCAN:
07300         *((SQLINTEGER *) param) = SQL_NOSCAN_ON;
07301         break;
07302     case SQL_CONCURRENCY:
07303         *((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
07304         break;
07305     case SQL_SIMULATE_CURSOR:
07306         *((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
07307         break;
07308     case SQL_ROWSET_SIZE:
07309     case SQL_MAX_ROWS:
07310     case SQL_MAX_LENGTH:
07311         *((SQLINTEGER *) param) = 1000000000;
07312         break;
07313     case SQL_CURSOR_TYPE:
07314         *((SQLINTEGER *) param) = d->curtype;
07315         break;
07316     case SQL_RETRIEVE_DATA:
07317         *((SQLINTEGER *) param) = SQL_RD_ON;
07318         break;
07319     default:
07320         *((SQLINTEGER *) param) = 0;
07321         setstatd(d, -1, "unsupported connect option %d",
07322                  (*d->ov3) ? "HYC00" : "S1C00", opt);
07323         return SQL_ERROR;
07324     }
07325     return SQL_SUCCESS;
07326 }
07327 
07328 #ifndef SQLITE_UTF8
07329 
07337 SQLRETURN SQL_API
07338 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
07339 {
07340     return drvgetconnectoption(dbc, opt, param);
07341 }
07342 #endif
07343 
07344 #ifdef SQLITE_UTF8
07345 
07353 SQLRETURN SQL_API
07354 SQLGetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
07355 {
07356     return drvgetconnectoption(dbc, opt, param);
07357 }
07358 #endif
07359 
07368 static SQLRETURN
07369 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
07370 {
07371     DBC *d;
07372 
07373     if (dbc == SQL_NULL_HDBC) {
07374         return SQL_INVALID_HANDLE;
07375     }
07376     d = (DBC *) dbc;
07377     switch (opt) {
07378     case SQL_AUTOCOMMIT:
07379         d->autocommit = param == SQL_AUTOCOMMIT_ON;
07380         if (d->autocommit && d->intrans) {
07381             return endtran(d, SQL_COMMIT);
07382         } else if (!d->autocommit) {
07383             vm_end(d->vm_stmt);
07384         }
07385         break;
07386     default:
07387         setstatd(d, -1, "option value changed", "01S02");
07388         return SQL_SUCCESS_WITH_INFO;
07389     }
07390     return SQL_SUCCESS;
07391 }
07392 
07393 #ifndef SQLITE_UTF8
07394 
07402 SQLRETURN SQL_API
07403 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
07404 {
07405     return drvsetconnectoption(dbc, opt, param);
07406 }
07407 #endif
07408 
07409 #ifdef SQLITE_UTF8
07410 
07418 SQLRETURN SQL_API
07419 SQLSetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
07420 {
07421     return drvsetconnectoption(dbc, opt, param);
07422 }
07423 #endif
07424 
07425 #if defined(WITHOUT_DRIVERMGR) || !defined(_WIN32)
07426 
07437 static int
07438 getdsnattr(char *dsn, char *attr, char *out, int outLen)
07439 {
07440     char *str = dsn, *start;
07441     int len = strlen(attr);
07442 
07443     while (*str) {
07444         while (*str && *str == ';') {
07445             ++str;
07446         }
07447         start = str;
07448         if ((str = strchr(str, '=')) == NULL) {
07449             return 0;
07450         }
07451         if (str - start == len &&
07452 #ifdef _WIN32
07453             _strnicmp(start, attr, len) == 0
07454 #else
07455             strncasecmp(start, attr, len) == 0
07456 #endif
07457            ) {
07458             start = ++str;
07459             while (*str && *str != ';') {
07460                 ++str;
07461             }
07462             len = min(outLen - 1, str - start);
07463             strncpy(out, start, len);
07464             out[len] = '\0';
07465             return 1;
07466         }
07467         while (*str && *str != ';') {
07468             ++str;
07469         }
07470     }
07471     return 0;
07472 }
07473 #endif
07474 
07483 static SQLRETURN
07484 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen)
07485 {
07486     DBC *d;
07487     int len;
07488     char buf[SQL_MAX_MESSAGE_LENGTH], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
07489     char busy[SQL_MAX_MESSAGE_LENGTH / 4];
07490     char sflag[32], nwflag[32];
07491 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
07492     char tracef[SQL_MAX_MESSAGE_LENGTH];
07493 #endif
07494 
07495     if (dbc == SQL_NULL_HDBC) {
07496         return SQL_INVALID_HANDLE;
07497     }
07498     d = (DBC *) dbc;
07499     if (d->magic != DBC_MAGIC) {
07500         return SQL_INVALID_HANDLE;
07501     }
07502     if (d->sqlite != NULL) {
07503         setstatd(d, -1, "connection already established", "08002");
07504         return SQL_ERROR;
07505     }
07506     buf[0] = '\0';
07507     if (dsnLen == SQL_NTS) {
07508         len = sizeof (buf) - 1;
07509     } else {
07510         len = min(sizeof (buf) - 1, dsnLen);
07511     }
07512     if (dsn != NULL) {
07513         strncpy(buf, dsn, len);
07514     }
07515     buf[len] = '\0';
07516     if (buf[0] == '\0') {
07517         setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
07518         return SQL_ERROR;
07519     }
07520     busy[0] = '\0';
07521     dbname[0] = '\0';
07522 #ifdef WITHOUT_DRIVERMGR
07523     getdsnattr(buf, "database", dbname, sizeof (dbname));
07524     if (dbname[0] == '\0') {
07525         strncpy(dbname, buf, sizeof (dbname));
07526         dbname[sizeof (dbname) - 1] = '\0';
07527     }
07528     getdsnattr(buf, "timeout", busy, sizeof (busy));
07529     sflag[0] = '\0';
07530     nwflag[0] = '\0';
07531     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
07532     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
07533 #else
07534     SQLGetPrivateProfileString(buf, "timeout", "1000",
07535                                busy, sizeof (busy), ODBC_INI);
07536     SQLGetPrivateProfileString(buf, "database", "",
07537                                dbname, sizeof (dbname), ODBC_INI);
07538     SQLGetPrivateProfileString(buf, "stepapi", "",
07539                                sflag, sizeof (sflag), ODBC_INI);
07540     SQLGetPrivateProfileString(buf, "nowchar", "",
07541                                nwflag, sizeof (nwflag), ODBC_INI);
07542 #endif
07543 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
07544     tracef[0] = '\0';
07545 #ifdef WITHOUT_DRIVERMGR
07546     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
07547 #else
07548     SQLGetPrivateProfileString(buf, "tracefile", "",
07549                                tracef, sizeof (tracef), ODBC_INI);
07550 #endif
07551     if (tracef[0] != '\0') {
07552         d->trace = fopen(tracef, "a");
07553     }
07554 #endif
07555     d->nowchar = getbool(nwflag);
07556     return dbopen(d, dbname, dsn, sflag, busy);
07557 }
07558 
07559 #ifndef SQLITE_UTF8
07560 
07572 SQLRETURN SQL_API
07573 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
07574            SQLCHAR *uid, SQLSMALLINT uidLen,
07575            SQLCHAR *pass, SQLSMALLINT passLen)
07576 {
07577     return drvconnect(dbc, dsn, dsnLen);
07578 }
07579 #endif
07580 
07581 #ifdef SQLITE_UTF8
07582 
07594 SQLRETURN SQL_API
07595 SQLConnectW(SQLHDBC dbc, SQLWCHAR *dsn, SQLSMALLINT dsnLen,
07596             SQLWCHAR *uid, SQLSMALLINT uidLen,
07597             SQLWCHAR *pass, SQLSMALLINT passLen)
07598 {
07599     char *dsna = NULL;
07600     SQLRETURN ret;
07601 
07602     if (dsn) {
07603         dsna = uc_to_utf_c(dsn, dsnLen);
07604         if (!dsna) {
07605             DBC *d = (DBC *) dbc;
07606 
07607             setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
07608             return SQL_ERROR;
07609         }
07610     }
07611     ret = drvconnect(dbc, dsna, SQL_NTS);
07612     uc_free(dsna);
07613     return ret;
07614 }
07615 #endif
07616 
07623 SQLRETURN SQL_API
07624 SQLDisconnect(SQLHDBC dbc)
07625 {
07626     DBC *d;
07627 
07628     if (dbc == SQL_NULL_HDBC) {
07629         return SQL_INVALID_HANDLE;
07630     }
07631     d = (DBC *) dbc;
07632     if (d->magic != DBC_MAGIC) {
07633         return SQL_INVALID_HANDLE;
07634     }
07635     if (d->intrans) {
07636         setstatd(d, -1, "incomplete transaction", "25000");
07637         return SQL_ERROR;
07638     }
07639     if (d->vm_stmt) {
07640         vm_end(d->vm_stmt);
07641     }
07642     if (d->sqlite) {
07643         sqlite_close(d->sqlite);
07644         d->sqlite = NULL;
07645     }
07646     freep(&d->dbname);
07647     freep(&d->dsn);
07648     return SQL_SUCCESS;
07649 }
07650 
07651 #if defined(WITHOUT_DRIVERMGR) || !defined(_WIN32)
07652 
07666 static SQLRETURN
07667 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
07668                  SQLCHAR *connIn, SQLSMALLINT connInLen,
07669                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
07670                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
07671 {
07672     DBC *d;
07673     int len;
07674     char buf[SQL_MAX_MESSAGE_LENGTH], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
07675     char dsn[SQL_MAX_MESSAGE_LENGTH / 4], busy[SQL_MAX_MESSAGE_LENGTH / 4];
07676     char sflag[32];
07677 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
07678     char tracef[SQL_MAX_MESSAGE_LENGTH];
07679 #endif
07680 
07681     if (dbc == SQL_NULL_HDBC || hwnd != NULL) {
07682         return SQL_INVALID_HANDLE;
07683     }
07684     if (drvcompl != SQL_DRIVER_COMPLETE &&
07685         drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
07686         drvcompl != SQL_DRIVER_PROMPT &&
07687         drvcompl != SQL_DRIVER_NOPROMPT) {
07688         return SQL_NO_DATA;
07689     }
07690     d = (DBC *) dbc;
07691     if (d->sqlite) {
07692         setstatd(d, -1, "connection already established", "08002");
07693         return SQL_ERROR;
07694     }
07695     buf[0] = '\0';
07696     if (connInLen == SQL_NTS) {
07697         len = sizeof (buf) - 1;
07698     } else {
07699         len = min(connInLen, sizeof (buf) - 1);
07700     }
07701     if (connIn != NULL) {
07702         strncpy(buf, connIn, len);
07703     }
07704     buf[len] = '\0';
07705     if (!buf[0]) {
07706         setstatd(d, -1, "invalid connect attributes",
07707                  (*d->ov3) ? "HY090" : "S1090");
07708         return SQL_ERROR;
07709     }
07710     dsn[0] = '\0';
07711     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
07712 
07713     /* special case: connIn is sole DSN value without keywords */
07714     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
07715         strncpy(dsn, buf, sizeof (dsn) - 1);
07716         dsn[sizeof (dsn) - 1] = '\0';
07717     }
07718 
07719     busy[0] = '\0';
07720     getdsnattr(buf, "timeout", busy, sizeof (busy));
07721 #ifndef WITHOUT_DRIVERMGR
07722     if (dsn[0] && !busy[0]) {
07723         SQLGetPrivateProfileString(dsn, "timeout", "1000",
07724                                    busy, sizeof (busy), ODBC_INI);
07725     }
07726 #endif
07727     dbname[0] = '\0';
07728     getdsnattr(buf, "database", dbname, sizeof (dbname));
07729 #ifndef WITHOUT_DRIVERMGR
07730     if (dsn[0] && !dbname[0]) {
07731         SQLGetPrivateProfileString(dsn, "database", "",
07732                                    dbname, sizeof (dbname), ODBC_INI);
07733     }
07734 #endif
07735     sflag[0] = '\0';
07736     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
07737 #ifndef WITHOUT_DRIVERMGR
07738     if (dsn[0] && !sflag[0]) {
07739         SQLGetPrivateProfileString(dsn, "stepapi", "",
07740                                    sflag, sizeof (sflag), ODBC_INI);
07741     }
07742 #endif
07743     if (!dbname[0] && !dsn[0]) {
07744         strcpy(dsn, "SQLite");
07745         strncpy(dbname, buf, sizeof (dbname));
07746         dbname[sizeof (dbname) - 1] = '\0';
07747     }
07748 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
07749     tracef[0] = '\0';
07750     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
07751 #ifndef WITHOUT_DRIVERMGR
07752     if (dsn[0] && !tracef[0]) {
07753         SQLGetPrivateProfileString(dsn, "tracefile", "",
07754                                    tracef, sizeof (tracef), ODBC_INI);
07755     }
07756 #endif
07757 #endif
07758     if (connOut || connOutLen) {
07759         int count;
07760 
07761         buf[0] = '\0';
07762         count = snprintf(buf, sizeof (buf),
07763 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
07764                          "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s;"
07765                          "Tracefile=%s",
07766                          dsn, dbname, sflag, busy, tracef
07767 #else
07768                          "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s",
07769                          dsn, dbname, sflag, busy
07770 #endif
07771                         );
07772         if (count < 0) {
07773             buf[sizeof (buf) - 1] = '\0';
07774         }
07775         len = min(connOutMax - 1, strlen(buf));
07776         if (connOut) {
07777             strncpy(connOut, buf, len);
07778             connOut[len] = '\0';
07779         }
07780         if (connOutLen) {
07781             *connOutLen = len;
07782         }
07783     }
07784 #if defined(HAVE_SQLITETRACE) && HAVE_SQLITETRACE
07785     if (tracef[0] != '\0') {
07786         d->trace = fopen(tracef, "a");
07787     }
07788 #endif
07789     return dbopen(d, dbname, dsn, sflag, busy);
07790 }
07791 #endif
07792 
07793 /* see doc on top */
07794 
07795 static SQLRETURN
07796 freestmt(SQLHSTMT stmt)
07797 {
07798     STMT *s;
07799     DBC *d;
07800 
07801     if (stmt == SQL_NULL_HSTMT) {
07802         return SQL_INVALID_HANDLE;
07803     }
07804     s = (STMT *) stmt;
07805     freeresult(s, 1);
07806     freep(&s->query);
07807     d = (DBC *) s->dbc;
07808     if (d && d->magic == DBC_MAGIC) {
07809         STMT *p, *n;
07810 
07811         p = NULL;
07812         n = d->stmt;
07813         while (n) {
07814             if (n == s) {
07815                 break;
07816             }
07817             p = n;
07818             n = n->next;
07819         }
07820         if (n) {
07821             if (p) {
07822                 p->next = s->next;
07823             } else {
07824                 d->stmt = s->next;
07825             }
07826         }
07827     }
07828     freeparams(s);
07829     freep(&s->bindparms);
07830     if (s->row_status0 != &s->row_status1) {
07831         freep(&s->row_status0);
07832         s->rowset_size = 1;
07833         s->row_status0 = &s->row_status1;
07834     }
07835     xfree(s);
07836     return SQL_SUCCESS;
07837 }
07838 
07846 static SQLRETURN
07847 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
07848 {
07849     DBC *d;
07850     STMT *s, *sl, *pl;
07851 
07852     if (dbc == SQL_NULL_HDBC) {
07853         return SQL_INVALID_HANDLE;
07854     }
07855     d = (DBC *) dbc;
07856     if (d->magic != DBC_MAGIC || stmt == NULL) {
07857         return SQL_INVALID_HANDLE;
07858     }
07859     s = (STMT *) xmalloc(sizeof (STMT));
07860     if (s == NULL) {
07861         *stmt = SQL_NULL_HSTMT;
07862         return SQL_ERROR;
07863     }
07864     *stmt = (SQLHSTMT) s;
07865     memset(s, 0, sizeof (STMT));
07866     s->dbc = dbc;
07867     s->ov3 = d->ov3;
07868     s->nowchar = d->nowchar;
07869     s->curtype = d->curtype;
07870     s->row_status0 = &s->row_status1;
07871     s->rowset_size = 1;
07872     s->retr_data = SQL_RD_ON;
07873     s->bind_type = SQL_BIND_BY_COLUMN;
07874     s->bind_offs = NULL;
07875     s->paramset_size = 1;
07876     sprintf(s->cursorname, "CUR_%08lX", (long) *stmt);
07877     sl = d->stmt;
07878     pl = NULL;
07879     while (sl) {
07880         pl = sl;
07881         sl = sl->next;
07882     }
07883     if (pl) {
07884         pl->next = s;
07885     } else {
07886         d->stmt = s;
07887     }
07888     return SQL_SUCCESS;
07889 }
07890 
07898 SQLRETURN SQL_API
07899 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
07900 {
07901     return drvallocstmt(dbc, stmt);
07902 }
07903 
07911 static SQLRETURN
07912 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
07913 {
07914     STMT *s;
07915 
07916     if (stmt == SQL_NULL_HSTMT) {
07917         return SQL_INVALID_HANDLE;
07918     }
07919     s = (STMT *) stmt;
07920     switch (opt) {
07921     case SQL_RESET_PARAMS:
07922         freeparams(s);
07923         break;
07924     case SQL_UNBIND:
07925         unbindcols(s);
07926         break;
07927     case SQL_CLOSE:
07928         vm_end_if(s);
07929         freeresult(s, 0);
07930         break;
07931     case SQL_DROP:
07932         vm_end_if(s);
07933         return freestmt(stmt);
07934     default:
07935         setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
07936         return SQL_ERROR;
07937     }
07938     return SQL_SUCCESS;
07939 }
07940 
07948 SQLRETURN SQL_API
07949 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
07950 {
07951     return drvfreestmt(stmt, opt);
07952 }
07953 
07960 SQLRETURN SQL_API
07961 SQLCancel(SQLHSTMT stmt)
07962 {
07963     return drvfreestmt(stmt, SQL_CLOSE);
07964 }
07965 
07975 static SQLRETURN
07976 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
07977                  SQLSMALLINT *lenp)
07978 {
07979     STMT *s;
07980 
07981     if (stmt == SQL_NULL_HSTMT) {
07982         return SQL_INVALID_HANDLE;
07983     }
07984     s = (STMT *) stmt;
07985     if (lenp && !cursor) {
07986         *lenp = strlen(s->cursorname);
07987         return SQL_SUCCESS;
07988     }
07989     if (cursor) {
07990         if (buflen > 0) {
07991             strncpy(cursor, s->cursorname, buflen - 1);
07992             cursor[buflen - 1] = '\0';
07993         }
07994         if (lenp) {
07995             *lenp = min(strlen(s->cursorname), buflen - 1);
07996         }
07997     }
07998     return SQL_SUCCESS;
07999 }
08000 
08001 #ifndef SQLITE_UTF8
08002 
08011 SQLRETURN SQL_API
08012 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
08013                  SQLSMALLINT *lenp)
08014 {
08015     return drvgetcursorname(stmt, cursor, buflen, lenp);
08016 }
08017 #endif
08018 
08019 #ifdef SQLITE_UTF8
08020 
08029 SQLRETURN SQL_API
08030 SQLGetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT buflen,
08031                   SQLSMALLINT *lenp)
08032 {
08033     SQLRETURN ret;
08034     SQLSMALLINT len;
08035 
08036     ret = drvgetcursorname(stmt, (SQLCHAR *) cursor, buflen, &len);
08037     if (ret == SQL_SUCCESS) {
08038         SQLWCHAR *c = NULL;
08039 
08040         if (cursor) {
08041             c = uc_from_utf((char *) cursor, len);
08042             if (!c) {
08043                 return nomem((STMT *) stmt);
08044             }
08045             len = uc_strlen(c);
08046             if (buflen > 0) {
08047                 uc_strncpy(cursor, c, buflen - 1);
08048                 cursor[buflen - 1] = 0;
08049             }
08050             uc_free(c);
08051         }
08052         if (lenp) {
08053             *lenp = min(len, buflen - 1);
08054         }
08055     }
08056     return ret;
08057 }
08058 #endif
08059 
08068 static SQLRETURN
08069 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
08070 {
08071     STMT *s;
08072 
08073     if (stmt == SQL_NULL_HSTMT) {
08074         return SQL_INVALID_HANDLE;
08075     }
08076     s = (STMT *) stmt;
08077     if (!cursor ||
08078         !((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
08079           (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
08080         setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
08081         return SQL_ERROR;
08082     }
08083     if (len == SQL_NTS) {
08084         len = sizeof (s->cursorname) - 1;
08085     } else {
08086         len = min(sizeof (s->cursorname) - 1, len);
08087     }
08088     strncpy(s->cursorname, cursor, len);
08089     s->cursorname[len] = '\0';
08090     return SQL_SUCCESS;
08091 }
08092 
08093 #ifndef SQLITE_UTF8
08094 
08102 SQLRETURN SQL_API
08103 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
08104 {
08105     return drvsetcursorname(stmt, cursor, len);
08106 }
08107 #endif
08108 
08109 #ifdef SQLITE_UTF8
08110 
08118 SQLRETURN SQL_API
08119 SQLSetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT len)
08120 {
08121     char *c = NULL;
08122     SQLRETURN ret;
08123 
08124     if (cursor) {
08125         c = uc_to_utf_c(cursor, len);
08126         if (!c) {
08127             return nomem((STMT *) stmt);
08128         }
08129     }
08130     ret = drvsetcursorname(stmt, c, SQL_NTS);
08131     uc_free(c);
08132     return ret;
08133 }
08134 #endif
08135 
08142 SQLRETURN SQL_API
08143 SQLCloseCursor(SQLHSTMT stmt)
08144 {
08145     return drvfreestmt(stmt, SQL_CLOSE);
08146 }
08147 
08148 #if defined(WITHOUT_DRIVERMGR) || !defined(HAVE_IODBC) || defined(_WIN32)
08149 
08158 SQLRETURN SQL_API
08159 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
08160 {
08161     SQLRETURN ret;
08162 
08163     switch (type) {
08164     case SQL_HANDLE_ENV:
08165         ret = drvallocenv((SQLHENV *) output);
08166         if (ret == SQL_SUCCESS) {
08167             ENV *e = (ENV *) *output;
08168 
08169             if (e && e->magic == ENV_MAGIC) {
08170                 e->ov3 = 1;
08171             }
08172         }
08173         return ret;
08174     case SQL_HANDLE_DBC:
08175         return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
08176     case SQL_HANDLE_STMT:
08177         return drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
08178     }
08179     return SQL_ERROR;
08180 }
08181 #endif
08182 
08183 #if defined(WITHOUT_DRIVERMGR) || !defined(HAVE_IODBC) || defined(_WIN32)
08184 
08192 SQLRETURN SQL_API
08193 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
08194 {
08195     switch (type) {
08196     case SQL_HANDLE_ENV:
08197         return drvfreeenv((SQLHENV) h);
08198     case SQL_HANDLE_DBC:
08199         return drvfreeconnect((SQLHDBC) h);
08200     case SQL_HANDLE_STMT:
08201         return drvfreestmt((SQLHSTMT) h, SQL_DROP);
08202     }
08203     return SQL_ERROR;
08204 }
08205 #endif
08206 
08212 static void
08213 freedyncols(STMT *s)
08214 {
08215     if (s->dyncols) {
08216         int i;
08217 
08218         for (i = 0; i < s->dcols; i++) {
08219             freep(&s->dyncols[i].typename);
08220         }
08221         if (s->cols == s->dyncols) {
08222             s->cols = NULL;
08223             s->ncols = 0;
08224         }
08225         freep(&s->dyncols);
08226     }
08227     s->dcols = 0;
08228 }
08229 
08230 /* see doc on top */
08231 
08232 static void
08233 freeresult(STMT *s, int clrcols)
08234 {
08235 #if HAVE_ENCDEC
08236     freep(&s->bincache);
08237     freep(&s->hexcache);
08238     s->bincell = NULL;
08239 #endif
08240     if (s->rows) {
08241         if (s->rowfree) {
08242             s->rowfree(s->rows);
08243             s->rowfree = NULL;
08244         }
08245         s->rows = NULL;
08246     }
08247     s->nrows = -1;
08248     if (clrcols > 0) {
08249         freep(&s->bindcols);
08250         s->nbindcols = 0;
08251     }
08252     if (clrcols) {
08253         freedyncols(s);
08254         s->cols = NULL;
08255         s->ncols = 0;
08256     }
08257 }
08258 
08259 /* see doc on top */
08260 
08261 static void
08262 unbindcols(STMT *s)
08263 {
08264     int i;
08265 
08266     s->bkmrkcol.type = -1;
08267     s->bkmrkcol.max = 0;
08268     s->bkmrkcol.lenp = NULL;
08269     s->bkmrkcol.valp = NULL;
08270     s->bkmrkcol.index = 0;
08271     s->bkmrkcol.offs = 0;
08272     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
08273         s->bindcols[i].type = -1;
08274         s->bindcols[i].max = 0;
08275         s->bindcols[i].lenp = NULL;
08276         s->bindcols[i].valp = NULL;
08277         s->bindcols[i].index = i;
08278         s->bindcols[i].offs = 0;
08279     }
08280 }
08281 
08282 /* see doc on top */
08283 
08284 static SQLRETURN
08285 mkbindcols(STMT *s, int ncols)
08286 {
08287     if (s->bindcols) {
08288         if (s->nbindcols < ncols) {
08289             int i;
08290             BINDCOL *bindcols =
08291                 xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
08292 
08293             if (!bindcols) {
08294                 return nomem(s);
08295             }
08296             for (i = s->nbindcols; i < ncols; i++) {
08297                 bindcols[i].type = -1;
08298                 bindcols[i].max = 0;
08299                 bindcols[i].lenp = NULL;
08300                 bindcols[i].valp = NULL;
08301                 bindcols[i].index = i;
08302                 bindcols[i].offs = 0;
08303             }
08304             s->bindcols = bindcols;
08305             s->nbindcols = ncols;
08306         }
08307     } else if (ncols > 0) {
08308         s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
08309         if (!s->bindcols) {
08310             return nomem(s);
08311         }
08312         s->nbindcols = ncols;
08313         unbindcols(s);
08314     }
08315     return SQL_SUCCESS;
08316 }
08317 
08331 static SQLRETURN
08332 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
08333            SQLPOINTER val, SQLINTEGER len, SQLINTEGER *lenp, int partial)
08334 {
08335     char **data, valdummy[16];
08336     SQLINTEGER dummy;
08337     int valnull = 0;
08338     int type = otype;
08339 
08340     if (!s->rows) {
08341         return SQL_NO_DATA;
08342     }
08343     if (col >= s->ncols) {
08344         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
08345         return SQL_ERROR;
08346     }
08347     if (s->rowp < 0 || s->rowp >= s->nrows) {
08348         return SQL_NO_DATA;
08349     }
08350     if (s->retr_data != SQL_RD_ON) {
08351         return SQL_SUCCESS;
08352     }
08353     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0,
08354                       s->nowchar);
08355 #if HAVE_ENCDEC
08356     if (otype == SQL_C_CHAR) {
08357         switch (s->cols[col].type) {
08358         case SQL_BINARY:
08359         case SQL_VARBINARY:
08360         case SQL_LONGVARBINARY:
08361             type = SQL_C_BINARY;
08362             break;
08363         }
08364 #ifdef SQLITE_UTF8
08365     } else if (otype == SQL_C_WCHAR) {
08366         switch (s->cols[col].type) {
08367         case SQL_BINARY:
08368         case SQL_VARBINARY:
08369         case SQL_LONGVARBINARY:
08370             type = SQL_C_BINARY;
08371             break;
08372         }
08373 #endif
08374     }
08375 #endif
08376     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
08377     if (!lenp) {
08378         lenp = &dummy;
08379     }
08380     if (!val) {
08381         valnull = 1;
08382         val = (SQLPOINTER) valdummy;
08383     }
08384     if (*data == NULL) {
08385         *lenp = SQL_NULL_DATA;
08386         switch (type) {
08387         case SQL_C_UTINYINT:
08388         case SQL_C_TINYINT:
08389         case SQL_C_STINYINT:
08390             *((char *) val) = 0;
08391             break;
08392         case SQL_C_USHORT:
08393         case SQL_C_SHORT:
08394         case SQL_C_SSHORT:
08395             *((short *) val) = 0;
08396             break;
08397         case SQL_C_ULONG:
08398         case SQL_C_LONG:
08399         case SQL_C_SLONG:
08400             *((long *) val) = 0;
08401             break;
08402         case SQL_C_FLOAT:
08403             *((float *) val) = 0;
08404             break;
08405         case SQL_C_DOUBLE:
08406             *((double *) val) = 0;
08407             break;
08408         case SQL_C_BINARY:
08409         case SQL_C_CHAR:
08410 #ifdef SQLITE_UTF8
08411         case SQL_C_WCHAR:
08412             if (otype == SQL_C_WCHAR) {
08413                 *((SQLWCHAR *) val) = '\0';
08414             } else {
08415                 *((char *) val) = '\0';
08416             }
08417 #else
08418             *((char *) val) = '\0';
08419 #endif
08420             break;
08421 #ifdef SQL_C_TYPE_DATE
08422         case SQL_C_TYPE_DATE:
08423 #endif
08424         case SQL_C_DATE:
08425             memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
08426             break;
08427 #ifdef SQL_C_TYPE_TIME
08428         case SQL_C_TYPE_TIME:
08429 #endif
08430         case SQL_C_TIME:
08431             memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
08432             break;
08433 #ifdef SQL_C_TYPE_TIMESTAMP
08434         case SQL_C_TYPE_TIMESTAMP:
08435 #endif
08436         case SQL_C_TIMESTAMP:
08437             memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
08438             break;
08439         default:
08440             return SQL_ERROR;
08441         }
08442     } else {
08443         char *endp = NULL;
08444 
08445         switch (type) {
08446         case SQL_C_UTINYINT:
08447         case SQL_C_TINYINT:
08448         case SQL_C_STINYINT:
08449             *((char *) val) = strtol(*data, &endp, 0);
08450             if (endp && endp == *data) {
08451                 *lenp = SQL_NULL_DATA;
08452             } else {
08453                 *lenp = sizeof (char);
08454             }
08455             break;
08456         case SQL_C_USHORT:
08457         case SQL_C_SHORT:
08458         case SQL_C_SSHORT:
08459             *((short *) val) = strtol(*data, &endp, 0);
08460             if (endp && endp == *data) {
08461                 *lenp = SQL_NULL_DATA;
08462             } else {
08463                 *lenp = sizeof (short);
08464             }
08465             break;
08466         case SQL_C_ULONG:
08467         case SQL_C_LONG:
08468         case SQL_C_SLONG:
08469             *((int *) val) = strtol(*data, &endp, 0);
08470             if (endp && endp == *data) {
08471                 *lenp = SQL_NULL_DATA;
08472             } else {
08473                 *lenp = sizeof (int);
08474             }
08475             break;
08476         case SQL_C_FLOAT:
08477             *((float *) val) = ln_strtod(*data, &endp);
08478             if (endp && endp == *data) {
08479                 *lenp = SQL_NULL_DATA;
08480             } else {
08481                 *lenp = sizeof (float);
08482             }
08483             break;
08484         case SQL_C_DOUBLE:
08485             *((double *) val) = ln_strtod(*data, &endp);
08486             if (endp && endp == *data) {
08487                 *lenp = SQL_NULL_DATA;
08488             } else {
08489                 *lenp = sizeof (double);
08490             }
08491             break;
08492         case SQL_C_BINARY:
08493 #if HAVE_ENCDEC
08494         {
08495             int dlen, offs = 0;
08496             char *bin, *hex = NULL;
08497 
08498             if (*data == s->bincell && s->bincache) {
08499                 bin = s->bincache;
08500                 dlen = s->binlen;
08501             } else {
08502                 freep(&s->bincache);
08503                 freep(&s->hexcache);
08504                 s->bincell = NULL;
08505                 dlen = strlen(*data);
08506                 bin = xmalloc(dlen + 1);
08507                 if (!bin) {
08508                     return nomem(s);
08509                 }
08510                 dlen = sqlite_decode_binary(*data, bin);
08511                 if (dlen < 0) {
08512                     freep(&bin);
08513                     setstat(s, -1, "error decoding binary data",
08514                             (*s->ov3) ? "HY000" : "S1000");
08515                     return SQL_ERROR;
08516                 }
08517                 s->bincache = bin;
08518                 s->binlen = dlen;
08519                 s->bincell = *data;
08520             }
08521 #ifdef SQLITE_UTF8
08522             if (otype == SQL_C_CHAR || otype == SQL_C_WCHAR) {
08523 #else
08524             if (otype == SQL_C_CHAR) {
08525 #endif
08526                 if (s->hexcache) {
08527                     hex = s->hexcache;
08528                 } else {
08529                     int i, k;
08530 
08531                     hex = xmalloc(dlen * 2 + 1);
08532                     if (!hex) {
08533                         return nomem(s);
08534                     }
08535                     for (i = 0, k = 0; i < dlen; i++) {
08536                         hex[k++] = hexdigits[(bin[i] >> 4) & 0x0f];
08537                         hex[k++] = hexdigits[bin[i] & 0x0f];
08538                     }
08539                     hex[k] = '\0';
08540                     s->hexcache = hex;
08541                 }
08542             }
08543             if (otype == SQL_C_CHAR) {
08544                 bin = hex;
08545                 dlen = dlen * 2;
08546             }
08547 #ifdef SQLITE_UTF8
08548             else if (otype == SQL_C_WCHAR) {
08549                 bin = hex;
08550                 dlen = dlen * 2 * sizeof (SQLWCHAR);
08551             }
08552 #endif
08553             if (partial && len && s->bindcols) {
08554                 if (dlen && s->bindcols[col].offs >= dlen) {
08555                     s->bindcols[col].offs = 0;
08556                     return SQL_NO_DATA;
08557                 }
08558                 offs = s->bindcols[col].offs;
08559                 dlen -= offs;
08560             }
08561             if (val && !valnull && len) {
08562                 int max = min(len, dlen);
08563 
08564 #ifdef SQLITE_UTF8
08565                 if (otype == SQL_C_WCHAR) {
08566                     int i;
08567                     SQLWCHAR *valw = (SQLWCHAR *) val;
08568 
08569                     for (i = 0; i < max; i++) {
08570                        valw[i] = bin[i + offs];
08571                     }
08572                 } else
08573 #endif
08574                     memcpy(val, bin + offs, max);
08575             }
08576             if (valnull || len < 1) {
08577                 *lenp = dlen;
08578             } else {
08579                 *lenp = min(len, dlen);
08580                 if (*lenp == len && *lenp != dlen) {
08581                     *lenp = SQL_NO_TOTAL;
08582                 }
08583             }
08584             if (!valnull) {
08585                 if (otype == SQL_C_CHAR) {
08586                     ((char *) val)[len - 1] = '\0';
08587                 }
08588 #ifdef SQLITE_UTF8
08589                 else if (otype == SQL_C_WCHAR) {
08590                     ((SQLWCHAR *) val)[len / sizeof (SQLWCHAR) - 1] = 0;
08591                 }
08592 #endif
08593             }
08594             if (partial && len && s->bindcols) {
08595                 if (*lenp == SQL_NO_TOTAL) {
08596                     s->bindcols[col].offs += len;
08597                     setstat(s, -1, "data right truncated", "01004");
08598                     if (s->bindcols[col].lenp) {
08599                         *s->bindcols[col].lenp = dlen;
08600                     }
08601                     return SQL_SUCCESS_WITH_INFO;
08602                 }
08603                 s->bindcols[col].offs += *lenp;
08604             }
08605             break;
08606         }
08607 #endif
08608 #ifdef SQLITE_UTF8
08609         case SQL_C_WCHAR:
08610 #endif
08611         case SQL_C_CHAR: {
08612             int doz;
08613             int dlen = strlen(*data);
08614             int offs = 0;
08615 
08616 #ifdef SQLITE_UTF8
08617             SQLWCHAR *ucdata = NULL;
08618 
08619             doz = (type == SQL_C_CHAR || type == SQL_C_WCHAR) ? 1 : 0;
08620             if (otype == SQL_C_WCHAR) {
08621                 ucdata = uc_from_utf(*data, dlen);
08622                 if (!ucdata) {
08623                     return nomem(s);
08624                 }
08625                 dlen = uc_strlen(ucdata) * sizeof (SQLWCHAR);
08626             }
08627 #else
08628             doz = type == SQL_C_CHAR ? 1 : 0;
08629 #endif
08630             if (partial && len && s->bindcols) {
08631                 if (dlen && s->bindcols[col].offs >= dlen) {
08632                     s->bindcols[col].offs = 0;
08633 #ifdef SQLITE_UTF8
08634                     uc_free(ucdata);
08635 #endif
08636                     return SQL_NO_DATA;
08637                 }
08638                 offs = s->bindcols[col].offs;
08639                 dlen -= offs;
08640             }
08641             if (val && !valnull && len) {
08642 #ifdef SQLITE_UTF8
08643                 if (otype == SQL_C_WCHAR) {
08644                     uc_strncpy(val, ucdata + offs / sizeof (SQLWCHAR),
08645                                (len - doz) / sizeof (SQLWCHAR));
08646                 } else {
08647                     strncpy(val, *data + offs, len - doz);
08648                 }
08649 #else
08650                 strncpy(val, *data + offs, len - doz);
08651 #endif
08652             }
08653             if (valnull || len < 1) {
08654                 *lenp = dlen;
08655             } else {
08656                 *lenp = min(len - doz, dlen);
08657                 if (*lenp == len - doz && *lenp != dlen) {
08658                     *lenp = SQL_NO_TOTAL;
08659                 }
08660             }
08661             if (len && !valnull && doz) {
08662 #ifdef SQLITE_UTF8
08663                 if (otype == SQL_C_WCHAR) {
08664                     ((SQLWCHAR *) val)[len / sizeof (SQLWCHAR) - 1] = 0;
08665                 } else {
08666                     ((char *) val)[len - 1] = '\0';
08667                 }
08668 #else
08669                 ((char *) val)[len - 1] = '\0';
08670 #endif
08671             }
08672 #ifdef SQLITE_UTF8
08673             uc_free(ucdata);
08674 #endif
08675             if (partial && len && s->bindcols) {
08676                 if (*lenp == SQL_NO_TOTAL) {
08677                     s->bindcols[col].offs += len - doz;
08678                     setstat(s, -1, "data right truncated", "01004");
08679                     if (s->bindcols[col].lenp) {
08680                         *s->bindcols[col].lenp = dlen;
08681                     }
08682                     return SQL_SUCCESS_WITH_INFO;
08683                 }
08684                 s->bindcols[col].offs += *lenp;
08685             }
08686             break;
08687         }
08688 #ifdef SQL_C_TYPE_DATE
08689         case SQL_C_TYPE_DATE:
08690 #endif
08691         case SQL_C_DATE:
08692             if (str2date(*data, (DATE_STRUCT *) val) < 0) {
08693                 *lenp = SQL_NULL_DATA;
08694             } else {
08695                 *lenp = sizeof (DATE_STRUCT);
08696             }
08697             break;
08698 #ifdef SQL_C_TYPE_TIME
08699         case SQL_C_TYPE_TIME:
08700 #endif
08701         case SQL_C_TIME:
08702             if (str2time(*data, (TIME_STRUCT *) val) < 0) {
08703                 *lenp = SQL_NULL_DATA;
08704             } else {
08705                 *lenp = sizeof (TIME_STRUCT);
08706             }
08707             break;
08708 #ifdef SQL_C_TYPE_TIMESTAMP
08709         case SQL_C_TYPE_TIMESTAMP:
08710 #endif
08711         case SQL_C_TIMESTAMP:
08712             if (str2timestamp(*data, (TIMESTAMP_STRUCT *) val) < 0) {
08713                 *lenp = SQL_NULL_DATA;
08714             } else {
08715                 *lenp = sizeof (TIMESTAMP_STRUCT);
08716             }
08717             break;
08718         default:
08719             return SQL_ERROR;
08720         }
08721     }
08722     return SQL_SUCCESS;
08723 }
08724 
08736 SQLRETURN SQL_API
08737 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
08738            SQLPOINTER val, SQLINTEGER max, SQLINTEGER *lenp)
08739 {
08740     STMT *s;
08741 
08742     if (stmt == SQL_NULL_HSTMT) {
08743         return SQL_INVALID_HANDLE;
08744     }
08745     s = (STMT *) stmt;
08746     if (col < 1) {
08747         if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
08748             s->bkmrkcol.type = type;
08749             s->bkmrkcol.max = max;
08750             s->bkmrkcol.lenp = lenp;
08751             s->bkmrkcol.valp = val;
08752             s->bkmrkcol.offs = 0;
08753             if (lenp) {
08754                 *lenp = 0;
08755             }
08756             return SQL_SUCCESS;
08757         }
08758         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
08759         return SQL_ERROR;
08760     }
08761     if (mkbindcols(s, col) != SQL_SUCCESS) {
08762         return SQL_ERROR;
08763     }
08764     --col;
08765     if (type == SQL_C_DEFAULT) {
08766         type = mapdeftype(type, s->cols[col].type, 0, s->nowchar);
08767     } else {
08768         switch (type) {
08769         case SQL_C_LONG:
08770         case SQL_C_ULONG:
08771         case SQL_C_SLONG:
08772         case SQL_C_TINYINT:
08773         case SQL_C_UTINYINT:
08774         case SQL_C_STINYINT:
08775         case SQL_C_SHORT:
08776         case SQL_C_USHORT:
08777         case SQL_C_SSHORT:
08778         case SQL_C_FLOAT:
08779         case SQL_C_DOUBLE:
08780         case SQL_C_TIMESTAMP:
08781         case SQL_C_TIME:
08782         case SQL_C_DATE:
08783         case SQL_C_CHAR:
08784 #ifdef SQLITE_UTF8
08785         case SQL_C_WCHAR:
08786 #endif
08787 #ifdef SQL_C_TYPE_DATE
08788         case SQL_C_TYPE_DATE:
08789 #endif
08790 #ifdef SQL_C_TYPE_TIME
08791         case SQL_C_TYPE_TIME:
08792 #endif
08793 #ifdef SQL_C_TYPE_TIMESTAMP
08794         case SQL_C_TYPE_TIMESTAMP:
08795 #endif
08796             break;
08797 #if HAVE_ENCDEC
08798         case SQL_C_BINARY:
08799             break;
08800 #endif
08801         default:
08802             setstat(s, -1, "invalid type %d", "HY003", type);
08803             return SQL_ERROR;
08804         }
08805     }
08806     if (max < 0) {
08807         setstat(s, -1, "invalid length", "HY090");
08808         return SQL_ERROR;
08809     }
08810     s->bindcols[col].type = type;
08811     s->bindcols[col].max = max;
08812     s->bindcols[col].lenp = lenp;
08813     s->bindcols[col].valp = val;
08814     s->bindcols[col].offs = 0;
08815     if (lenp) {
08816         *lenp = 0;
08817     }
08818     return SQL_SUCCESS; 
08819 }
08820 
08825 static COL tableSpec[] = {
08826     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
08827     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
08828     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
08829     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
08830     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
08831 };
08832 
08847 static SQLRETURN
08848 drvtables(SQLHSTMT stmt,
08849           SQLCHAR *cat, SQLSMALLINT catLen,
08850           SQLCHAR *schema, SQLSMALLINT schemaLen,
08851           SQLCHAR *table, SQLSMALLINT tableLen,
08852           SQLCHAR *type, SQLSMALLINT typeLen)
08853 {
08854     SQLRETURN ret;
08855     STMT *s;
08856     DBC *d;
08857     int ncols, rc;
08858     char *errp = NULL, tname[512];
08859     char *where = "(type = 'table' or type = 'view')";
08860 
08861     ret = mkresultset(stmt, tableSpec, array_size(tableSpec));
08862     if (ret != SQL_SUCCESS) {
08863         return ret;
08864     }
08865     s = (STMT *) stmt;
08866     d = (DBC *) s->dbc;
08867     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
08868         int size = 3 * array_size(tableSpec);
08869 
08870         s->rows = xmalloc(size * sizeof (char *));
08871         if (!s->rows) {
08872             s->nrows = 0;
08873             return nomem(s);
08874         }
08875         memset(s->rows, 0, sizeof (char *) * size);
08876         s->ncols = array_size(tableSpec);
08877         s->rows[s->ncols + 0] = "";
08878         s->rows[s->ncols + 1] = "";
08879         s->rows[s->ncols + 2] = "";
08880         s->rows[s->ncols + 3] = "TABLE";
08881         s->rows[s->ncols + 5] = "";
08882         s->rows[s->ncols + 6] = "";
08883         s->rows[s->ncols + 7] = "";
08884         s->rows[s->ncols + 8] = "VIEW";
08885 #ifdef MEMORY_DEBUG
08886         s->rowfree = xfree__;
08887 #else
08888         s->rowfree = free;
08889 #endif
08890         s->nrows = 2;
08891         s->rowp = -1;
08892         return SQL_SUCCESS;
08893     }
08894     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
08895         int size = 2 * array_size(tableSpec);
08896 
08897         s->rows = xmalloc(size * sizeof (char *));
08898         if (!s->rows) {
08899             s->nrows = 0;
08900             return nomem(s);
08901         }
08902         memset(s->rows, 0, sizeof (char *) * size);
08903         s->ncols = array_size(tableSpec);
08904         s->rows[s->ncols + 0] = "";
08905         s->rows[s->ncols + 1] = "";
08906         s->rows[s->ncols + 2] = d->dbname;
08907         s->rows[s->ncols + 3] = "CATALOG";
08908 #ifdef MEMORY_DEBUG
08909         s->rowfree = xfree__;
08910 #else
08911         s->rowfree = free;
08912 #endif
08913         s->nrows = 1;
08914         s->rowp = -1;
08915         return SQL_SUCCESS;
08916     }
08917     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
08918         schema[0] == '%') {
08919         if ((!cat || catLen == 0 || !cat[0]) &&
08920             (!table || tableLen == 0 || !table[0])) {
08921             int size = 2 * array_size(tableSpec);
08922 
08923             s->rows = xmalloc(size * sizeof (char *));
08924             if (!s->rows) {
08925                 s->nrows = 0;
08926                 return nomem(s);
08927             }
08928             memset(s->rows, 0, sizeof (char *) * size);
08929             s->ncols = array_size(tableSpec);
08930             s->rows[s->ncols + 1] = "";
08931 #ifdef MEMORY_DEBUG
08932             s->rowfree = xfree__;
08933 #else
08934             s->rowfree = free;
08935 #endif
08936             s->nrows = 1;
08937             s->rowp = -1;
08938             return SQL_SUCCESS;
08939         }
08940     }
08941     if (type) {
08942         char tmp[256], *t;
08943         int with_view = 0, with_table = 0;
08944 
08945         if (typeLen == SQL_NTS) {
08946             strncpy(tmp, type, sizeof (tmp));
08947             tmp[sizeof (tmp) - 1] = '\0';
08948         } else {
08949             int len = min(sizeof (tmp) - 1, typeLen);
08950 
08951             strncpy(tmp, type, len);
08952             tmp[len] = '\0';
08953         }
08954         t = tmp;
08955         while (*t) {
08956             *t = TOLOWER(*t);
08957             t++;
08958         }
08959         t = tmp;
08960         while (t) {
08961             if (t[0] == '\'') {
08962                 ++t;
08963             }
08964             if (strncmp(t, "table", 5) == 0) {
08965                 with_table++;
08966             } else if (strncmp(t, "view", 4) == 0) {
08967                 with_view++;
08968             }
08969             t = strchr(t, ',');
08970             if (t) {
08971                 ++t;
08972             }
08973         }
08974         if (with_view && with_table) {
08975             /* where is already preset */
08976         } else if (with_view && !with_table) {
08977             where = "type = 'view'";
08978         } else if (!with_view && with_table) {
08979             where = "type = 'table'";
08980         } else {
08981             s->rowp = -1;
08982             return SQL_SUCCESS;
08983         }
08984     }
08985     strcpy(tname, "%");
08986     if (table && (tableLen > 0 || tableLen == SQL_NTS) && table[0] != '%') {
08987         int size;
08988 
08989         if (tableLen == SQL_NTS) {
08990             size = sizeof (tname) - 1;
08991         } else {
08992             size = min(sizeof (tname) - 1, tableLen);
08993         }
08994         strncpy(tname, table, size);
08995         tname[size] = '\0';
08996     }
08997     rc = sqlite_get_table_printf(d->sqlite,
08998                                  "select '' as 'TABLE_QUALIFIER', "
08999                                  "'' as 'TABLE_OWNER', "
09000                                  "tbl_name as 'TABLE_NAME', "
09001                                  "upper(type) as 'TABLE_TYPE', "
09002                                  "NULL as 'REMARKS' "
09003                                  "from sqlite_master where %s "
09004                                  "and tbl_name like '%q'",
09005                                  &s->rows, &s->nrows, &ncols, &errp,
09006                                  where, tname);
09007     if (rc == SQLITE_OK) {
09008         if (ncols != s->ncols) {
09009             freeresult(s, 0);
09010             s->nrows = 0;
09011         } else {
09012             s->rowfree = sqlite_free_table;
09013         }
09014     } else {
09015         s->nrows = 0;
09016         s->rows = NULL;
09017         s->rowfree = NULL;
09018     }
09019     if (errp) {
09020         sqlite_freemem(errp);
09021         errp = NULL;
09022     }
09023     s->rowp = -1;
09024     return SQL_SUCCESS;
09025 }
09026 
09027 #ifndef SQLITE_UTF8
09028 
09042 SQLRETURN SQL_API
09043 SQLTables(SQLHSTMT stmt,
09044           SQLCHAR *cat, SQLSMALLINT catLen,
09045           SQLCHAR *schema, SQLSMALLINT schemaLen,
09046           SQLCHAR *table, SQLSMALLINT tableLen,
09047           SQLCHAR *type, SQLSMALLINT typeLen)
09048 {
09049     return drvtables(stmt, cat, catLen, schema, schemaLen,
09050                      table, tableLen, type, typeLen);
09051 }
09052 #endif
09053 
09054 #ifdef SQLITE_UTF8
09055 
09069 SQLRETURN SQL_API
09070 SQLTablesW(SQLHSTMT stmt,
09071            SQLWCHAR *cat, SQLSMALLINT catLen,
09072            SQLWCHAR *schema, SQLSMALLINT schemaLen,
09073            SQLWCHAR *table, SQLSMALLINT tableLen,
09074            SQLWCHAR *type, SQLSMALLINT typeLen)
09075 {
09076     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
09077     SQLRETURN ret;
09078 
09079     if (cat) {
09080         c = uc_to_utf_c(cat, catLen);
09081         if (!c) {
09082             ret = nomem((STMT *) stmt);
09083             goto done;
09084         }
09085     }
09086     if (schema) {
09087         s = uc_to_utf_c(schema, schemaLen);
09088         if (!s) {
09089             ret = nomem((STMT *) stmt);
09090             goto done;
09091         }
09092     }
09093     if (table) {
09094         t = uc_to_utf_c(table, tableLen);
09095         if (!t) {
09096             ret = nomem((STMT *) stmt);
09097             goto done;
09098         }
09099     }
09100     if (type) {
09101         y = uc_to_utf_c(type, typeLen);
09102         if (!y) {
09103             ret = nomem((STMT *) stmt);
09104             goto done;
09105         }
09106     }
09107     ret = drvtables(stmt, c, SQL_NTS, s, SQL_NTS,
09108                     t, SQL_NTS, y, SQL_NTS);
09109 done:
09110     uc_free(y);
09111     uc_free(t);
09112     uc_free(s);
09113     uc_free(c);
09114     return ret;
09115 }
09116 #endif
09117 
09122 static COL colSpec[] = {
09123     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
09124     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
09125     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
09126     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
09127     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
09128     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
09129     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
09130     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
09131     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
09132     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
09133     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
09134     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
09135     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
09136     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
09137     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
09138     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
09139     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
09140     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
09141 };
09142 
09157 static SQLRETURN
09158 drvcolumns(SQLHSTMT stmt,
09159            SQLCHAR *cat, SQLSMALLINT catLen,
09160            SQLCHAR *schema, SQLSMALLINT schemaLen,
09161            SQLCHAR *table, SQLSMALLINT tableLen,
09162            SQLCHAR *col, SQLSMALLINT colLen)
09163 {
09164     SQLRETURN sret;
09165     STMT *s;
09166     DBC *d;
09167     int ret, nrows, ncols, size, i, k;
09168     char *errp = NULL, tname[512], **rowp;
09169 
09170     sret = mkresultset(stmt, colSpec, array_size(colSpec));
09171     if (sret != SQL_SUCCESS) {
09172         return sret;
09173     }
09174     s = (STMT *) stmt;
09175     d = (DBC *) s->dbc;
09176     if (!table || table[0] == '\0' || table[0] == '%') {
09177         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
09178         return SQL_ERROR;
09179     }
09180     if (tableLen == SQL_NTS) {
09181         size = sizeof (tname) - 1;
09182     } else {
09183         size = min(sizeof (tname) - 1, tableLen);
09184     }
09185     strncpy(tname, table, size);
09186     tname[size] = '\0';
09187     ret = sqlite_get_table_printf(d->sqlite, "PRAGMA table_info('%q')", &rowp,
09188                                   &nrows, &ncols, &errp, tname);
09189     if (ret != SQLITE_OK) {
09190         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
09191                 errp ? errp : "unknown error", ret);
09192         if (errp) {
09193             sqlite_freemem(errp);
09194             errp = NULL;
09195         }
09196         return SQL_ERROR;       
09197     }
09198     if (errp) {
09199         sqlite_freemem(errp);
09200         errp = NULL;
09201     }
09202     if (ncols * nrows <= 0) {
09203         sqlite_free_table(rowp);
09204         return SQL_NO_DATA;
09205     }
09206     size = array_size(colSpec) * (nrows + 1);
09207     s->rows = xmalloc((size + 1) * sizeof (char *));
09208     if (!s->rows) {
09209         return nomem(s);
09210     }
09211     s->rows[0] = (char *) size;
09212     s->rows += 1;
09213     memset(s->rows, 0, sizeof (char *) * size);
09214     s->rowfree = freerows;
09215     s->nrows = nrows;
09216     for (i = 1; i <= s->nrows; i++) {
09217         s->rows[array_size(colSpec) * i + 0] = xstrdup("");
09218         s->rows[array_size(colSpec) * i + 1] = xstrdup("");
09219         s->rows[array_size(colSpec) * i + 2] = xstrdup(tname);
09220         s->rows[array_size(colSpec) * i + 8] = xstrdup("10");
09221         s->rows[array_size(colSpec) * i + 9] = xstrdup("0");
09222         s->rows[array_size(colSpec) * i + 15] = xstrdup("16384");
09223     }
09224     for (k = 0; k < ncols; k++) {
09225         if (strcmp(rowp[k], "cid") == 0) {
09226             for (i = 1; i <= s->nrows; i++) {
09227                 char buf[256];
09228                 int coln = i;
09229 
09230                 sscanf(rowp[i * ncols + k], "%d", &coln);
09231                 sprintf(buf, "%d", coln + 1);
09232                 s->rows[array_size(colSpec) * i + 16] = xstrdup(buf);
09233             }
09234         } else if (strcmp(rowp[k], "name") == 0) {
09235             for (i = 1; i <= s->nrows; i++) {
09236                 s->rows[array_size(colSpec) * i + 3] =
09237                     xstrdup(rowp[i * ncols + k]);
09238             }
09239         } else if (strcmp(rowp[k], "notnull") == 0) {
09240             for (i = 1; i <= s->nrows; i++) {
09241                 if (*rowp[i * ncols + k] != '0') {
09242                     s->rows[array_size(colSpec) * i + 10] =
09243                         xstrdup(stringify(SQL_FALSE));
09244                 } else {
09245                     s->rows[array_size(colSpec) * i + 10] =
09246                         xstrdup(stringify(SQL_TRUE));
09247                 }
09248                 s->rows[array_size(colSpec) * i + 17] =
09249                     xstrdup(*rowp[i * ncols + k] != '0' ? "NO" : "YES");
09250             }
09251         } else if (strcmp(rowp[k], "dflt_value") == 0) {
09252             for (i = 1; i <= s->nrows; i++) {
09253                 char *dflt = rowp[i * ncols + k];
09254 
09255                 s->rows[array_size(colSpec) * i + 12] =
09256                     xstrdup(dflt ? dflt : "NULL");
09257             }
09258         } else if (strcmp(rowp[k], "type") == 0) {
09259             for (i = 1; i <= s->nrows; i++) {
09260                 char *typename = rowp[i * ncols + k];
09261                 int sqltype, m, d;
09262                 char buf[256];
09263 
09264                 s->rows[array_size(colSpec) * i + 5] = xstrdup(typename);
09265                 sqltype = mapsqltype(typename, NULL, *s->ov3, s->nowchar);
09266                 getmd(typename, sqltype, &m, &d);
09267 #ifdef SQL_LONGVARCHAR
09268                 if (sqltype == SQL_VARCHAR && m > 255) {
09269                     sqltype = SQL_LONGVARCHAR;
09270                 }
09271 #endif
09272 #ifdef SQLITE_UTF8
09273 #ifdef SQL_WLONGVARCHAR
09274                 if (sqltype == SQL_WVARCHAR && m > 255) {
09275                     sqltype = SQL_WLONGVARCHAR;
09276                 }
09277 #endif
09278 #endif
09279 #if HAVE_ENCDEC
09280                 if (sqltype == SQL_VARBINARY && m > 255) {
09281                     sqltype = SQL_LONGVARBINARY;
09282                 }
09283 #endif
09284                 sprintf(buf, "%d", sqltype);
09285                 s->rows[array_size(colSpec) * i + 4] = xstrdup(buf);
09286                 s->rows[array_size(colSpec) * i + 13] = xstrdup(buf);
09287                 sprintf(buf, "%d", m);
09288                 s->rows[array_size(colSpec) * i + 7] = xstrdup(buf);
09289                 sprintf(buf, "%d", d);
09290                 s->rows[array_size(colSpec) * i + 6] = xstrdup(buf);
09291             }
09292         }
09293     }
09294     sqlite_free_table(rowp);
09295     return SQL_SUCCESS;
09296 }
09297 
09298 #ifndef SQLITE_UTF8
09299 
09313 SQLRETURN SQL_API
09314 SQLColumns(SQLHSTMT stmt,
09315            SQLCHAR *cat, SQLSMALLINT catLen,
09316            SQLCHAR *schema, SQLSMALLINT schemaLen,
09317            SQLCHAR *table, SQLSMALLINT tableLen,
09318            SQLCHAR *col, SQLSMALLINT colLen)
09319 {
09320     return drvcolumns(stmt, cat, catLen, schema, schemaLen,
09321                       table, tableLen, col, colLen);
09322 }
09323 #endif
09324 
09325 #ifdef SQLITE_UTF8
09326 
09340 SQLRETURN SQL_API
09341 SQLColumnsW(SQLHSTMT stmt,
09342             SQLWCHAR *cat, SQLSMALLINT catLen,
09343             SQLWCHAR *schema, SQLSMALLINT schemaLen,
09344             SQLWCHAR *table, SQLSMALLINT tableLen,
09345             SQLWCHAR *col, SQLSMALLINT colLen)
09346 {
09347     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
09348     SQLRETURN ret;
09349 
09350     if (cat) {
09351         c = uc_to_utf_c(cat, catLen);
09352         if (!c) {
09353             ret = nomem((STMT *) stmt);
09354             goto done;
09355         }
09356     }
09357     if (schema) {
09358         s = uc_to_utf_c(schema, schemaLen);
09359         if (!s) {
09360             ret = nomem((STMT *) stmt);
09361             goto done;
09362         }
09363     }
09364     if (table) {
09365         t = uc_to_utf_c(table, tableLen);
09366         if (!t) {
09367             ret = nomem((STMT *) stmt);
09368             goto done;
09369         }
09370     }
09371     if (col) {
09372         k = uc_to_utf_c(col, colLen);
09373         if (!k) {
09374             ret = nomem((STMT *) stmt);
09375             goto done;
09376         }
09377     }
09378     ret = drvcolumns(stmt, c, SQL_NTS, s, SQL_NTS,
09379                      t, SQL_NTS, k, SQL_NTS);
09380 done:
09381     uc_free(k);
09382     uc_free(t);
09383     uc_free(s);
09384     uc_free(c);
09385     return ret;
09386 
09387 }
09388 #endif
09389 
09394 static COL typeSpec[] = {
09395     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
09396     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
09397     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 4 },
09398     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
09399     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
09400     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
09401     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
09402     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
09403     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
09404     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
09405     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
09406     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
09407     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
09408     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
09409     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
09410 };
09411 
09421 static void
09422 mktypeinfo(STMT *s, int row, char *typename, int type, int tind)
09423 {
09424     int offs = row * array_size(typeSpec);
09425     char *tcode, *crpar = NULL, *quote = NULL, *sign = stringify(SQL_FALSE);
09426     static char tcodes[32 * 32];
09427 
09428     if (tind <= 0) {
09429         tind = row;
09430     }
09431     tcode = tcodes + tind * 32;
09432     sprintf(tcode, "%d", type);
09433     s->rows[offs + 0] = typename;
09434     s->rows[offs + 1] = tcode;
09435     switch (type) {
09436     default:
09437 #ifdef SQL_LONGVARCHAR
09438     case SQL_LONGVARCHAR:
09439 #ifdef SQLITE_UTF8
09440     case SQL_WLONGVARCHAR:
09441 #endif
09442         crpar = "length";
09443         quote = "'";
09444         sign = NULL;
09445         s->rows[offs + 2] = "65536";
09446         break;
09447 #endif
09448     case SQL_CHAR:
09449     case SQL_VARCHAR:
09450 #ifdef SQLITE_UTF8
09451     case SQL_WCHAR:
09452     case SQL_WVARCHAR:
09453 #endif
09454         s->rows[offs + 2] = "255";
09455         crpar = "length";
09456         quote = "'";
09457         sign = NULL;
09458         break;
09459     case SQL_TINYINT:
09460         s->rows[offs + 2] = "3";
09461         break;
09462     case SQL_SMALLINT:
09463         s->rows[offs + 2] = "5";
09464         break;
09465     case SQL_INTEGER:
09466         s->rows[offs + 2] = "7";
09467         break;
09468     case SQL_FLOAT:
09469         s->rows[offs + 2] = "7";
09470         break;
09471     case SQL_DOUBLE:
09472         s->rows[offs + 2] = "15";
09473         break;
09474 #ifdef SQL_TYPE_DATE
09475     case SQL_TYPE_DATE:
09476 #endif
09477     case SQL_DATE:
09478         s->rows[offs + 2] = "10";
09479         quote = "'";
09480         sign = NULL;
09481         break;
09482 #ifdef SQL_TYPE_TIME
09483     case SQL_TYPE_TIME:
09484 #endif
09485     case SQL_TIME:
09486         s->rows[offs + 2] = "8";
09487         quote = "'";
09488         sign = NULL;
09489         break;
09490 #ifdef SQL_TYPE_TIMESTAMP
09491     case SQL_TYPE_TIMESTAMP:
09492 #endif
09493     case SQL_TIMESTAMP:
09494         s->rows[offs + 2] = "32";
09495         quote = "'";
09496         sign = NULL;
09497         break;
09498 #if HAVE_ENCDEC
09499     case SQL_VARBINARY:
09500         sign = NULL;
09501         s->rows[offs + 2] = "255";
09502         break;
09503     case SQL_LONGVARBINARY:
09504         sign = NULL;
09505         s->rows[offs + 2] = "65536";
09506         break;
09507 #endif
09508     }
09509     s->rows[offs + 3] = s->rows[offs + 4] = quote;
09510     s->rows[offs + 5] = crpar;
09511     s->rows[offs + 6] = stringify(SQL_NULLABLE);
09512     s->rows[offs + 7] = stringify(SQL_FALSE);
09513     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
09514     s->rows[offs + 9] = sign;
09515     s->rows[offs + 10] = stringify(SQL_FALSE);
09516     s->rows[offs + 11] = stringify(SQL_FALSE);
09517     s->rows[offs + 12] = typename;
09518     s->rows[offs + 13] = NULL;
09519     s->rows[offs + 14] = NULL;
09520 }
09521 
09530 static int
09531 typeinfosort(const void *a, const void *b)
09532 {
09533     char **pa = (char **) a;
09534     char **pb = (char **) b;
09535     int na, nb;
09536 
09537     na = strtol(pa[1], NULL, 0);
09538     nb = strtol(pb[1], NULL, 0);
09539     return na - nb;
09540 }
09541 
09549 static SQLRETURN
09550 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
09551 {
09552     SQLRETURN ret;
09553     STMT *s;
09554     DBC *d;
09555 
09556     ret = mkresultset(stmt, typeSpec, array_size(typeSpec));
09557     if (ret != SQL_SUCCESS) {
09558         return ret;
09559     }
09560     s = (STMT *) stmt;
09561     d = (DBC *) s->dbc;
09562 #ifdef SQLITE_UTF8
09563 #ifdef SQL_LONGVARCHAR
09564 #ifdef SQL_WLONGVARCHAR
09565     if (s->nowchar) {
09566         s->nrows = sqltype == SQL_ALL_TYPES ? 13 : 1;
09567     } else {
09568         s->nrows = sqltype == SQL_ALL_TYPES ? 17 : 1;
09569     }
09570 #else
09571     if (s->nowchar) {
09572         s->nrows = sqltype == SQL_ALL_TYPES ? 12 : 1;
09573     } else {
09574         s->nrows = sqltype == SQL_ALL_TYPES ? 16 : 1;
09575     }
09576 #endif
09577 #else
09578     s->nrows = sqltype == SQL_ALL_TYPES ? 15 : 1;
09579 #endif
09580 #else
09581 #ifdef SQL_LONGVARCHAR
09582     s->nrows = sqltype == SQL_ALL_TYPES ? 13 : 1;
09583 #else
09584     s->nrows = sqltype == SQL_ALL_TYPES ? 12 : 1;
09585 #endif
09586 #endif
09587 #if HAVE_ENCDEC
09588     if (sqltype == SQL_ALL_TYPES) {
09589         s->nrows += 2;
09590     }
09591 #endif
09592     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1)
09593                                 * array_size(typeSpec));
09594     if (!s->rows) {
09595         s->nrows = 0;
09596         return nomem(s);
09597     }
09598 #ifdef MEMORY_DEBUG
09599     s->rowfree = xfree__;
09600 #else
09601     s->rowfree = free;
09602 #endif
09603     memset(s->rows, 0,
09604            sizeof (char *) * (s->nrows + 1) * array_size(typeSpec));
09605     if (sqltype == SQL_ALL_TYPES) {
09606         int cc = 1;
09607 
09608         mktypeinfo(s, cc++, "varchar", SQL_VARCHAR, 0);
09609         mktypeinfo(s, cc++, "tinyint", SQL_TINYINT, 0);
09610         mktypeinfo(s, cc++, "smallint", SQL_SMALLINT, 0);
09611         mktypeinfo(s, cc++, "integer", SQL_INTEGER, 0);
09612         mktypeinfo(s, cc++, "float", SQL_FLOAT, 0);
09613         mktypeinfo(s, cc++, "double", SQL_DOUBLE, 0);
09614 #ifdef SQL_TYPE_DATE
09615         mktypeinfo(s, cc++, "date", (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
09616 #else
09617         mktypeinfo(s, cc++, "date", SQL_DATE, 0);
09618 #endif
09619 #ifdef SQL_TYPE_TIME
09620         mktypeinfo(s, cc++, "time", (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
09621 #else
09622         mktypeinfo(s, cc++, "time", SQL_TIME, 0);
09623 #endif
09624 #ifdef SQL_TYPE_TIMESTAMP
09625         mktypeinfo(s, cc++, "timestamp",
09626                    (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
09627 #else
09628         mktypeinfo(s, cc++, "timestamp", SQL_TIMESTAMP, 0);
09629 #endif
09630         mktypeinfo(s, cc++, "char", SQL_CHAR, 0);
09631         mktypeinfo(s, cc++, "numeric", SQL_DOUBLE, 0);
09632 #ifdef SQL_LONGVARCHAR
09633         mktypeinfo(s, cc++, "text", SQL_LONGVARCHAR, 0);
09634         mktypeinfo(s, cc++, "longvarchar", SQL_LONGVARCHAR, 0);
09635 #else
09636         mktypeinfo(s, cc++, "text", SQL_VARCHAR, 0);
09637 #endif
09638 #ifdef SQLITE_UTF8
09639         if (!s->nowchar) {
09640             mktypeinfo(s, cc++, "wvarchar", SQL_WVARCHAR, 0);
09641 #ifdef SQL_LONGVARCHAR
09642             mktypeinfo(s, cc++, "wchar", SQL_WCHAR, 0);
09643             mktypeinfo(s, cc++, "wtext", SQL_WLONGVARCHAR, 0);
09644 #ifdef SQL_WLONGVARCHAR
09645             mktypeinfo(s, cc++, "longwvarchar", SQL_WLONGVARCHAR, 0);
09646 #endif
09647 #else
09648             mktypeinfo(s, cc++, "wvarchar", SQL_WVARCHAR, 0);
09649             mktypeinfo(s, cc++, "wchar", SQL_WCHAR, 0);
09650             mktypeinfo(s, cc++, "wtext", SQL_WVARCHAR, 0);
09651 #endif
09652         }
09653 #endif
09654 #if HAVE_ENCDEC
09655         mktypeinfo(s, cc++, "varbinary", SQL_VARBINARY, 0);
09656         mktypeinfo(s, cc++, "longvarbinary", SQL_LONGVARBINARY, 0);
09657 #endif
09658         qsort(s->rows + array_size(typeSpec), s->nrows,
09659               sizeof (char *) * array_size(typeSpec), typeinfosort);
09660     } else {
09661         switch (sqltype) {
09662         case SQL_CHAR:
09663             mktypeinfo(s, 1, "char", SQL_CHAR, 10);
09664             break;
09665         case SQL_VARCHAR:
09666             mktypeinfo(s, 1, "varchar", SQL_VARCHAR, 1);
09667             break;
09668         case SQL_TINYINT:
09669             mktypeinfo(s, 1, "tinyint", SQL_TINYINT, 2);
09670             break;
09671         case SQL_SMALLINT:
09672             mktypeinfo(s, 1, "smallint", SQL_SMALLINT, 3);
09673             break;
09674         case SQL_INTEGER:
09675             mktypeinfo(s, 1, "integer", SQL_INTEGER, 4);
09676             break;
09677         case SQL_FLOAT:
09678             mktypeinfo(s, 1, "float", SQL_FLOAT, 5);
09679             break;
09680         case SQL_DOUBLE:
09681             mktypeinfo(s, 1, "double", SQL_DOUBLE, 6);
09682             break;
09683 #ifdef SQL_TYPE_DATE
09684         case SQL_TYPE_DATE:
09685             mktypeinfo(s, 1, "date", SQL_TYPE_DATE, 25);
09686             break;
09687 #endif
09688         case SQL_DATE:
09689             mktypeinfo(s, 1, "date", SQL_DATE, 7);
09690             break;
09691 #ifdef SQL_TYPE_TIME
09692         case SQL_TYPE_TIME:
09693             mktypeinfo(s, 1, "date", SQL_TYPE_TIME, 26);
09694             break;
09695 #endif
09696         case SQL_TIME:
09697             mktypeinfo(s, 1, "time", SQL_TIME, 8);
09698             break;
09699 #ifdef SQL_TYPE_TIMESTAMP
09700         case SQL_TYPE_TIMESTAMP:
09701             mktypeinfo(s, 1, "date", SQL_TYPE_TIMESTAMP, 27);
09702             break;
09703 #endif
09704         case SQL_TIMESTAMP:
09705             mktypeinfo(s, 1, "timestamp", SQL_TIMESTAMP, 9);
09706             break;
09707 #ifdef SQL_LONGVARCHAR
09708         case SQL_LONGVARCHAR:
09709             mktypeinfo(s, 1, "longvarchar", SQL_LONGVARCHAR, 12);
09710             break;
09711 #endif
09712 #ifdef SQLITE_UTF8
09713 #ifdef SQL_WCHAR
09714         case SQL_WCHAR:
09715             mktypeinfo(s, 1, "wchar", SQL_WCHAR, 18);
09716             break;
09717 #endif
09718 #ifdef SQL_WVARCHAR
09719         case SQL_WVARCHAR:
09720             mktypeinfo(s, 1, "wvarchar", SQL_WVARCHAR, 19);
09721             break;
09722 #endif
09723 #ifdef SQL_WLONGVARCHAR
09724         case SQL_WLONGVARCHAR:
09725             mktypeinfo(s, 1, "longwvarchar", SQL_WLONGVARCHAR, 20);
09726             break;
09727 #endif
09728 #endif
09729 #if HAVE_ENCDEC
09730         case SQL_VARBINARY:
09731             mktypeinfo(s, 1, "varbinary", SQL_VARBINARY, 30);
09732             break;
09733         case SQL_LONGVARBINARY:
09734             mktypeinfo(s, 1, "longvarbinary", SQL_LONGVARBINARY, 31);
09735             break;
09736 #endif
09737         default:
09738             s->nrows = 0;
09739             return SQL_NO_DATA;
09740         }
09741     }
09742     return SQL_SUCCESS;
09743 }
09744 
09745 #ifndef SQLITE_UTF8
09746 
09753 SQLRETURN SQL_API
09754 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
09755 {
09756     return drvgettypeinfo(stmt, sqltype);
09757 }
09758 #endif
09759 
09760 #ifdef SQLITE_UTF8
09761 
09768 SQLRETURN SQL_API
09769 SQLGetTypeInfoW(SQLHSTMT stmt, SQLSMALLINT sqltype)
09770 {
09771     return drvgettypeinfo(stmt, sqltype);
09772 }
09773 #endif
09774 
09779 static COL statSpec[] = {
09780     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
09781     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
09782     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
09783     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
09784     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
09785     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
09786     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
09787     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
09788     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
09789     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
09790     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
09791     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
09792     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
09793 };
09794 
09809 static SQLRETURN
09810 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
09811               SQLCHAR *schema, SQLSMALLINT schemaLen,
09812               SQLCHAR *table, SQLSMALLINT tableLen,
09813               SQLUSMALLINT itype, SQLUSMALLINT resv)
09814 {
09815     SQLRETURN sret;
09816     STMT *s;
09817     DBC *d;
09818     int i, size, ret, nrows, ncols, offs, namec, uniquec;
09819     char **rowp, *errp = NULL, tname[512];
09820 
09821     sret = mkresultset(stmt, statSpec, array_size(statSpec));
09822     if (sret != SQL_SUCCESS) {
09823         return sret;
09824     }
09825     s = (STMT *) stmt;
09826     d = (DBC *) s->dbc;
09827     if (!table || table[0] == '\0' || table[0] == '%') {
09828         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
09829         return SQL_ERROR;
09830     }
09831     if (tableLen == SQL_NTS) {
09832         size = sizeof (tname) - 1;
09833     } else {
09834         size = min(sizeof (tname) - 1, tableLen);
09835     }
09836     strncpy(tname, table, size);
09837     tname[size] = '\0';
09838     ret = sqlite_get_table_printf(d->sqlite,
09839                                   "PRAGMA index_list('%q')", &rowp,
09840                                   &nrows, &ncols, &errp, tname);
09841     if (ret != SQLITE_OK) {
09842         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
09843                 errp ? errp : "unknown error", ret);
09844         if (errp) {
09845             sqlite_freemem(errp);
09846             errp = NULL;
09847         }
09848         return SQL_ERROR;
09849     }
09850     if (errp) {
09851         sqlite_freemem(errp);
09852         errp = NULL;
09853     }
09854     if (ncols * nrows <= 0) {
09855 nodata:
09856         sqlite_free_table(rowp);
09857         /* try table_info for integer primary keys */
09858         if (itype == SQL_INDEX_UNIQUE) {
09859             ret = sqlite_get_table_printf(d->sqlite,
09860                                           "PRAGMA table_info('%q')", &rowp,
09861                                           &nrows, &ncols, NULL, tname);
09862             if (ret == SQLITE_OK) {
09863                 int colid, typec, roffs;
09864 
09865                 namec = findcol(rowp, ncols, "name");
09866                 uniquec = findcol(rowp, ncols, "pk");
09867                 typec = findcol(rowp, ncols, "type");
09868                 colid = findcol(rowp, ncols, "cid");
09869                 if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
09870                     goto nodata2;
09871                 }
09872                 for (i = 1; i <= nrows; i++) {
09873                     if (*rowp[i * ncols + uniquec] != '0' &&
09874                         strlen(rowp[i * ncols + typec]) == 7 &&
09875                         strncasecmp(rowp[i * ncols + typec], "integer", 7)
09876                         == 0) {
09877                         break;
09878                     }
09879                 }
09880                 if (i > nrows) {
09881                     goto nodata2;
09882                 }
09883                 size = (1 + 1) * array_size(statSpec);
09884                 s->rows = xmalloc((size + 1) * sizeof (char *));
09885                 if (!s->rows) {
09886                     s->nrows = 0;
09887                     return nomem(s);
09888                 }
09889                 s->rows[0] = (char *) size;
09890                 s->rows += 1;
09891                 memset(s->rows, 0, sizeof (char *) * size);
09892                 s->rowfree = freerows;
09893                 s->nrows = 1;
09894                 roffs = s->ncols;
09895                 s->rows[roffs + 0] = xstrdup("");
09896                 s->rows[roffs + 1] = xstrdup("");
09897                 s->rows[roffs + 2] = xstrdup(tname);
09898                 s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
09899                 s->rows[roffs + 4] = xstrdup("");
09900                 s->rows[roffs + 5] = xstrdup("");
09901                 s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
09902                 s->rows[roffs + 7] = xstrdup("1");
09903                 s->rows[roffs + 8] = xstrdup(rowp[i * ncols + namec]);
09904                 s->rows[roffs + 9] = xstrdup("A");
09905 nodata2:
09906                 sqlite_free_table(rowp);
09907             }
09908         }
09909         return SQL_SUCCESS;
09910     }
09911     size = 0;
09912     namec = findcol(rowp, ncols, "name");
09913     uniquec = findcol(rowp, ncols, "unique");
09914     if (namec < 0 || uniquec < 0) {
09915         goto nodata;
09916     }
09917     for (i = 1; i <= nrows; i++) {
09918         int nnrows, nncols;
09919         char **rowpp;
09920         int isuniq;
09921 
09922         isuniq = *rowp[i * ncols + uniquec] != '0';
09923         if (isuniq || itype == SQL_INDEX_ALL) {
09924             ret = sqlite_get_table_printf(d->sqlite,
09925                                           "PRAGMA index_info('%q')", &rowpp,
09926                                           &nnrows, &nncols, NULL,
09927                                           rowp[i * ncols + namec]);
09928             if (ret == SQLITE_OK) {
09929                 size += nnrows;
09930                 sqlite_free_table(rowpp);
09931             }
09932         }
09933     }
09934     if (size == 0) {
09935         goto nodata;
09936     }
09937     s->nrows = size;
09938     size = (size + 1) * array_size(statSpec);
09939     s->rows = xmalloc((size + 1) * sizeof (char *));
09940     if (!s->rows) {
09941         s->nrows = 0;
09942         return nomem(s);
09943     }
09944     s->rows[0] = (char *) size;
09945     s->rows += 1;
09946     memset(s->rows, 0, sizeof (char *) * size);
09947     s->rowfree = freerows;
09948     offs = 0;
09949     for (i = 1; i <= nrows; i++) {
09950         int nnrows, nncols;
09951         char **rowpp;
09952 
09953         if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
09954             int k;
09955 
09956             ret = sqlite_get_table_printf(d->sqlite,
09957                                           "PRAGMA index_info('%q')", &rowpp,
09958                                           &nnrows, &nncols, NULL,
09959                                           rowp[i * ncols + namec]);
09960             if (ret != SQLITE_OK) {
09961                 continue;
09962             }
09963             for (k = 0; nnrows && k < nncols; k++) {
09964                 if (strcmp(rowpp[k], "name") == 0) {
09965                     int m;
09966 
09967                     for (m = 1; m <= nnrows; m++) {
09968                         int roffs = (offs + m) * s->ncols;
09969                         int isuniq;
09970 
09971                         isuniq = *rowp[i * ncols + uniquec] != '0';
09972                         s->rows[roffs + 0] = xstrdup("");
09973                         s->rows[roffs + 1] = xstrdup("");
09974                         s->rows[roffs + 2] = xstrdup(tname);
09975                         if (isuniq) {
09976                             s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
09977                         } else {
09978                             s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
09979                         }
09980                         s->rows[roffs + 4] = xstrdup("");
09981                         s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
09982                         s->rows[roffs + 6] =
09983                             xstrdup(stringify(SQL_INDEX_OTHER));
09984                         s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
09985                         s->rows[roffs + 9] = xstrdup("A");
09986                     }
09987                 } else if (strcmp(rowpp[k], "seqno") == 0) {
09988                     int m;
09989 
09990                     for (m = 1; m <= nnrows; m++) {
09991                         int roffs = (offs + m) * s->ncols;
09992                         int pos = m - 1;
09993                         char buf[32];
09994 
09995                         sscanf(rowpp[m * nncols + k], "%d", &pos);
09996                         sprintf(buf, "%d", pos + 1);
09997                         s->rows[roffs + 7] = xstrdup(buf);
09998                     }
09999                 }
10000             }
10001             offs += nnrows;
10002             sqlite_free_table(rowpp);
10003         }
10004     }
10005     sqlite_free_table(rowp);
10006     return SQL_SUCCESS;
10007 }
10008 
10009 #ifndef SQLITE_UTF8
10010 
10024 SQLRETURN SQL_API
10025 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
10026               SQLCHAR *schema, SQLSMALLINT schemaLen,
10027               SQLCHAR *table, SQLSMALLINT tableLen,
10028               SQLUSMALLINT itype, SQLUSMALLINT resv)
10029 {
10030     return drvstatistics(stmt, cat, catLen, schema, schemaLen,
10031                          table, tableLen, itype, resv);
10032 }
10033 #endif
10034 
10035 #ifdef SQLITE_UTF8
10036 
10050 SQLRETURN SQL_API
10051 SQLStatisticsW(SQLHSTMT stmt, SQLWCHAR *cat, SQLSMALLINT catLen,
10052                SQLWCHAR *schema, SQLSMALLINT schemaLen,
10053                SQLWCHAR *table, SQLSMALLINT tableLen,
10054                SQLUSMALLINT itype, SQLUSMALLINT resv)
10055 {
10056     char *c = NULL, *s = NULL, *t = NULL;
10057     SQLRETURN ret;
10058 
10059     if (cat) {
10060         c = uc_to_utf_c(cat, catLen);
10061         if (!c) {
10062             ret = nomem((STMT *) stmt);
10063             goto done;
10064         }
10065     }
10066     if (schema) {
10067         s = uc_to_utf_c(schema, schemaLen);
10068         if (!s) {
10069             ret = nomem((STMT *) stmt);
10070             goto done;
10071         }
10072     }
10073     if (table) {
10074         t = uc_to_utf_c(table, tableLen);
10075         if (!t) {
10076             ret = nomem((STMT *) stmt);
10077             goto done;
10078         }
10079     }
10080     ret = drvstatistics(stmt, c, SQL_NTS, s, SQL_NTS, t, SQL_NTS,
10081                         itype, resv);
10082 done:
10083     uc_free(t);
10084     uc_free(s);
10085     uc_free(c);
10086     return ret;
10087 }
10088 #endif
10089 
10101 SQLRETURN SQL_API
10102 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
10103            SQLPOINTER val, SQLINTEGER len, SQLINTEGER *lenp)
10104 {
10105     STMT *s;
10106 
10107     if (stmt == SQL_NULL_HSTMT) {
10108         return SQL_INVALID_HANDLE;
10109     }
10110     s = (STMT *) stmt;
10111     if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
10112         *((long *) val) = s->rowp;
10113         if (lenp) {
10114             *lenp = sizeof (long);
10115         }
10116         return SQL_SUCCESS;
10117     }
10118     if (col < 1 || col > s->ncols) {
10119         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
10120         return SQL_ERROR;
10121     }
10122     --col;
10123     return getrowdata(s, col, type, val, len, lenp, 1);
10124 }
10125 
10133 static SQLRETURN
10134 dofetchbind(STMT *s, int rsi)
10135 {
10136     int ret, i, withinfo = 0;
10137 
10138     s->row_status0[rsi] = SQL_ROW_SUCCESS;
10139     if (s->bkmrk && s->bkmrkcol.valp) {
10140         long *val;
10141 
10142         if (s->bind_type != SQL_BIND_BY_COLUMN) {
10143             val = (long *) ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
10144         } else {
10145             val = (long *) s->bkmrkcol.valp + rsi;
10146         }
10147         if (s->bind_offs) {
10148             val = (long *) ((char *) val + *s->bind_offs);
10149         }
10150         *val = s->rowp;
10151         if (s->bkmrkcol.lenp) {
10152             SQLINTEGER *ival;
10153 
10154             if (s->bind_type != SQL_BIND_BY_COLUMN) {
10155                 ival = (SQLINTEGER *) ((char *) s->bkmrkcol.lenp +
10156                                        s->bind_type * rsi);
10157             } else {
10158                 ival = &s->bkmrkcol.lenp[rsi];
10159             }
10160             if (s->bind_offs) {
10161                 ival = (SQLINTEGER *) ((char *) ival + *s->bind_offs);
10162             }
10163             *ival = sizeof (long);
10164         }
10165     }
10166     ret = SQL_SUCCESS;
10167     for (i = 0; s->bindcols && i < s->ncols; i++) {
10168         BINDCOL *b = &s->bindcols[i];
10169         SQLPOINTER dp = 0;
10170         SQLINTEGER *lp = 0;
10171 
10172         b->offs = 0;
10173         if (b->valp) {
10174             if (s->bind_type != SQL_BIND_BY_COLUMN) {
10175                 dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
10176             } else {
10177                 dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
10178             }
10179             if (s->bind_offs) {
10180                 dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
10181             }
10182         }
10183         if (b->lenp) {
10184             if (s->bind_type != SQL_BIND_BY_COLUMN) {
10185                 lp = (SQLINTEGER *) ((char *) b->lenp + s->bind_type * rsi);
10186             } else {
10187                 lp = b->lenp + rsi;
10188             }
10189             if (s->bind_offs) {
10190                 lp = (SQLINTEGER *) ((char *) lp + *s->bind_offs);
10191             }
10192         }
10193         if (dp || lp) {
10194             ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
10195             if (!SQL_SUCCEEDED(ret)) {
10196                 s->row_status0[rsi] = SQL_ROW_ERROR;
10197                 break;
10198             }
10199             if (ret != SQL_SUCCESS) {
10200                 withinfo = 1;
10201 #ifdef SQL_ROW_SUCCESS_WITH_INFO
10202                 s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
10203 #endif
10204             }
10205         }
10206     }
10207     if (SQL_SUCCEEDED(ret)) {
10208         ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
10209     }
10210     return ret;
10211 }
10212 
10221 static SQLRETURN
10222 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
10223 {
10224     STMT *s;
10225     int i, withinfo = 0;
10226     SQLRETURN ret;
10227 
10228     if (stmt == SQL_NULL_HSTMT) {
10229         return SQL_INVALID_HANDLE;
10230     }
10231     s = (STMT *) stmt;
10232     for (i = 0; i < s->rowset_size; i++) {
10233         s->row_status0[i] = SQL_ROW_NOROW;
10234     }
10235     if (s->row_status) {
10236         memcpy(s->row_status, s->row_status0,
10237                sizeof (SQLUSMALLINT) * s->rowset_size);
10238     }
10239     s->row_count0 = 0;
10240     if (s->row_count) {
10241         *s->row_count = s->row_count0;
10242     }
10243     if (!s->bindcols) {
10244         for (i = 0; i < s->rowset_size; i++) {
10245             s->row_status0[i] = SQL_ROW_ERROR;
10246         }
10247         ret = SQL_ERROR;
10248         i = 0;
10249         goto done2;
10250     }
10251     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
10252         setstat(s, -1, "wrong fetch direction", "01000");
10253         ret = SQL_ERROR;
10254         i = 0;
10255         goto done2;
10256     }
10257     ret = SQL_SUCCESS;
10258     i = 0;
10259     if (((DBC *) (s->dbc))->vm_stmt == s && s->vm) {
10260         s->rowp = 0;
10261         for (; i < s->rowset_size; i++) {
10262             ret = vm_step(s);
10263             if (ret != SQL_SUCCESS) {
10264                 s->row_status0[i] = SQL_ROW_ERROR;
10265                 break;
10266             }
10267             if (s->nrows < 1) {
10268                 break;
10269             }
10270             ret = dofetchbind(s, i);
10271             if (!SQL_SUCCEEDED(ret)) {
10272                 break;
10273             } else if (ret == SQL_SUCCESS_WITH_INFO) {
10274                 withinfo = 1;
10275             }
10276         }
10277     } else if (s->rows) {
10278         switch (orient) {
10279         case SQL_FETCH_NEXT:
10280             if (s->nrows < 1) {
10281                 return SQL_NO_DATA;
10282             }
10283             if (s->rowp < 0) {
10284                 s->rowp = -1;
10285             }
10286             if (s->rowp >= s->nrows) {
10287                 s->rowp = s->nrows;
10288                 return SQL_NO_DATA;
10289             }
10290             break;
10291         case SQL_FETCH_PRIOR:
10292             if (s->nrows < 1) {
10293                 s->rowp = -1;
10294                 return SQL_NO_DATA;
10295             }
10296             s->rowp -= s->rowset_size + 1;
10297             if (s->rowp < -1) {
10298                 s->rowp = -1;
10299                 return SQL_NO_DATA;
10300             }
10301             break;
10302         case SQL_FETCH_FIRST:
10303             if (s->nrows < 1) {
10304                 return SQL_NO_DATA;
10305             }
10306             s->rowp = -1;
10307             break;
10308         case SQL_FETCH_LAST:
10309             if (s->nrows < 1) {
10310                 return SQL_NO_DATA;
10311             }
10312             s->rowp = s->nrows - s->rowset_size;
10313             if (--s->rowp < -1) {
10314                 s->rowp = -1;
10315             }
10316             break;
10317         case SQL_FETCH_ABSOLUTE:
10318             if (offset == 0) {
10319                 s->rowp = -1;
10320                 return SQL_NO_DATA;
10321             } else if (offset < 0) {
10322                 if (0 - offset <= s->nrows) {
10323                     s->rowp = s->nrows + offset - 1;
10324                     break;
10325                 }
10326                 s->rowp = -1;
10327                 return SQL_NO_DATA;
10328             } else if (offset > s->nrows) {
10329                 s->rowp = s->nrows;
10330                 return SQL_NO_DATA;
10331             }
10332             s->rowp = offset - 1 - 1;
10333             break;
10334         case SQL_FETCH_RELATIVE:
10335             if (offset >= 0) {
10336                 s->rowp += offset * s->rowset_size - 1;
10337                 if (s->rowp >= s->nrows) {
10338                     s->rowp = s->nrows;
10339                     return SQL_NO_DATA;
10340                 }
10341             } else {
10342                 s->rowp += offset * s->rowset_size - 1;
10343                 if (s->rowp < -1) {
10344                     s->rowp = -1;
10345                     return SQL_NO_DATA;
10346                 }
10347             }
10348             break;
10349         case SQL_FETCH_BOOKMARK:
10350             if (s->bkmrk) {
10351                 if (offset < 0 || offset >= s->nrows) {
10352                     return SQL_NO_DATA;
10353                 }
10354                 s->rowp = offset - 1;
10355                 break;
10356             }
10357             /* fall through */
10358         default:
10359             s->row_status0[0] = SQL_ROW_ERROR;
10360             ret = SQL_ERROR;
10361             goto done;
10362         }
10363         for (; i < s->rowset_size; i++) {
10364             ++s->rowp;
10365             if (s->rowp < 0 || s->rowp >= s->nrows) {
10366                 break;
10367             }
10368             ret = dofetchbind(s, i);
10369             if (!SQL_SUCCEEDED(ret)) {
10370                 break;
10371             } else if (ret == SQL_SUCCESS_WITH_INFO) {
10372                 withinfo = 1;
10373             }
10374         }
10375     }
10376 done:
10377     if (i == 0) {
10378         if (SQL_SUCCEEDED(ret)) {
10379             return SQL_NO_DATA;
10380         }
10381         return ret;
10382     }
10383     if (SQL_SUCCEEDED(ret)) {
10384         ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
10385     }
10386 done2:
10387     if (s->row_status) {
10388         memcpy(s->row_status, s->row_status0,
10389                sizeof (SQLUSMALLINT) * s->rowset_size);
10390     }
10391     s->row_count0 = i;
10392     if (s->row_count) {
10393         *s->row_count = s->row_count0;
10394     }
10395     return ret;
10396 }
10397 
10404 SQLRETURN SQL_API
10405 SQLFetch(SQLHSTMT stmt)
10406 {
10407     return drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
10408 }
10409 
10418 SQLRETURN SQL_API
10419 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
10420 {
10421     return drvfetchscroll(stmt, orient, offset);
10422 }
10423 
10434 SQLRETURN SQL_API
10435 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLINTEGER offset,
10436                  SQLUINTEGER *rowcount, SQLUSMALLINT *rowstatus)
10437 {
10438     STMT *s;
10439     SQLRETURN ret;
10440     SQLUSMALLINT *rst;
10441 
10442     if (stmt == SQL_NULL_HSTMT) {
10443         return SQL_INVALID_HANDLE;
10444     }
10445     s = (STMT *) stmt;
10446     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
10447     rst = s->row_status;
10448     s->row_status = 0;
10449     ret = drvfetchscroll(stmt, orient, offset);
10450     s->row_status = rst;
10451     if (rowstatus) {
10452         memcpy(rowstatus, s->row_status0,
10453                sizeof (SQLUSMALLINT) * s->rowset_size);
10454     }
10455     if (rowcount) {
10456         *rowcount = s->row_count0;
10457     }
10458     return ret;
10459 }
10460 
10468 SQLRETURN SQL_API
10469 SQLRowCount(SQLHSTMT stmt, SQLINTEGER *nrows)
10470 {
10471     STMT *s;
10472 
10473     if (stmt == SQL_NULL_HSTMT) {
10474         return SQL_INVALID_HANDLE;
10475     }
10476     s = (STMT *) stmt;
10477     if (nrows) {
10478         *nrows = s->nrows;
10479     }
10480     return SQL_SUCCESS;
10481 }
10482 
10490 SQLRETURN SQL_API
10491 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
10492 {
10493     STMT *s;
10494 
10495     if (stmt == SQL_NULL_HSTMT) {
10496         return SQL_INVALID_HANDLE;
10497     }
10498     s = (STMT *) stmt;
10499     if (ncols) {
10500         *ncols = s->ncols;
10501     }
10502     return SQL_SUCCESS;
10503 }
10504 
10519 static SQLRETURN
10520 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
10521                SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
10522                SQLSMALLINT *type, SQLUINTEGER *size,
10523                SQLSMALLINT *digits, SQLSMALLINT *nullable)
10524 {
10525     STMT *s;
10526     COL *c;
10527     int didname = 0;
10528 
10529     if (stmt == SQL_NULL_HSTMT) {
10530         return SQL_INVALID_HANDLE;
10531     }
10532     s = (STMT *) stmt;
10533     if (!s->cols) {
10534         setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
10535         return SQL_ERROR;
10536     }
10537     if (col < 1 || col > s->ncols) {
10538         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
10539         return SQL_ERROR;
10540     }
10541     c = s->cols + col - 1;
10542     if (name && nameMax > 0) {
10543         strncpy(name, c->column, nameMax);
10544         name[nameMax - 1] = '\0';
10545         didname = 1;
10546     }
10547     if (nameLen) {
10548         if (didname) {
10549             *nameLen = strlen(name);
10550         } else {
10551             *nameLen = strlen(c->column);
10552         }
10553     }
10554     if (type) {
10555         *type = c->type;
10556 #ifdef SQLITE_UTF8
10557         if (s->nowchar) {
10558             switch (c->type) {
10559             case SQL_WCHAR:
10560                 *type = SQL_CHAR;
10561                 break;
10562             case SQL_WVARCHAR:
10563                 *type = SQL_VARCHAR;
10564                 break;
10565 #ifdef SQL_LONGVARCHAR
10566             case SQL_WLONGVARCHAR:
10567                 *type = SQL_LONGVARCHAR;
10568                 break;
10569 #endif
10570             }
10571         }
10572 #endif
10573     }
10574     if (size) {
10575         *size = c->size;
10576     }
10577     if (digits) {
10578         *digits = 0;
10579     }
10580     if (nullable) {
10581         *nullable = 1;
10582     }
10583     return SQL_SUCCESS;
10584 }
10585 
10586 #ifndef SQLITE_UTF8
10587 
10601 SQLRETURN SQL_API
10602 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
10603                SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
10604                SQLSMALLINT *type, SQLUINTEGER *size,
10605                SQLSMALLINT *digits, SQLSMALLINT *nullable)
10606 {
10607     return drvdescribecol(stmt, col, name, nameMax, nameLen,
10608                           type, size, digits, nullable);
10609 }
10610 #endif
10611 
10612 #ifdef SQLITE_UTF8
10613 
10627 SQLRETURN SQL_API
10628 SQLDescribeColW(SQLHSTMT stmt, SQLUSMALLINT col, SQLWCHAR *name,
10629                 SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
10630                 SQLSMALLINT *type, SQLUINTEGER *size,
10631                 SQLSMALLINT *digits, SQLSMALLINT *nullable)
10632 {
10633     SQLRETURN ret;
10634     SQLSMALLINT len;
10635 
10636     ret = drvdescribecol(stmt, col, (char *) name,
10637                          (SQLSMALLINT) (nameMax * sizeof (SQLWCHAR)),
10638                          &len, type, size, digits, nullable);
10639     if (ret == SQL_SUCCESS) {
10640         if (name) {
10641             if (len > 0) {
10642                 SQLWCHAR *n = NULL;
10643 
10644                 n = uc_from_utf((char *) name, len);
10645                 if (n) {
10646                     uc_strncpy(name, n, nameMax);
10647                     len = min(nameMax, uc_strlen(n));
10648                     uc_free(n);
10649                 } else {
10650                     len = 0;
10651                 }
10652             }
10653             if (len <= 0) {
10654                 len = 0;
10655                 if (nameMax > 0) {
10656                     name[0] = 0;
10657                 }
10658             }
10659         } else {
10660             STMT *s = (STMT *) stmt;
10661             COL *c = s->cols + col - 1;
10662 
10663             len = 0;
10664             if (c->column) {
10665                 len = strlen(c->column);
10666             }
10667         }
10668         if (nameLen) {
10669             *nameLen = len;
10670         }
10671     }
10672     return ret;
10673 }
10674 #endif
10675 
10688 static SQLRETURN
10689 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
10690                  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
10691                  SQLINTEGER *val2)
10692 {
10693     STMT *s;
10694     COL *c;
10695     SQLSMALLINT dummy;
10696     char *valc = (char *) val;
10697 
10698     if (stmt == SQL_NULL_HSTMT) {
10699         return SQL_INVALID_HANDLE;
10700     }
10701     s = (STMT *) stmt;
10702     if (!s->cols) {
10703         return SQL_ERROR;
10704     }
10705     if (!valLen) {
10706         valLen = &dummy;
10707     }
10708     if (id == SQL_COLUMN_COUNT) {
10709         if (val2) {
10710             *val2 = s->ncols;
10711         }
10712         *valLen = sizeof (int);
10713         return SQL_SUCCESS;
10714     }
10715     if (id == SQL_COLUMN_TYPE && col == 0) {
10716         if (val2) {
10717             *val2 = SQL_INTEGER;
10718         }
10719         *valLen = sizeof (int);
10720         return SQL_SUCCESS;
10721     }
10722 #ifdef SQL_DESC_OCTET_LENGTH
10723     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
10724         if (val2) {
10725             *val2 = 4;
10726         }
10727         *valLen = sizeof (int);
10728         return SQL_SUCCESS;
10729     }
10730 #endif
10731     if (col < 1 || col > s->ncols) {
10732         setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
10733         return SQL_ERROR;
10734     }
10735     c = s->cols + col - 1;
10736 
10737     switch (id) {
10738     case SQL_COLUMN_LABEL:
10739         if (c->label) {
10740             if (valc && valMax > 0) {
10741                 strncpy(valc, c->label, valMax);
10742                 valc[valMax - 1] = '\0';
10743             }
10744             if (valLen) {
10745                 *valLen = strlen(c->label);
10746             }
10747             goto checkLen;
10748         }
10749         /* fall through */
10750     case SQL_COLUMN_NAME:
10751     case SQL_DESC_NAME:
10752         if (valc && valMax > 0) {
10753             strncpy(valc, c->column, valMax);
10754             valc[valMax - 1] = '\0';
10755         }
10756         *valLen = strlen(c->column);
10757 checkLen:
10758         if (*valLen >= valMax) {
10759             setstat(s, -1, "data right truncated", "01004");
10760             return SQL_SUCCESS_WITH_INFO;
10761         }
10762         return SQL_SUCCESS;
10763     case SQL_COLUMN_TYPE:
10764     case SQL_DESC_TYPE:
10765 #ifdef SQLITE_UTF8
10766         {
10767             int type = c->type;
10768 
10769             if (s->nowchar) {
10770                 switch (type) {
10771                 case SQL_WCHAR:
10772                     type = SQL_CHAR;
10773                     break;
10774                 case SQL_WVARCHAR:
10775                     type = SQL_VARCHAR;
10776                     break;
10777 #ifdef SQL_LONGVARCHAR
10778                 case SQL_WLONGVARCHAR:
10779                     type = SQL_LONGVARCHAR;
10780                     break;
10781                 }
10782             }
10783             if (val2) {
10784                 *val2 = type;
10785             }
10786 #endif
10787         }
10788 #else
10789         if (val2) {
10790             *val2 = c->type;
10791         }
10792 #endif
10793         *valLen = sizeof (int);
10794         return SQL_SUCCESS;
10795     case SQL_COLUMN_DISPLAY_SIZE:
10796         if (val2) {
10797             *val2 = c->size;
10798         }
10799         *valLen = sizeof (int);
10800         return SQL_SUCCESS;
10801     case SQL_COLUMN_UNSIGNED:
10802         if (val2) {
10803             *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
10804         }
10805         *valLen = sizeof (int);
10806         return SQL_SUCCESS;
10807     case SQL_COLUMN_SCALE:
10808     case SQL_DESC_SCALE:
10809         if (val2) {
10810             *val2 = c->scale;
10811         }
10812         *valLen = sizeof (int);
10813         return SQL_SUCCESS;
10814     case SQL_COLUMN_PRECISION:
10815     case SQL_DESC_PRECISION:
10816         if (val2) {
10817             *val2 = c->prec;
10818         }
10819         *valLen = sizeof (int);
10820         return SQL_SUCCESS;
10821     case SQL_COLUMN_MONEY:
10822         if (val2) {
10823             *val2 = SQL_FALSE;
10824         }
10825         *valLen = sizeof (int);
10826         return SQL_SUCCESS;
10827     case SQL_COLUMN_AUTO_INCREMENT:
10828         if (val2) {
10829             *val2 = c->autoinc > 0 ? SQL_TRUE : SQL_FALSE;
10830         }
10831         *valLen = sizeof (int);
10832         return SQL_SUCCESS;
10833     case SQL_COLUMN_LENGTH:
10834     case SQL_DESC_LENGTH:
10835         if (val2) {
10836             *val2 = c->size;
10837         }
10838         *valLen = sizeof (int);
10839         return SQL_SUCCESS;
10840     case SQL_COLUMN_NULLABLE:
10841     case SQL_DESC_NULLABLE:
10842         if (val2) {
10843             *val2 = SQL_NULLABLE;
10844         }
10845         *valLen = sizeof (int);
10846         return SQL_SUCCESS;
10847     case SQL_COLUMN_SEARCHABLE:
10848         if (val2) {
10849             *val2 = SQL_SEARCHABLE;
10850         }
10851         *valLen = sizeof (int);
10852         return SQL_SUCCESS;
10853     case SQL_COLUMN_CASE_SENSITIVE:
10854         if (val2) {
10855             *val2 = SQL_TRUE;
10856         }
10857         *valLen = sizeof (int);
10858         return SQL_SUCCESS;
10859     case SQL_COLUMN_UPDATABLE:
10860         if (val2) {
10861             *val2 = SQL_TRUE;
10862         }
10863         *valLen = sizeof (int);
10864         return SQL_SUCCESS;
10865     case SQL_COLUMN_TYPE_NAME: {
10866         char *tn = c->typename ? c->typename : "varchar";
10867 
10868         if (valc && valMax > 0) {
10869             strncpy(valc, tn, valMax);
10870             valc[valMax - 1] = '\0';
10871         }
10872         *valLen = strlen(tn);
10873         goto checkLen;
10874     }
10875     case SQL_COLUMN_OWNER_NAME:
10876     case SQL_COLUMN_QUALIFIER_NAME: {
10877         char *z = "";
10878 
10879         if (valc && valMax > 0) {
10880             strncpy(valc, z, valMax);
10881             valc[valMax - 1] = '\0';
10882         }
10883         *valLen = strlen(z);
10884         goto checkLen;
10885     }
10886     case SQL_COLUMN_TABLE_NAME:
10887 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
10888     case SQL_DESC_TABLE_NAME:
10889 #endif
10890         if (valc && valMax > 0) {
10891             strncpy(valc, c->table, valMax);
10892             valc[valMax - 1] = '\0';
10893         }
10894         *valLen = strlen(c->table);
10895         goto checkLen;
10896     }
10897     setstat(s, -1, "unsupported column attributes %d", "HY091", id);
10898     return SQL_ERROR;
10899 }
10900 
10901 #ifndef SQLITE_UTF8
10902 
10914 SQLRETURN SQL_API
10915 SQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
10916                  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
10917                  SQLINTEGER *val2)
10918 {
10919     return drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
10920 }
10921 #endif
10922 
10923 #ifdef SQLITE_UTF8
10924 
10936 SQLRETURN SQL_API
10937 SQLColAttributesW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
10938                   SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
10939                   SQLINTEGER *val2)
10940 {
10941     SQLRETURN ret;
10942     SQLSMALLINT len;
10943 
10944     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
10945     if (SQL_SUCCEEDED(ret)) {
10946         SQLWCHAR *v = NULL;
10947 
10948         switch (id) {
10949         case SQL_COLUMN_LABEL:
10950         case SQL_COLUMN_NAME:
10951         case SQL_DESC_NAME:
10952         case SQL_COLUMN_TYPE_NAME:
10953         case SQL_COLUMN_OWNER_NAME:
10954         case SQL_COLUMN_QUALIFIER_NAME:
10955         case SQL_COLUMN_TABLE_NAME:
10956 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
10957         case SQL_DESC_TABLE_NAME:
10958 #endif
10959             if (val && valMax > 0) {
10960                 int vmax = valMax / sizeof (SQLWCHAR);
10961 
10962                 v = uc_from_utf((char *) val, SQL_NTS);
10963                 if (v) {
10964                     uc_strncpy(val, v, vmax);
10965                     len = min(vmax, uc_strlen(v));
10966                     uc_free(v);
10967                 }
10968                 if (vmax > 0) {
10969                     v = (SQLWCHAR *) val;
10970                     v[vmax - 1] = '\0';
10971                 }
10972             }
10973             if (len <= 0) {
10974                 len = 0;
10975             }
10976             break;
10977         }
10978         if (valLen) {
10979             *valLen = len;
10980         }
10981     }
10982     return ret;
10983 }
10984 #endif
10985 
10998 static SQLRETURN
10999 drvcolattribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
11000                 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
11001                 SQLPOINTER val2)
11002 {
11003     STMT *s;
11004     COL *c;
11005     int v = 0;
11006     char *valc = (char *) val;
11007 
11008     if (stmt == SQL_NULL_HSTMT) {
11009         return SQL_INVALID_HANDLE;
11010     }
11011     s = (STMT *) stmt;
11012     if (!s->cols) {
11013         return SQL_ERROR;
11014     }
11015     if (col < 1 || col > s->ncols) {
11016         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
11017         return SQL_ERROR;
11018     }
11019     c = s->cols + col - 1;
11020     switch (id) {
11021     case SQL_DESC_CATALOG_NAME:
11022         if (valc && valMax > 0) {
11023             strncpy(valc, c->db, valMax);
11024             valc[valMax - 1] = '\0';
11025         }
11026         if (valLen) {
11027             *valLen = strlen(c->db);
11028         }
11029 checkLen:
11030         if (valLen && *valLen >= valMax) {
11031             setstat(s, -1, "data right truncated", "01004");
11032             return SQL_SUCCESS_WITH_INFO;
11033         }
11034         break;
11035     case SQL_COLUMN_LENGTH:
11036     case SQL_DESC_LENGTH:
11037         v = c->size;
11038         break;
11039     case SQL_COLUMN_LABEL:
11040         if (c->label) {
11041             if (valc && valMax > 0) {
11042                 strncpy(valc, c->label, valMax);
11043                 valc[valMax - 1] = '\0';
11044             }
11045             if (valLen) {
11046                 *valLen = strlen(c->label);
11047             }
11048             goto checkLen;
11049         }
11050         /* fall through */
11051     case SQL_COLUMN_NAME:
11052     case SQL_DESC_NAME:
11053         if (valc && valMax > 0) {
11054             strncpy(valc, c->column, valMax);
11055             valc[valMax - 1] = '\0';
11056         }
11057         if (valLen) {
11058             *valLen = strlen(c->column);
11059             goto checkLen;
11060         }
11061         break;
11062     case SQL_DESC_TYPE_NAME: {
11063         char *tn = c->typename ? c->typename : "varchar";
11064 
11065         if (valc && valMax > 0) {
11066             strncpy(valc, tn, valMax);
11067             valc[valMax - 1] = '\0';
11068         }
11069         if (valLen) {
11070             *valLen = strlen(tn);
11071             goto checkLen;
11072         }
11073         break;
11074     }
11075     case SQL_DESC_OCTET_LENGTH:
11076         v = c->size;
11077         break;
11078 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
11079     case SQL_COLUMN_TABLE_NAME:
11080 #endif
11081     case SQL_DESC_TABLE_NAME:
11082         if (valc && valMax > 0) {
11083             strncpy(valc, c->table, valMax);
11084             valc[valMax - 1] = '\0';
11085         }
11086         if (valLen) {
11087             *valLen = strlen(c->table);
11088             goto checkLen;
11089         }
11090         break;
11091     case SQL_DESC_TYPE:
11092         v = c->type;
11093 #ifdef SQLITE_UTF8
11094         if (s->nowchar) {
11095             switch (v) {
11096             case SQL_WCHAR:
11097                 v = SQL_CHAR;
11098                 break;
11099             case SQL_WVARCHAR:
11100                 v = SQL_VARCHAR;
11101                 break;
11102 #ifdef SQL_LONGVARCHAR
11103             case SQL_WLONGVARCHAR:
11104                 v = SQL_LONGVARCHAR;
11105                 break;
11106 #endif
11107             }
11108         }
11109 #endif
11110         break;
11111     case SQL_DESC_CONCISE_TYPE:
11112         switch (c->type) {
11113         case SQL_INTEGER:
11114             v = SQL_C_LONG;
11115             break;
11116         case SQL_TINYINT:
11117             v = SQL_C_TINYINT;
11118             break;
11119         case SQL_SMALLINT:
11120             v = SQL_C_SHORT;
11121             break;
11122         case SQL_FLOAT:
11123             v = SQL_C_FLOAT;
11124             break;
11125         case SQL_DOUBLE:
11126             v = SQL_C_DOUBLE;
11127             break;
11128         case SQL_TIMESTAMP:
11129             v = SQL_C_TIMESTAMP;
11130             break;
11131         case SQL_TIME:
11132             v = SQL_C_TIME;
11133             break;
11134         case SQL_DATE:
11135             v = SQL_C_DATE;
11136             break;
11137 #ifdef SQL_C_TYPE_TIMESTAMP
11138         case SQL_TYPE_TIMESTAMP:
11139             v = SQL_C_TYPE_TIMESTAMP;
11140             break;
11141 #endif
11142 #ifdef SQL_C_TYPE_TIME
11143         case SQL_TYPE_TIME:
11144             v = SQL_C_TYPE_TIME;
11145             break;
11146 #endif
11147 #ifdef SQL_C_TYPE_DATE
11148         case SQL_TYPE_DATE:
11149             v = SQL_C_TYPE_DATE;
11150             break;
11151 #endif
11152         default:
11153 #ifdef SQLITE_UTF8
11154             v = s->nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
11155 #else
11156             v = SQL_C_CHAR;
11157 #endif
11158             break;
11159         }
11160         break;
11161     case SQL_DESC_UPDATABLE:
11162         v = SQL_TRUE;
11163         break;
11164     case SQL_COLUMN_DISPLAY_SIZE:
11165         v = c->size;
11166         break;
11167     case SQL_COLUMN_UNSIGNED:
11168         v = c->nosign ? SQL_TRUE : SQL_FALSE;
11169         break;
11170     case SQL_COLUMN_SEARCHABLE:
11171         v = SQL_SEARCHABLE;
11172         break;
11173     case SQL_COLUMN_SCALE:
11174     case SQL_DESC_SCALE:
11175         v = c->scale;
11176         break;
11177     case SQL_COLUMN_PRECISION:
11178     case SQL_DESC_PRECISION:
11179         v = c->prec;
11180         break;
11181     case SQL_COLUMN_MONEY:
11182         v = SQL_FALSE;
11183         break;
11184     case SQL_COLUMN_AUTO_INCREMENT:
11185         v = c->autoinc > 0 ? SQL_TRUE : SQL_FALSE;
11186         break;
11187     case SQL_DESC_NULLABLE:
11188         v = SQL_NULLABLE;
11189         break;
11190     default:
11191         setstat(s, -1, "unsupported column attribute %d", "HY091", id);
11192         return SQL_ERROR;
11193     }
11194     if (val2) {
11195         *(int *) val2 = v;
11196     }
11197     return SQL_SUCCESS;
11198 }
11199 
11200 #ifndef SQLITE_UTF8
11201 
11213 SQLRETURN SQL_API
11214 SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
11215                 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
11216                 SQLPOINTER val2)
11217 {
11218     return drvcolattribute(stmt, col, id, val, valMax, valLen, val2);
11219 }
11220 #endif
11221 
11222 #ifdef SQLITE_UTF8
11223 
11235 SQLRETURN SQL_API
11236 SQLColAttributeW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
11237                  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
11238                  SQLPOINTER val2)
11239 {
11240     SQLRETURN ret;
11241     SQLSMALLINT len;
11242 
11243     ret = drvcolattribute(stmt, col, id, val, valMax, &len, val2);
11244     if (SQL_SUCCEEDED(ret)) {
11245         SQLWCHAR *v = NULL;
11246 
11247         switch (id) {
11248         case SQL_DESC_CATALOG_NAME:
11249         case SQL_COLUMN_LABEL:
11250         case SQL_DESC_NAME:
11251         case SQL_DESC_TABLE_NAME:
11252         case SQL_DESC_TYPE_NAME:
11253             if (val && valMax > 0) {
11254                 int vmax = valMax / sizeof (SQLWCHAR);
11255 
11256                 v = uc_from_utf((char *) val, SQL_NTS);
11257                 if (v) {
11258                     uc_strncpy(val, v, vmax);
11259                     len = min(vmax, uc_strlen(v));
11260                     uc_free(v);
11261                 }
11262                 if (vmax > 0) {
11263                     v = (SQLWCHAR *) val;
11264                     v[vmax - 1] = '\0';
11265                 }
11266             }
11267             if (len <= 0) {
11268                 len = 0;
11269             }
11270             break;
11271         }
11272         if (valLen) {
11273             *valLen = len;
11274         }
11275     }
11276     return ret;
11277 }
11278 #endif
11279 
11293 static SQLRETURN
11294 drverror(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
11295          SQLCHAR *sqlState, SQLINTEGER *nativeErr,
11296          SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
11297 {
11298     SQLCHAR dummy0[6];
11299     SQLINTEGER dummy1;
11300     SQLSMALLINT dummy2;
11301 
11302     if (env == SQL_NULL_HENV &&
11303         dbc == SQL_NULL_HDBC &&
11304         stmt == SQL_NULL_HSTMT) {
11305         return SQL_INVALID_HANDLE;
11306     }
11307     if (sqlState) {
11308         sqlState[0] = '\0';
11309     } else {
11310         sqlState = dummy0;
11311     }
11312     if (!nativeErr) {
11313         nativeErr = &dummy1;
11314     }
11315     *nativeErr = 0;
11316     if (!errlen) {
11317         errlen = &dummy2;
11318     }
11319     *errlen = 0;
11320     if (errmsg) {
11321         if (errmax > 0) {
11322             errmsg[0] = '\0';
11323         }
11324     } else {
11325         errmsg = dummy0;
11326         errmax = 0;
11327     }
11328     if (stmt) {
11329         STMT *s = (STMT *) stmt;
11330 
11331         if (s->logmsg[0] == '\0') {
11332             goto noerr;
11333         }
11334         *nativeErr = s->naterr;
11335         strcpy(sqlState, s->sqlstate);
11336         if (errmax == SQL_NTS) {
11337             strcpy(errmsg, "[SQLite]");
11338             strcat(errmsg, s->logmsg);
11339             *errlen = strlen(errmsg);
11340         } else {
11341             strncpy(errmsg, "[SQLite]", errmax);
11342             if (errmax - 8 > 0) {
11343                 strncpy(errmsg + 8, s->logmsg, errmax - 8);
11344             }
11345             *errlen = min(strlen(s->logmsg) + 8, errmax);
11346         }
11347         s->logmsg[0] = '\0';
11348         return SQL_SUCCESS;
11349     }
11350     if (dbc) {
11351         DBC *d = (DBC *) dbc;
11352 
11353         if (d->magic != DBC_MAGIC || d->logmsg[0] == '\0') {
11354             goto noerr;
11355         }
11356         *nativeErr = d->naterr;
11357         strcpy(sqlState, d->sqlstate);
11358         if (errmax == SQL_NTS) {
11359             strcpy(errmsg, "[SQLite]");
11360             strcat(errmsg, d->logmsg);
11361             *errlen = strlen(errmsg);
11362         } else {
11363             strncpy(errmsg, "[SQLite]", errmax);
11364             if (errmax - 8 > 0) {
11365                 strncpy(errmsg + 8, d->logmsg, errmax - 8);
11366             }
11367             *errlen = min(strlen(d->logmsg) + 8, errmax);
11368         }
11369         d->logmsg[0] = '\0';
11370         return SQL_SUCCESS;
11371     }
11372 noerr:
11373     sqlState[0] = '\0';
11374     errmsg[0] = '\0';
11375     *nativeErr = 0;
11376     *errlen = 0;
11377     return SQL_NO_DATA_FOUND;
11378 }
11379 
11380 #ifndef SQLITE_UTF8
11381 
11394 SQLRETURN SQL_API
11395 SQLError(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
11396          SQLCHAR *sqlState, SQLINTEGER *nativeErr,
11397          SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
11398 {
11399     return drverror(env, dbc, stmt, sqlState, nativeErr,
11400                     errmsg, errmax, errlen);
11401 }
11402 #endif
11403 
11404 #ifdef SQLITE_UTF8
11405 
11418 SQLRETURN SQL_API
11419 SQLErrorW(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
11420           SQLWCHAR *sqlState, SQLINTEGER *nativeErr,
11421           SQLWCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
11422 {
11423     char state[16];
11424     SQLSMALLINT len;
11425     SQLRETURN ret;
11426     
11427     ret = drverror(env, dbc, stmt, state, nativeErr,
11428                    (char *) errmsg, errmax, &len);
11429     if (ret == SQL_SUCCESS) {
11430         if (sqlState) {
11431             uc_from_utf_buf(state, sqlState, 6 * sizeof (SQLWCHAR));
11432         }
11433         if (errmsg) {
11434             if (len > 0) {
11435                 SQLWCHAR *e = NULL;
11436 
11437                 e = uc_from_utf((char *) errmsg, len);
11438                 if (e) {
11439                     if (errmax > 0) {
11440                         uc_strncpy(errmsg, e, errmax);
11441                         len = min(errmax, uc_strlen(e));
11442                     } else {
11443                         len = uc_strlen(e);
11444                     }
11445                     uc_free(e);
11446                 } else {
11447                     len = 0;
11448                 }
11449             }
11450             if (len <= 0) {
11451                 len = 0;
11452                 if (errmax > 0) {
11453                     errmsg[0] = 0;
11454                 }
11455             }
11456         } else {
11457             len = 0;
11458         }
11459         if (errlen) {
11460             *errlen = len;
11461         }
11462     } else if (ret == SQL_NO_DATA) {
11463         if (sqlState) {
11464             sqlState[0] = 0;
11465         }
11466         if (errmsg) {
11467             if (errmax > 0) {
11468                 errmsg[0] = 0;
11469             }
11470         }
11471         if (errlen) {
11472             *errlen = 0;
11473         }
11474     }
11475     return ret;
11476 }
11477 #endif
11478 
11485 SQLRETURN SQL_API
11486 SQLMoreResults(SQLHSTMT stmt)
11487 {
11488     if (stmt == SQL_NULL_HSTMT) {
11489         return SQL_INVALID_HANDLE;
11490     }
11491     return SQL_NO_DATA;
11492 }
11493 
11503 static int
11504 selcb(void *arg, int ncols, char **values, char **cols)
11505 {
11506     STMT *s = (STMT *) arg;
11507 
11508     if (ncols > 0) {
11509         int i, size;
11510         char *p;
11511         COL *dyncols;
11512         DBC *d = (DBC *) s->dbc;
11513 
11514         for (i = size = 0; i < ncols; i++) {
11515             size += 3 + 3 * strlen(cols[i]);
11516         }
11517         dyncols = xmalloc(ncols * sizeof (COL) + size);
11518         if (!dyncols) {
11519             freedyncols(s);
11520             s->ncols = 0;
11521             return 1;
11522         }
11523         p = (char *) (dyncols + ncols);
11524         for (i = 0; i < ncols; i++) {
11525             char *q;
11526 
11527             dyncols[i].db = ((DBC *) (s->dbc))->dbname;
11528             strcpy(p, cols[i]);
11529             dyncols[i].label = p;
11530             p += strlen(p) + 1;
11531             q = strchr(cols[i], '.');
11532             if (q) {
11533                 dyncols[i].table = p;
11534                 strncpy(p, cols[i], q - cols[i]);
11535                 p[q - cols[i]] = '\0';
11536                 p += strlen(p) + 1;
11537                 strcpy(p, q + 1);
11538                 dyncols[i].column = p;
11539                 p += strlen(p) + 1;
11540             } else {
11541                 dyncols[i].table = "";
11542                 strcpy(p, cols[i]);
11543                 dyncols[i].column = p;
11544                 p += strlen(p) + 1;
11545             }
11546 #ifdef SQL_LONGVARCHAR
11547             dyncols[i].type = SQL_LONGVARCHAR;
11548             dyncols[i].size = 65536;
11549 #else
11550             dyncols[i].type = SQL_VARCHAR;
11551             dyncols[i].size = 256;
11552 #endif
11553             dyncols[i].index = i;
11554             dyncols[i].scale = 0;
11555             dyncols[i].prec = 0;
11556             dyncols[i].nosign = 1;
11557             dyncols[i].autoinc = -1;
11558             dyncols[i].typename = NULL;
11559         }
11560         freedyncols(s);
11561         s->dyncols = s->cols = dyncols;
11562         s->dcols = ncols;
11563         fixupdyncols(s, d->sqlite, (const char **) cols + ncols);
11564     }
11565     s->ncols = ncols;
11566     return 1;
11567 }
11568 
11577 static SQLRETURN
11578 drvprepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
11579 {
11580     STMT *s;
11581     DBC *d;
11582     char *errp = NULL;
11583 
11584     if (stmt == SQL_NULL_HSTMT) {
11585         return SQL_INVALID_HANDLE;
11586     }
11587     s = (STMT *) stmt;
11588     if (s->dbc == SQL_NULL_HDBC) {
11589 noconn:
11590         return noconn(s);
11591     }
11592     d = s->dbc;
11593     if (!d->sqlite) {
11594         goto noconn;
11595     }
11596     vm_end(s);
11597     freep(&s->query);
11598     s->query = fixupsql(query, queryLen, &s->nparams, &s->isselect, &errp,
11599                         d->version, &s->parmnames);
11600     if (!s->query) {
11601         if (errp) {
11602             setstat(s, -1, errp, (*s->ov3) ? "HY000" : "S1000");
11603             return SQL_ERROR;
11604         }
11605         return nomem(s);
11606     }
11607     errp = NULL;
11608     freeresult(s, -1);
11609     if (s->isselect) {
11610         int ret;
11611         char **params = NULL;
11612 
11613         if (s->nparams) {
11614             int i;
11615 
11616             params = xmalloc(s->nparams * sizeof (char *));
11617             if (!params) {
11618                 return nomem(s);
11619             }
11620             for (i = 0; i < s->nparams; i++) {
11621                 params[i] = NULL;
11622             }
11623         }
11624         ret = sqlite_exec_vprintf(d->sqlite, s->query, selcb, s,
11625                                   &errp, (char *) params);
11626         if (ret != SQLITE_ABORT && ret != SQLITE_OK) {
11627             dbtracerc(d, ret, errp);
11628             freep(&params);
11629             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
11630                     errp ? errp : "unknown error", ret);
11631             if (errp) {
11632                 sqlite_freemem(errp);
11633                 errp = NULL;
11634             }
11635             return SQL_ERROR;
11636         }
11637         freep(&params);
11638         if (errp) {
11639             sqlite_freemem(errp);
11640             errp = NULL;
11641         }
11642     }
11643     mkbindcols(s, s->ncols);
11644     if (s->nparams) {
11645         s->paramset_count = 0;
11646     }
11647     return SQL_SUCCESS;
11648 }
11649 
11650 /* see doc on top */
11651 
11652 static SQLRETURN
11653 drvexecute(SQLHSTMT stmt)
11654 {
11655     STMT *s;
11656     DBC *d;
11657     char *errp = NULL, **params = NULL;
11658     int rc, i, size, ncols;
11659     SQLRETURN ret;
11660 
11661     if (stmt == SQL_NULL_HSTMT) {
11662         return SQL_INVALID_HANDLE;
11663     }
11664     s = (STMT *) stmt;
11665     if (s->dbc == SQL_NULL_HDBC) {
11666 noconn:
11667         return noconn(s);
11668     }
11669     d = (DBC *) s->dbc;
11670     if (!d->sqlite) {
11671         goto noconn;
11672     }
11673     if (!s->query) {
11674         setstat(s, -1, "no query prepared", (*s->ov3) ? "HY000" : "S1000");
11675         return SQL_ERROR;
11676     }
11677     if (s->nbindparms < s->nparams) {
11678         setstat(s, -1, "unbound parameters in query",
11679                 (*s->ov3) ? "HY000" : "S1000");
11680         return SQL_ERROR;
11681     }
11682 again:
11683     vm_end(s);
11684     for (i = size = 0; i < s->nparams; i++) {
11685         ret = substparam(s, i, NULL, &size);
11686         if (ret != SQL_SUCCESS) {
11687             goto cleanup;
11688         }
11689     }
11690     if (s->nparams) {
11691         char *p;
11692 
11693         params = xmalloc(s->nparams * sizeof (char *) + size);
11694         if (!params) {
11695             ret = nomem(s);
11696             goto cleanup;
11697         }
11698         p = (char *) (params + s->nparams);
11699         for (i = 0; i < s->nparams; i++) {
11700             int len = 0;
11701 
11702             params[i] = p;
11703             substparam(s, i, &p, NULL);
11704             if (s->bindparms[i].ind) {
11705                 len = s->bindparms[i].len;
11706             } else if (s->bindparms[i].lenp) {
11707                 len = *s->bindparms[i].lenp;
11708             }
11709             if (len == SQL_NULL_DATA) {
11710                 params[i] = NULL;
11711             }
11712         }
11713     }
11714     freeresult(s, 0);
11715     if (!d->autocommit && !d->intrans) {
11716         rc = sqlite_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL, &errp);
11717         dbtracerc(d, rc, errp);
11718         if (rc != SQLITE_OK) {
11719             freep(&params);
11720             setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
11721                     errp ? errp : "unknown error", rc);
11722             if (errp) {
11723                 sqlite_freemem(errp);
11724                 errp = NULL;
11725             }
11726             ret = SQL_ERROR;
11727             goto cleanup;
11728         }
11729         d->intrans = 1;
11730         if (errp) {
11731             sqlite_freemem(errp);
11732             errp = NULL;
11733         }
11734     }
11735     if (s->isselect && !d->intrans &&
11736         s->curtype == SQL_CURSOR_FORWARD_ONLY &&
11737         d->step_enable && s->nparams == 0 && d->vm_stmt == NULL) {
11738         s->nrows = -1;
11739         ret = vm_start(s, params);
11740         if (ret == SQL_SUCCESS) {
11741             freep(&params);
11742             goto done2;
11743         }
11744     }
11745     rc = sqlite_get_table_vprintf(d->sqlite, s->query, &s->rows,
11746                                   &s->nrows, &ncols, &errp, (char *) params);
11747     dbtracerc(d, rc, errp);
11748     if (rc != SQLITE_OK) {
11749         freep(&params);
11750         setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
11751                 errp ? errp : "unknown error", rc);
11752         if (errp) {
11753             sqlite_freemem(errp);
11754             errp = NULL;
11755         }
11756         ret = SQL_ERROR;
11757         goto cleanup;
11758     }
11759     freep(&params);
11760     if (errp) {
11761         sqlite_freemem(errp);
11762         errp = NULL;
11763     }
11764     s->rowfree = sqlite_free_table;
11765     if (ncols == 1 && !s->isselect) {
11766         /*
11767          * INSERT/UPDATE/DELETE results are immediately released,
11768          * but the row count is retained for SQLRowCount().
11769          */
11770         if (strcmp(s->rows[0], "rows inserted") == 0 ||
11771             strcmp(s->rows[0], "rows updated") == 0 ||
11772             strcmp(s->rows[0], "rows deleted") == 0) {
11773             int nrows = 0;
11774            
11775             nrows = strtol(s->rows[1], NULL, 0);
11776             freeresult(s, -1);
11777             s->nrows = nrows;
11778             goto done;
11779         }
11780     }
11781     if (s->ncols != ncols) {
11782         int size;
11783         char *p;
11784         COL *dyncols;
11785 
11786         for (i = size = 0; i < ncols; i++) {
11787             size += 3 + 3 * strlen(s->rows[i]);
11788         }
11789         if (size == 0) {
11790             freeresult(s, -1);
11791             goto done;
11792         }
11793         dyncols = xmalloc(ncols * sizeof (COL) + size);
11794         if (!dyncols) {
11795             ret = nomem(s);
11796             goto cleanup;
11797         }
11798         p = (char *) (dyncols + ncols);
11799         for (i = 0; i < ncols; i++) {
11800             char *q;
11801 
11802             dyncols[i].db = d->dbname;
11803             strcpy(p, s->rows[i]);
11804             dyncols[i].label = p;
11805             p += strlen(p) + 1;
11806             q = strchr(s->rows[i], '.');
11807             if (q) {
11808                 dyncols[i].table = p;
11809                 strncpy(p, s->rows[i], q - s->rows[i]);
11810                 p[q - s->rows[i]] = '\0';
11811                 p += strlen(p) + 1;
11812                 dyncols[i].column = q + 1;
11813             } else {
11814                 dyncols[i].table = "";
11815                 dyncols[i].column = s->rows[i];
11816             }
11817 #ifdef SQL_LONGVARCHAR
11818             dyncols[i].type = SQL_LONGVARCHAR;
11819             dyncols[i].size = 65536;
11820 #else
11821             dyncols[i].type = SQL_VARCHAR;
11822             dyncols[i].size = 255;
11823 #endif
11824             dyncols[i].index = i;
11825             dyncols[i].scale = 0;
11826             dyncols[i].prec = 0;
11827             dyncols[i].nosign = 1;
11828             dyncols[i].autoinc = -1;
11829             dyncols[i].typename = NULL;
11830         }
11831         freedyncols(s);
11832         s->ncols = s->dcols = ncols;
11833         s->dyncols = s->cols = dyncols;
11834         fixupdyncols(s, d->sqlite, NULL);
11835     }
11836 done:
11837     mkbindcols(s, s->ncols);
11838 done2:
11839     ret = SQL_SUCCESS;
11840     s->rowp = -1;
11841     if (s->nparams) {
11842         s->paramset_count++;
11843         s->paramset_nrows += s->nrows;
11844         if (s->paramset_count < s->paramset_size) {
11845             for (i = 0; i < s->nparams; i++) {
11846                 BINDPARM *p = &s->bindparms[i];
11847 
11848                 if (p->param && p->inc > 0) {
11849                     p->param = (char *) p->param + p->inc;
11850                 }
11851             }
11852             goto again;
11853         }
11854     }
11855 cleanup:
11856     if (s->nparams) {
11857         for (i = 0; i < s->nparams; i++) {
11858             BINDPARM *p = &s->bindparms[i];
11859 
11860             p->param = p->param0;
11861         }
11862         s->nrows = s->paramset_nrows;
11863         s->paramset_count = 0;
11864         s->paramset_nrows = 0;
11865     }
11866     return ret;
11867 }
11868 
11869 #ifndef SQLITE_UTF8
11870 
11878 SQLRETURN SQL_API
11879 SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
11880 {
11881     return drvprepare(stmt, query, queryLen);
11882 }
11883 #endif
11884 
11885 #ifdef SQLITE_UTF8
11886 
11894 SQLRETURN SQL_API
11895 SQLPrepareW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
11896 {
11897     SQLRETURN ret;
11898     char *q = uc_to_utf_c(query, queryLen);
11899 
11900     if (!q) {
11901         return nomem((STMT *) stmt);
11902     }
11903     ret = drvprepare(stmt, q, SQL_NTS);
11904     uc_free(q);
11905     return ret;
11906 }
11907 #endif
11908 
11915 SQLRETURN SQL_API
11916 SQLExecute(SQLHSTMT stmt)
11917 {
11918     return drvexecute(stmt);
11919 }
11920 
11921 #ifndef SQLITE_UTF8
11922 
11930 SQLRETURN SQL_API
11931 SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
11932 {
11933     if (drvprepare(stmt, query, queryLen) != SQL_SUCCESS) {
11934         return SQL_ERROR;
11935     }
11936     return drvexecute(stmt);
11937 }
11938 #endif
11939 
11940 #ifdef SQLITE_UTF8
11941 
11949 SQLRETURN SQL_API
11950 SQLExecDirectW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
11951 {
11952     SQLRETURN ret;
11953     char *q = uc_to_utf_c(query, queryLen);
11954 
11955     if (!q) {
11956         return nomem((STMT *) stmt);
11957     }
11958     ret = drvprepare(stmt, q, SQL_NTS);
11959     uc_free(q);
11960     if (ret == SQL_SUCCESS) {
11961         return drvexecute(stmt);
11962     }
11963     return ret;
11964 }
11965 #endif
11966 
11967 #ifdef _WIN32
11968 #ifndef WITHOUT_DRIVERMGR
11969 
11970 /*
11971  * Windows configuration dialog stuff.
11972  */
11973 
11974 #include <windowsx.h>
11975 #include <winuser.h>
11976 
11977 #define stricmp _stricmp
11978 
11979 static HINSTANCE NEAR hModule;  /* Saved module handle for resources */
11980 
11981 #define MAXPATHLEN      (255+1)           /* Max path length */
11982 #define MAXKEYLEN       (15+1)            /* Max keyword length */
11983 #define MAXDESC         (255+1)           /* Max description length */
11984 #define MAXDSNAME       (32+1)            /* Max data source name length */
11985 #define MAXTONAME       (32+1)            /* Max timeout length */
11986 #define MAXDBNAME       (255+1)
11987 
11988 /* Attribute key indexes into an array of Attr structs, see below */
11989 
11990 #define KEY_DSN                 0
11991 #define KEY_DESC                1
11992 #define KEY_DBNAME              2
11993 #define KEY_BUSY                3
11994 #define KEY_DRIVER              4
11995 #define KEY_NOWCHAR             5
11996 #define KEY_STEPAPI             6
11997 #define NUMOFKEYS               7
11998 
11999 typedef struct {
12000     BOOL supplied;
12001     char attr[MAXPATHLEN];
12002 } ATTR;
12003 
12004 typedef struct {
12005     SQLHWND parent;
12006     LPCSTR  driver;
12007     ATTR    attr[NUMOFKEYS];
12008     char    DSN[MAXDSNAME];
12009     BOOL    newDSN;
12010     BOOL    defDSN;
12011 } SETUPDLG;
12012 
12013 static struct {
12014     char *key;
12015     int ikey;
12016 } attrLookup[] = {
12017     { "DSN", KEY_DSN },
12018     { "DESC", KEY_DESC },
12019     { "Description", KEY_DESC},
12020     { "Database", KEY_DBNAME },
12021     { "Timeout", KEY_BUSY },
12022     { "Driver", KEY_DRIVER },
12023     { "NoWCHAR", KEY_NOWCHAR },
12024     { "StepAPI", KEY_STEPAPI },
12025     { NULL, 0 }
12026 };
12027 
12034 static void
12035 ParseAttributes(LPCSTR attribs, SETUPDLG *setupdlg)
12036 {
12037     char *str = (char *) attribs, *start, key[MAXKEYLEN];
12038     int elem, nkey;
12039 
12040     while (*str) {
12041         start = str;
12042         if ((str = strchr(str, '=')) == NULL) {
12043             return;
12044         }
12045         elem = -1;
12046         nkey = str - start;
12047         if (nkey < sizeof (key)) {
12048             int i;
12049 
12050             memcpy(key, start, nkey);
12051             key[nkey] = '\0';
12052             for (i = 0; attrLookup[i].key; i++) {
12053                 if (stricmp(attrLookup[i].key, key) == 0) {
12054                     elem = attrLookup[i].ikey;
12055                     break;
12056                 }
12057             }
12058         }
12059         start = ++str;
12060         while (*str && *str != ';') {
12061             ++str;
12062         }
12063         if (elem >= 0) {
12064             int end = min(str - start, sizeof (setupdlg->attr[elem].attr) - 1);
12065 
12066             setupdlg->attr[elem].supplied = TRUE;
12067             memcpy(setupdlg->attr[elem].attr, start, end);
12068             setupdlg->attr[elem].attr[end] = '\0';
12069         }
12070         ++str;
12071     }
12072 }
12073 
12081 static BOOL
12082 SetDSNAttributes(HWND parent, SETUPDLG *setupdlg)
12083 {
12084     char *dsn = setupdlg->attr[KEY_DSN].attr;
12085 
12086     if (setupdlg->newDSN && strlen(dsn) == 0) {
12087         return FALSE;
12088     }
12089     if (!SQLWriteDSNToIni(dsn, setupdlg->driver)) {
12090         if (parent) {
12091             char buf[MAXPATHLEN], msg[MAXPATHLEN];
12092 
12093             LoadString(hModule, IDS_BADDSN, buf, sizeof (buf));
12094             wsprintf(msg, buf, dsn);
12095             LoadString(hModule, IDS_MSGTITLE, buf, sizeof (buf));
12096             MessageBox(parent, msg, buf,
12097                        MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
12098                        MB_SETFOREGROUND);
12099         }
12100         return FALSE;
12101     }
12102     if (parent || setupdlg->attr[KEY_DESC].supplied) {
12103         SQLWritePrivateProfileString(dsn, "Description",
12104                                      setupdlg->attr[KEY_DESC].attr,
12105                                      ODBC_INI);
12106     }
12107     if (parent || setupdlg->attr[KEY_DBNAME].supplied) {
12108         SQLWritePrivateProfileString(dsn, "Database",
12109                                      setupdlg->attr[KEY_DBNAME].attr,
12110                                      ODBC_INI);
12111     }
12112     if (parent || setupdlg->attr[KEY_BUSY].supplied) {
12113         SQLWritePrivateProfileString(dsn, "Timeout",
12114                                      setupdlg->attr[KEY_BUSY].attr,
12115                                      ODBC_INI);
12116     }
12117     if (parent || setupdlg->attr[KEY_NOWCHAR].supplied) {
12118         SQLWritePrivateProfileString(dsn, "NoWCHAR",
12119                                      setupdlg->attr[KEY_NOWCHAR].attr,
12120                                      ODBC_INI);
12121     }
12122     if (parent || setupdlg->attr[KEY_STEPAPI].supplied) {
12123         SQLWritePrivateProfileString(dsn, "StepAPI",
12124                                      setupdlg->attr[KEY_STEPAPI].attr,
12125                                      ODBC_INI);
12126     }
12127     if (setupdlg->attr[KEY_DSN].supplied &&
12128         stricmp(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr)) {
12129         SQLRemoveDSNFromIni(setupdlg->DSN);
12130     }
12131     return TRUE;
12132 }
12133 
12139 static void
12140 GetAttributes(SETUPDLG *setupdlg)
12141 {
12142     char *dsn = setupdlg->attr[KEY_DSN].attr;
12143 
12144     if (!setupdlg->attr[KEY_DESC].supplied) {
12145         SQLGetPrivateProfileString(dsn, "Description", "",
12146                                    setupdlg->attr[KEY_DESC].attr,
12147                                    sizeof (setupdlg->attr[KEY_DESC].attr),
12148                                    ODBC_INI);
12149     }
12150     if (!setupdlg->attr[KEY_DBNAME].supplied) {
12151         SQLGetPrivateProfileString(dsn, "Database", "",
12152                                    setupdlg->attr[KEY_DBNAME].attr,
12153                                    sizeof (setupdlg->attr[KEY_DBNAME].attr),
12154                                    ODBC_INI);
12155     }
12156     if (!setupdlg->attr[KEY_BUSY].supplied) {
12157         SQLGetPrivateProfileString(dsn, "Timeout", "1000",
12158                                    setupdlg->attr[KEY_BUSY].attr,
12159                                    sizeof (setupdlg->attr[KEY_BUSY].attr),
12160                                    ODBC_INI);
12161     }
12162     if (!setupdlg->attr[KEY_NOWCHAR].supplied) {
12163         SQLGetPrivateProfileString(dsn, "NoWCHAR", "",
12164                                    setupdlg->attr[KEY_NOWCHAR].attr,
12165                                    sizeof (setupdlg->attr[KEY_NOWCHAR].attr),
12166                                    ODBC_INI);
12167     }
12168     if (!setupdlg->attr[KEY_STEPAPI].supplied) {
12169         SQLGetPrivateProfileString(dsn, "StepAPI", "0",
12170                                    setupdlg->attr[KEY_STEPAPI].attr,
12171                                    sizeof (setupdlg->attr[KEY_STEPAPI].attr),
12172                                    ODBC_INI);
12173     }
12174 }
12175 
12181 static void
12182 GetDBFile(HWND hdlg)
12183 {
12184     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
12185     OPENFILENAME ofn;
12186 
12187     memset(&ofn, 0, sizeof (ofn));
12188     ofn.lStructSize = sizeof (ofn);
12189     ofn.hwndOwner = hdlg;
12190     ofn.hInstance = (HINSTANCE) GetWindowLong(hdlg, GWL_HINSTANCE);
12191     ofn.lpstrFile = (LPTSTR) setupdlg->attr[KEY_DBNAME].attr;
12192     ofn.nMaxFile = MAXPATHLEN;
12193     ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
12194                 OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_FILEMUSTEXIST;
12195     if (GetOpenFileName(&ofn)) {
12196         SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
12197         setupdlg->attr[KEY_DBNAME].supplied = TRUE;
12198     }
12199 }
12200 
12210 static BOOL CALLBACK
12211 ConfigDlgProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
12212 {
12213     SETUPDLG *setupdlg = NULL;
12214 
12215     switch (wmsg) {
12216     case WM_INITDIALOG:
12217         SetWindowLong(hdlg, DWL_USER, lparam);
12218         setupdlg = (SETUPDLG *) lparam;
12219         GetAttributes(setupdlg);
12220         SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
12221         SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
12222         SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
12223         SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
12224         CheckDlgButton(hdlg, IDC_NOWCHAR,
12225                        getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
12226                        BST_CHECKED : BST_UNCHECKED);
12227         CheckDlgButton(hdlg, IDC_STEPAPI,
12228                        getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
12229                        BST_CHECKED : BST_UNCHECKED);
12230         if (setupdlg->defDSN) {
12231             EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
12232             EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
12233         } else {
12234             SendDlgItemMessage(hdlg, IDC_DSNAME,
12235                                EM_LIMITTEXT, (WPARAM) (MAXDSNAME - 1), 0L);
12236             SendDlgItemMessage(hdlg, IDC_DESC,
12237                                EM_LIMITTEXT, (WPARAM) (MAXDESC - 1), 0L);
12238             SendDlgItemMessage(hdlg, IDC_DBNAME,
12239                                EM_LIMITTEXT, (WPARAM) (MAXDBNAME - 1), 0L);
12240             SendDlgItemMessage(hdlg, IDC_TONAME,
12241                                EM_LIMITTEXT, (WPARAM) (MAXTONAME - 1), 0L);
12242         }
12243         return TRUE;
12244     case WM_COMMAND:
12245         switch (GET_WM_COMMAND_ID(wparam, lparam)) {
12246         case IDC_DSNAME:
12247             if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) {
12248                 char item[MAXDSNAME];
12249 
12250                 EnableWindow(GetDlgItem(hdlg, IDOK),
12251                              GetDlgItemText(hdlg, IDC_DSNAME,
12252                                             item, sizeof (item)));
12253                 return TRUE;
12254             }
12255             break;
12256         case IDC_BROWSE:
12257             GetDBFile(hdlg);
12258             break;
12259         case IDOK:
12260             setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
12261             if (!setupdlg->defDSN) {
12262                 GetDlgItemText(hdlg, IDC_DSNAME,
12263                                setupdlg->attr[KEY_DSN].attr,
12264                                sizeof (setupdlg->attr[KEY_DSN].attr));
12265             }
12266             GetDlgItemText(hdlg, IDC_DESC,
12267                            setupdlg->attr[KEY_DESC].attr,
12268                            sizeof (setupdlg->attr[KEY_DESC].attr));
12269             GetDlgItemText(hdlg, IDC_DBNAME,
12270                            setupdlg->attr[KEY_DBNAME].attr,
12271                            sizeof (setupdlg->attr[KEY_DBNAME].attr));
12272             GetDlgItemText(hdlg, IDC_TONAME,
12273                            setupdlg->attr[KEY_BUSY].attr,
12274                            sizeof (setupdlg->attr[KEY_BUSY].attr));
12275             strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
12276                    IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED ?
12277                    "1" : "0");
12278             strcpy(setupdlg->attr[KEY_STEPAPI].attr,
12279                    IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED ?
12280                    "1" : "0");
12281             SetDSNAttributes(hdlg, setupdlg);
12282             /* FALL THROUGH */
12283         case IDCANCEL:
12284             EndDialog(hdlg, wparam);
12285             return TRUE;
12286         }
12287         break;
12288     }
12289     return FALSE;
12290 }
12291 
12301 BOOL INSTAPI
12302 ConfigDSN(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attribs)
12303 {
12304     BOOL success;
12305     SETUPDLG *setupdlg;
12306 
12307     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
12308     if (setupdlg == NULL) {
12309         return FALSE;
12310     }
12311     memset(setupdlg, 0, sizeof (SETUPDLG));
12312     if (attribs) {
12313         ParseAttributes(attribs, setupdlg);
12314     }
12315     if (setupdlg->attr[KEY_DSN].supplied) {
12316         strcpy(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr);
12317     } else {
12318         setupdlg->DSN[0] = '\0';
12319     }
12320     if (request == ODBC_REMOVE_DSN) {
12321         if (!setupdlg->attr[KEY_DSN].supplied) {
12322             success = FALSE;
12323         } else {
12324             success = SQLRemoveDSNFromIni(setupdlg->attr[KEY_DSN].attr);
12325         }
12326     } else {
12327         setupdlg->parent = hwnd;
12328         setupdlg->driver = driver;
12329         setupdlg->newDSN = request == ODBC_ADD_DSN;
12330         setupdlg->defDSN = stricmp(setupdlg->attr[KEY_DSN].attr,
12331                                    "Default") == 0;
12332         if (hwnd) {
12333             success = DialogBoxParam(hModule, MAKEINTRESOURCE(CONFIGDSN),
12334                                      hwnd, (DLGPROC) ConfigDlgProc,
12335                                      (LONG) setupdlg) == IDOK;
12336         } else if (setupdlg->attr[KEY_DSN].supplied) {
12337             success = SetDSNAttributes(hwnd, setupdlg);
12338         } else {
12339             success = FALSE;
12340         }
12341     }
12342     xfree(setupdlg);
12343     return success;
12344 }
12345 
12355 static BOOL CALLBACK
12356 DriverConnectProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
12357 {
12358     SETUPDLG *setupdlg;
12359 
12360     switch (wmsg) {
12361     case WM_INITDIALOG:
12362         SetWindowLong(hdlg, DWL_USER, lparam);
12363         setupdlg = (SETUPDLG *) lparam;
12364         SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
12365         SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
12366         SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
12367         SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
12368         SendDlgItemMessage(hdlg, IDC_DSNAME,
12369                            EM_LIMITTEXT, (WPARAM) (MAXDSNAME - 1), 0L);
12370         SendDlgItemMessage(hdlg, IDC_DESC,
12371                            EM_LIMITTEXT, (WPARAM) (MAXDESC - 1), 0L);
12372         SendDlgItemMessage(hdlg, IDC_DBNAME,
12373                            EM_LIMITTEXT, (WORD)(MAXDBNAME - 1), 0L);
12374         SendDlgItemMessage(hdlg, IDC_TONAME,
12375                            EM_LIMITTEXT, (WORD)(MAXTONAME - 1), 0L);
12376         CheckDlgButton(hdlg, IDC_NOWCHAR,
12377                        getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
12378                        BST_CHECKED : BST_UNCHECKED);
12379         CheckDlgButton(hdlg, IDC_STEPAPI,
12380                        getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
12381                        BST_CHECKED : BST_UNCHECKED);
12382         return TRUE;
12383     case WM_COMMAND:
12384         switch (GET_WM_COMMAND_ID(wparam, lparam)) {
12385         case IDC_BROWSE:
12386             GetDBFile(hdlg);
12387             break;
12388         case IDOK:
12389             setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
12390             GetDlgItemText(hdlg, IDC_DSNAME,
12391                            setupdlg->attr[KEY_DSN].attr,
12392                            sizeof (setupdlg->attr[KEY_DSN].attr));
12393             GetDlgItemText(hdlg, IDC_DBNAME,
12394                            setupdlg->attr[KEY_DBNAME].attr,
12395                            sizeof (setupdlg->attr[KEY_DBNAME].attr));
12396             GetDlgItemText(hdlg, IDC_TONAME,
12397                            setupdlg->attr[KEY_BUSY].attr,
12398                            sizeof (setupdlg->attr[KEY_BUSY].attr));
12399             strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
12400                    IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED ?
12401                    "1" : "0");
12402             strcpy(setupdlg->attr[KEY_STEPAPI].attr,
12403                    IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED ?
12404                    "1" : "0");
12405             /* FALL THROUGH */
12406         case IDCANCEL:
12407             EndDialog(hdlg, GET_WM_COMMAND_ID(wparam, lparam) == IDOK);
12408             return TRUE;
12409         }
12410     }
12411     return FALSE;
12412 }
12413 
12427 static SQLRETURN
12428 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
12429                  SQLCHAR *connIn, SQLSMALLINT connInLen,
12430                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
12431                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
12432 {
12433     BOOL maybeprompt, prompt = FALSE;
12434     DBC *d;
12435     SETUPDLG *setupdlg;
12436     short ret;
12437     SQLRETURN rc;
12438 
12439     if (dbc == SQL_NULL_HDBC) {
12440         return SQL_INVALID_HANDLE;
12441     }
12442     d = (DBC *) dbc;
12443     if (d->sqlite) {
12444         setstatd(d, -1, "connection already established", "08002");
12445         return SQL_ERROR;
12446     }
12447     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
12448     if (setupdlg == NULL) {
12449         return SQL_ERROR;
12450     }
12451     memset(setupdlg, 0, sizeof (SETUPDLG));
12452     maybeprompt = drvcompl == SQL_DRIVER_COMPLETE ||
12453         drvcompl == SQL_DRIVER_COMPLETE_REQUIRED;
12454     if (connIn == NULL || !connInLen ||
12455         (connInLen == SQL_NTS && !connIn[0])) {
12456         prompt = TRUE;
12457     } else {
12458         ParseAttributes(connIn, setupdlg);
12459         if (!setupdlg->attr[KEY_DSN].attr[0] &&
12460             drvcompl == SQL_DRIVER_COMPLETE_REQUIRED) {
12461             strcpy(setupdlg->attr[KEY_DSN].attr, "DEFAULT");
12462         }
12463         GetAttributes(setupdlg);
12464         if (drvcompl == SQL_DRIVER_PROMPT ||
12465             (maybeprompt &&
12466              !setupdlg->attr[KEY_DSN].attr[0] ||
12467              !setupdlg->attr[KEY_DBNAME].attr[0])) {
12468             prompt = TRUE;
12469         }
12470     }
12471 retry:
12472     if (prompt) {
12473         ret = DialogBoxParam(hModule, MAKEINTRESOURCE(DRIVERCONNECT),
12474                              hwnd, (DLGPROC) DriverConnectProc,
12475                              (LONG) setupdlg);
12476         if (!ret || ret == -1) {
12477             xfree(setupdlg);
12478             return SQL_NO_DATA_FOUND;
12479         }
12480     }
12481     if (connOut || connOutLen) {
12482         char buf[1024];
12483         int len, count;
12484         char dsn_0 = setupdlg->attr[KEY_DSN].attr[0];
12485         char drv_0 = setupdlg->attr[KEY_DRIVER].attr[0];
12486 
12487         buf[0] = '\0';
12488         count = snprintf(buf, sizeof (buf),
12489                          "%s%s%s%s%s%sDatabase=%s;StepAPI=%s;"
12490                          "Timeout=%s;NoWCHAR=%s",
12491                          dsn_0 ? "DSN=" : "",
12492                          dsn_0 ? setupdlg->attr[KEY_DSN].attr : "",
12493                          dsn_0 ? ";" : "",
12494                          drv_0 ? "Driver=" : "",
12495                          drv_0 ? setupdlg->attr[KEY_DRIVER].attr : "",
12496                          drv_0 ? ";" : "",
12497                          setupdlg->attr[KEY_DBNAME].attr,
12498                          setupdlg->attr[KEY_STEPAPI].attr,
12499                          setupdlg->attr[KEY_BUSY].attr,
12500                          setupdlg->attr[KEY_NOWCHAR].attr);
12501         if (count < 0) {
12502             buf[sizeof (buf) - 1] = '\0';
12503         }
12504         len = min(connOutMax - 1, strlen(buf));
12505         if (connOut) {
12506             strncpy(connOut, buf, len);
12507             connOut[len] = '\0';
12508         }
12509         if (connOutLen) {
12510             *connOutLen = len;
12511         }
12512     }
12513     d->nowchar = getbool(setupdlg->attr[KEY_NOWCHAR].attr);
12514     rc = dbopen(d, setupdlg->attr[KEY_DBNAME].attr,
12515                 setupdlg->attr[KEY_DSN].attr,
12516                 setupdlg->attr[KEY_STEPAPI].attr,
12517                 setupdlg->attr[KEY_BUSY].attr);
12518     if (rc != SQL_SUCCESS) {
12519         if (maybeprompt && !prompt) {
12520             prompt = TRUE;
12521             goto retry;
12522         }
12523         xfree(setupdlg);
12524         return rc;
12525     }
12526     xfree(setupdlg);
12527     return SQL_SUCCESS;
12528 }
12529 
12530 #endif /* WITHOUT_DRIVERMGR */
12531 #endif /* _WIN32 */
12532 
12533 #ifndef WITHOUT_DRIVERMGR
12534 
12535 #ifndef SQLITE_UTF8
12536 
12549 SQLRETURN SQL_API
12550 SQLDriverConnect(SQLHDBC dbc, SQLHWND hwnd,
12551                  SQLCHAR *connIn, SQLSMALLINT connInLen,
12552                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
12553                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
12554 {
12555     return drvdriverconnect(dbc, hwnd, connIn, connInLen,
12556                             connOut, connOutMax, connOutLen, drvcompl);
12557 }
12558 #endif
12559 
12560 #ifdef SQLITE_UTF8
12561 
12574 SQLRETURN SQL_API
12575 SQLDriverConnectW(SQLHDBC dbc, SQLHWND hwnd,
12576                   SQLWCHAR *connIn, SQLSMALLINT connInLen,
12577                   SQLWCHAR *connOut, SQLSMALLINT connOutMax,
12578                   SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
12579 {
12580     SQLRETURN ret;
12581     char *ci = NULL;
12582     SQLSMALLINT len;
12583 
12584     if (connIn) {
12585         ci = uc_to_utf_c(connIn, connInLen);
12586         if (!ci) {
12587             DBC *d = (DBC *) dbc;
12588 
12589             setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12590             return SQL_ERROR;
12591         }
12592     }
12593     ret = drvdriverconnect(dbc, hwnd, ci, SQL_NTS,
12594                            (char *) connOut, connOutMax, &len, drvcompl);
12595     uc_free(ci);
12596     if (ret == SQL_SUCCESS) {
12597         SQLWCHAR *co = NULL;
12598 
12599         if (connOut) {
12600             if (len > 0) {
12601                 co = uc_from_utf((char *) connOut, len);
12602                 if (co) {
12603                     uc_strncpy(connOut, co, connOutMax);
12604                     len = min(connOutMax, uc_strlen(co));
12605                     uc_free(co);
12606                 } else {
12607                     len = 0;
12608                 }
12609             }
12610             if (len <= 0) {
12611                 len = 0;
12612                 connOut[0] = 0;
12613             }
12614         } else {
12615             len = 0;
12616         }
12617         if (connOutLen) {
12618             *connOutLen = len;
12619         }
12620     }
12621     return ret;
12622 }
12623 #endif
12624 
12625 #endif /* WITHOUT_DRIVERMGR */
12626 
12627 #ifdef _WIN32
12628 
12637 BOOL APIENTRY
12638 LibMain(HANDLE hinst, DWORD reason, LPVOID reserved)
12639 {
12640     static int initialized = 0;
12641 
12642     switch (reason) {
12643     case DLL_PROCESS_ATTACH:
12644         if (!initialized++) {
12645             hModule = hinst;
12646         }
12647         break;
12648     case DLL_THREAD_ATTACH:
12649         break;
12650     case DLL_PROCESS_DETACH:
12651         --initialized;
12652         break;
12653     case DLL_THREAD_DETACH:
12654         break;
12655     default:
12656         break;
12657     }
12658     return TRUE;
12659 }
12660 
12669 int __stdcall
12670 DllMain(HANDLE hinst, DWORD reason, LPVOID reserved)
12671 {
12672     return LibMain(hinst, reason, reserved);
12673 }
12674 
12675 #endif /* _WIN32 */
12676 
12677 #if defined(HAVE_ODBCINSTEXT_H) && HAVE_ODBCINSTEXT_H
12678 
12679 /*
12680  * unixODBC property page for this driver,
12681  * may or may not work depending on unixODBC version.
12682  */
12683 
12684 #include <odbcinstext.h>
12685 
12686 int
12687 ODBCINSTGetProperties(HODBCINSTPROPERTY prop)
12688 {
12689     static const char *instYN[] = { "No", "Yes", NULL };
12690 
12691     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
12692     prop = prop->pNext;
12693     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
12694     prop->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
12695     strncpy(prop->szName, "Database", INI_MAX_PROPERTY_NAME);
12696     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
12697     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
12698     prop = prop->pNext;
12699     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
12700     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
12701     strncpy(prop->szName, "Timeout", INI_MAX_PROPERTY_NAME);
12702     strncpy(prop->szValue, "1000", INI_MAX_PROPERTY_VALUE);
12703     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
12704     prop = prop->pNext;
12705     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
12706     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
12707     prop->aPromptData = malloc (sizeof (instYN));
12708     memcpy(prop->aPromptData, instYN, sizeof (instYN));
12709     strncpy(prop->szName, "StepAPI", INI_MAX_PROPERTY_NAME);
12710     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
12711 #ifdef SQLITE_UTF8
12712     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
12713     prop = prop->pNext;
12714     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
12715     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
12716     prop->aPromptData = malloc (sizeof (instYN));
12717     memcpy(prop->aPromptData, instYN, sizeof (instYN));
12718     strncpy(prop->szName, "NoWCHAR", INI_MAX_PROPERTY_NAME);
12719     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
12720 #endif
12721     return 1;
12722 }
12723 
12724 #endif /* HAVE_ODBCINSTEXT_H */

Generated on 9 Feb 2005 by doxygen.
Contact: chw@ch-werner.de