sqlite3odbc.c

Go to the documentation of this file.
00001 
00014 #include "sqlite3odbc.h"
00015 
00016 #ifdef _WIN32
00017 #include "resource3.h"
00018 #define ODBC_INI "ODBC.INI"
00019 #else
00020 #define ODBC_INI ".odbc.ini"
00021 #endif
00022 
00023 #ifdef CANT_PASS_VALIST_AS_CHARPTR
00024 #define MAX_PARAMS_FOR_MPRINTF 32
00025 #endif
00026 
00027 #ifndef DRIVER_VER_INFO
00028 #define DRIVER_VER_INFO "0.0"
00029 #endif
00030 
00031 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
00032 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
00033 #endif
00034 
00035 #undef min
00036 #define min(a, b) ((a) < (b) ? (a) : (b))
00037 #undef max
00038 #define max(a, b) ((a) < (b) ? (b) : (a))
00039 
00040 #define array_size(x) (sizeof (x) / sizeof (x[0]))
00041 
00042 #define stringify1(s) #s
00043 #define stringify(s) stringify1(s)
00044 
00045 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
00046 
00047 /* Column types for static string column descriptions (SQLTables etc.) */
00048 
00049 #define SCOL_VARCHAR SQL_VARCHAR
00050 #define SCOL_CHAR SQL_CHAR
00051 
00052 #define ENV_MAGIC  0x53544145
00053 #define DBC_MAGIC  0x53544144
00054 #define DEAD_MAGIC 0xdeadbeef
00055 
00056 static const char *xdigits = "0123456789ABCDEFabcdef";
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_(const 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 
00296 static SQLRETURN substparam(STMT *s, char **sqlp, int pnum, char **outp);
00297 
00303 static void freedyncols(STMT *s);
00304 
00312 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
00313 
00320 static void dbtraceapi(DBC *d, char *fn, const char *sql);
00321 
00322 #if (MEMORY_DEBUG < 1)
00323 
00329 static char *
00330 strdup_(const char *str)
00331 {
00332     char *p = NULL;
00333 
00334     if (str) {
00335         p = xmalloc(strlen(str) + 1);
00336         if (p) {
00337             strcpy(p, str);
00338         }
00339     }
00340     return p;
00341 }
00342 #endif
00343 
00344 #ifdef USE_DLOPEN_FOR_GPPS
00345 
00346 #include <dlfcn.h>
00347 
00348 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
00349 
00350 /*
00351  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
00352  * dlopen(), in theory this makes the driver independent from the
00353  * driver manager, i.e. the same driver binary can run with iODBC
00354  * and unixODBC.
00355  */
00356 
00357 static void
00358 drvgetgpps(DBC *d)
00359 {
00360     void *lib;
00361     int (*gpps)();
00362 
00363     lib = dlopen("libodbcinst.so", RTLD_LAZY);
00364     if (!lib) {
00365         lib = dlopen("libiodbcinst.so", RTLD_LAZY);
00366     }
00367     if (lib) {
00368         gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
00369         if (!gpps) {
00370             dlclose(lib);
00371             return;
00372         }
00373         d->instlib = lib;
00374         d->gpps = gpps;
00375     }
00376 }
00377 
00378 static void
00379 drvrelgpps(DBC *d)
00380 {
00381     if (d->instlib) {
00382         dlclose(d->instlib);
00383         d->instlib = 0;
00384     }
00385 }
00386 
00387 static int
00388 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
00389         int bufsiz, char *fname)
00390 {
00391     if (d->gpps) {
00392         return d->gpps(sect, ent, def, buf, bufsiz, fname);
00393     }
00394     strncpy(buf, def, bufsiz);
00395     buf[bufsiz - 1] = '\0';
00396     return 1;
00397 }
00398 #else
00399 #define drvgetgpps(d)
00400 #define drvrelgpps(d)
00401 #endif
00402 
00412 static void freerows(char **rowp);
00413 
00414 /*
00415  * Internal structure for managing driver's
00416  * sqlite3_get_table() implementation.
00417  */
00418 
00419 typedef struct tblres {
00420     char **resarr;
00421     char *errmsg;
00422     sqlite3_stmt *stmt;
00423     int nres;
00424     int nalloc;
00425     int nrow;
00426     int ncol;
00427     int ndata;
00428     int rc;
00429 } TBLRES;
00430 
00431 /*
00432  * Driver's version of sqlite3_get_table() and friends which are
00433  * capable of dealing with blobs.
00434  */
00435 
00436 static int
00437 drvgettable_row(TBLRES *t, int ncol, int rc)
00438 {
00439     int need;
00440     int i;
00441     char *p;
00442 
00443     if (t->nrow == 0 && rc == SQLITE_ROW) {
00444         need = ncol * 2;
00445     } else {
00446         need = ncol;
00447     }
00448     if (t->ndata + need >= t->nalloc) {
00449         char **resnew;
00450         int nalloc = t->nalloc * 2 + need + 1;
00451 
00452         nalloc = t->nalloc * 2 + need + 1;
00453         resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
00454         if (!resnew) {
00455 nomem:
00456             t->rc = SQLITE_NOMEM;
00457             return 1;
00458         }
00459         t->nalloc = nalloc;
00460         t->resarr = resnew;
00461     }
00462     /* column names when first row */
00463     if (t->nrow == 0) {
00464         t->ncol = ncol;
00465         for (i = 0; i < ncol; i++) {
00466             p = (char *) sqlite3_column_name(t->stmt, i);
00467             if (p) {
00468                 char *q = xmalloc(strlen(p) + 1);
00469 
00470                 if (!q) {
00471                     goto nomem;
00472                 }
00473                 strcpy(q, p);
00474                 p = q;
00475             }
00476             t->resarr[t->ndata++] = p;
00477         }
00478     } else if (t->ncol != ncol) {
00479         t->errmsg = sqlite3_mprintf("drvgettable() called with two or"
00480                                     " more incompatible queries");
00481         t->rc = SQLITE_ERROR;
00482         return 1;
00483     }
00484     /* copy row data */
00485     if (rc == SQLITE_ROW) {
00486         for (i = 0; i < ncol; i++) {
00487             int coltype = sqlite3_column_type(t->stmt, i);
00488 
00489             p = NULL;
00490             if (coltype == SQLITE_BLOB) {
00491                 int k, nbytes = sqlite3_column_bytes(t->stmt, i);
00492                 char *qp;
00493                 unsigned const char *bp;
00494 
00495                 bp = sqlite3_column_blob(t->stmt, i);
00496                 qp = xmalloc(nbytes * 2 + 4);
00497                 if (!qp) {
00498                     goto nomem;
00499                 }
00500                 p = qp;
00501                 *qp++ = 'X';
00502                 *qp++ = '\'';
00503                 for (k = 0; k < nbytes; k++) {
00504                     *qp++ = xdigits[(bp[k] >> 4)];
00505                     *qp++ = xdigits[(bp[k] & 0xF)];
00506                 }
00507                 *qp++ = '\'';
00508                 *qp = '\0';
00509             } else if (coltype != SQLITE_NULL) {
00510                 p = xstrdup(sqlite3_column_text(t->stmt, i));
00511                 if (!p) {
00512                     goto nomem;
00513                 }
00514             }
00515             t->resarr[t->ndata++] = p;
00516         }
00517         t->nrow++;
00518     }
00519     return 0;
00520 }
00521 
00522 static int
00523 drvgettable(DBC *d, const char *sql, char ***resp, int *nrowp,
00524             int *ncolp, char **errp)
00525 {
00526     int rc = SQLITE_OK;
00527     TBLRES tres;
00528     const char *sqlleft;
00529     int nretry = 0;
00530 
00531     if (!resp) {
00532         return SQLITE_ERROR;
00533     }
00534     *resp = NULL;
00535     if (nrowp) {
00536         *nrowp = 0;
00537     }
00538     if (ncolp) {
00539         *ncolp = 0;
00540     }
00541     if (!sql) {
00542         return SQLITE_OK;
00543     }
00544     tres.errmsg = NULL;
00545     tres.nres = 0;
00546     tres.nrow = 0;
00547     tres.ncol = 0;
00548     tres.ndata = 1;
00549     tres.nalloc = 20;
00550     tres.rc = SQLITE_OK;
00551     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
00552     tres.stmt = NULL;
00553     if (!tres.resarr) {
00554         return SQLITE_NOMEM;
00555     }
00556     tres.resarr[0] = 0;
00557     while (*sql && (rc == SQLITE_OK ||
00558                       (rc == SQLITE_SCHEMA && (++nretry) < 2))) {
00559         int ncol;
00560 
00561         tres.stmt = NULL;
00562         dbtraceapi(d, "sqlite3_prepare", sql);
00563         rc = sqlite3_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
00564         if (rc != SQLITE_OK) {
00565             if (tres.stmt) {
00566                 dbtraceapi(d, "sqlite3_finalize", 0);
00567                 sqlite3_finalize(tres.stmt);
00568                 tres.stmt = NULL;
00569             }
00570             continue;
00571         }
00572         if (!tres.stmt) {
00573             /* this happens for a comment or white-space */
00574             sql = sqlleft;
00575             continue;
00576         }
00577         ncol = sqlite3_column_count(tres.stmt);
00578         while (1) {
00579             rc = sqlite3_step(tres.stmt);
00580             if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
00581                 if (drvgettable_row(&tres, ncol, rc)) {
00582                     rc = SQLITE_ABORT;
00583                     goto tbldone;
00584                 }
00585             }
00586             if (rc != SQLITE_ROW) {
00587                 dbtraceapi(d, "sqlite3_finalize", 0);
00588                 rc = sqlite3_finalize(tres.stmt);
00589                 tres.stmt = 0;
00590                 if (rc != SQLITE_SCHEMA) {
00591                     nretry = 0;
00592                     sql = sqlleft;
00593                     while (ISSPACE(*sql)) {
00594                         sql++;
00595                     }
00596                 }
00597                 break;
00598             }
00599         }
00600     }
00601 tbldone:
00602     if (tres.stmt) {
00603         dbtraceapi(d, "sqlite3_finalize", 0);
00604         sqlite3_finalize(tres.stmt);
00605     }
00606     if (rc != SQLITE_OK && rc == sqlite3_errcode(d->sqlite) && errp) {
00607         *errp = sqlite3_mprintf("%s", sqlite3_errmsg(d->sqlite));
00608     } else if (errp) {
00609         *errp = NULL;
00610     }
00611     if (tres.resarr) {
00612         tres.resarr[0] = (char *) (tres.ndata - 1);
00613     }
00614     if (rc == SQLITE_ABORT) {
00615         freerows(&tres.resarr[1]);
00616         if (tres.errmsg) {
00617             if (errp) {
00618                 if (*errp) {
00619                     sqlite3_free(*errp);
00620                 }
00621                 *errp = tres.errmsg;
00622             } else {
00623                 sqlite3_free(tres.errmsg);
00624             }
00625         }
00626         return tres.rc;
00627     }
00628     sqlite3_free(tres.errmsg);
00629     if (rc != SQLITE_OK) {
00630         freerows(&tres.resarr[1]);
00631         return rc;
00632     }
00633     *resp = &tres.resarr[1];
00634     if (ncolp) {
00635         *ncolp = tres.ncol;
00636     }
00637     if (nrowp) {
00638         *nrowp = tres.nrow;
00639     }
00640     return rc;
00641 }
00642 
00651 #if defined(__GNUC__) && (__GNUC__ >= 2)
00652 static void setstatd(DBC *, int, char *, char *, ...)
00653     __attribute__((format (printf, 3, 5)));
00654 #endif
00655 
00656 static void
00657 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
00658 {
00659     va_list ap;
00660 
00661     if (!d) {
00662         return;
00663     }
00664     d->naterr = naterr;
00665     d->logmsg[0] = '\0';
00666     if (msg) {
00667         int count;
00668 
00669         va_start(ap, st);
00670         count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
00671         va_end(ap);
00672         if (count < 0) {
00673             d->logmsg[sizeof (d->logmsg) - 1] = '\0';
00674         }
00675     }
00676     if (!st) {
00677         st = "?????";
00678     }
00679     strncpy(d->sqlstate, st, 5);
00680     d->sqlstate[5] = '\0';
00681 }
00682 
00691 #if defined(__GNUC__) && (__GNUC__ >= 2)
00692 static void setstat(STMT *, int, char *, char *, ...)
00693     __attribute__((format (printf, 3, 5)));
00694 #endif
00695 
00696 static void
00697 setstat(STMT *s, int naterr, char *msg, char *st, ...)
00698 {
00699     va_list ap;
00700 
00701     if (!s) {
00702         return;
00703     }
00704     s->naterr = naterr;
00705     s->logmsg[0] = '\0';
00706     if (msg) {
00707         int count;
00708 
00709         va_start(ap, st);
00710         count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
00711         va_end(ap);
00712         if (count < 0) {
00713             s->logmsg[sizeof (s->logmsg) - 1] = '\0';
00714         }
00715     }
00716     if (!st) {
00717         st = "?????";
00718     }
00719     strncpy(s->sqlstate, st, 5);
00720     s->sqlstate[5] = '\0';
00721 }
00722 
00729 static SQLRETURN
00730 drvunimpldbc(HDBC dbc)
00731 {
00732     DBC *d;
00733 
00734     if (dbc == SQL_NULL_HDBC) {
00735         return SQL_INVALID_HANDLE;
00736     }
00737     d = (DBC *) dbc;
00738     setstatd(d, -1, "not supported", "IM001");
00739     return SQL_ERROR;
00740 }
00741 
00748 static SQLRETURN
00749 drvunimplstmt(HSTMT stmt)
00750 {
00751     STMT *s;
00752 
00753     if (stmt == SQL_NULL_HSTMT) {
00754         return SQL_INVALID_HANDLE;
00755     }
00756     s = (STMT *) stmt;
00757     setstat(s, -1, "not supported", "IM001");
00758     return SQL_ERROR;
00759 }
00760 
00766 static void
00767 freep(void *x)
00768 {
00769     if (x && ((char **) x)[0]) {
00770         xfree(((char **) x)[0]);
00771         ((char **) x)[0] = NULL;
00772     }
00773 }
00774 
00781 static SQLRETURN
00782 nomem(STMT *s)
00783 {
00784     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
00785     return SQL_ERROR;
00786 }
00787 
00794 static SQLRETURN
00795 noconn(STMT *s)
00796 {
00797     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
00798     return SQL_ERROR;
00799 }
00800 
00808 static double
00809 ln_strtod(const char *data, char **endp)
00810 {
00811 #if defined(HAVE_LOCALECONV) || defined(_WIN32)
00812     struct lconv *lc;
00813     char buf[128], *p, *end;
00814     double value;
00815 
00816     lc = localeconv();
00817     if (lc && lc->decimal_point && lc->decimal_point[0] &&
00818         lc->decimal_point[0] != '.') {
00819         strncpy(buf, data, sizeof (buf) - 1);
00820         buf[sizeof (buf) - 1] = '\0';
00821         p = strchr(buf, '.');
00822         if (p) {
00823             *p = lc->decimal_point[0];
00824         }
00825         p = buf;
00826     } else {
00827         p = (char *) data;
00828     }
00829     value = strtod(p, &end);
00830     end = (char *) data + (end - p);
00831     if (endp) {
00832         *endp = end;
00833     }
00834     return value;
00835 #else
00836     return strtod(data, endp);
00837 #endif
00838 }
00839 
00847 static int
00848 busy_handler(void *udata, int count)
00849 {
00850     DBC *d = (DBC *) udata;
00851     long t1;
00852     int ret = 0;
00853 #ifndef _WIN32
00854     struct timeval tv;
00855 #endif
00856 
00857     if (d->timeout <= 0) {
00858         return ret;
00859     }
00860     if (count <= 1) {
00861 #ifdef _WIN32
00862         d->t0 = GetTickCount();
00863 #else
00864         gettimeofday(&tv, NULL);
00865         d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00866 #endif
00867     }
00868 #ifdef _WIN32
00869     t1 = GetTickCount();
00870 #else
00871     gettimeofday(&tv, NULL);
00872     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00873 #endif
00874     if (t1 - d->t0 > d->timeout) {
00875         goto done;
00876     }
00877 #ifdef _WIN32
00878     Sleep(10);
00879 #else
00880 #ifdef HAVE_USLEEP
00881     usleep(10000);
00882 #else
00883     tv.tv_sec = 0;
00884     tv.tv_usec = 10000;
00885     select(0, NULL, NULL, NULL, &tv);
00886 #endif
00887 #endif
00888     ret = 1;
00889 done:
00890     return ret;
00891 }
00892 
00903 static int
00904 setsqliteopts(sqlite3 *x, DBC *d)
00905 {
00906     int count = 0, step = 0, rc = SQLITE_ERROR;
00907 
00908     while (step < 2) {
00909         if (step < 1) {
00910             rc = sqlite3_exec(x, "PRAGMA full_column_names = on;",
00911                               NULL, NULL, NULL);
00912         } else if (step < 2) {
00913             rc = sqlite3_exec(x, "PRAGMA empty_result_callbacks = on;",
00914                               NULL, NULL, NULL);
00915         }
00916         if (rc != SQLITE_OK) {
00917             if (rc != SQLITE_BUSY ||
00918                 !busy_handler((void *) d, ++count)) {
00919                 return rc;
00920             }
00921             continue;
00922         }
00923         count = 0;
00924         ++step;
00925     }
00926     sqlite3_busy_handler(x, busy_handler, (void *) d);
00927     return SQLITE_OK;
00928 }
00929 
00930 /* see doc on top */
00931 
00932 static void
00933 freerows(char **rowp)
00934 {
00935     int size, i;
00936 
00937     if (!rowp) {
00938         return;
00939     }
00940     --rowp;
00941     size = (int) rowp[0];
00942     for (i = 1; i <= size; i++) {
00943         freep(&rowp[i]);
00944     }
00945     freep(&rowp);
00946 }
00947 
00956 static int
00957 mapsqltype(const char *typename, int *nosign, int ov3)
00958 {
00959     char *p, *q;
00960     int testsign = 0, result;
00961 
00962     result = SQL_VARCHAR;
00963     if (!typename) {
00964         return result;
00965     }
00966     q = p = xmalloc(strlen(typename) + 1);
00967     if (!p) {
00968         return result;
00969     }
00970     strcpy(p, typename);
00971     while (*q) {
00972         *q = TOLOWER(*q);
00973         ++q;
00974     }
00975     if (strncmp(p, "inter", 5) == 0) {
00976     } else if (strncmp(p, "int", 3) == 0 ||
00977         strncmp(p, "mediumint", 9) == 0) {
00978         testsign = 1;
00979         result = SQL_INTEGER;
00980     } else if (strncmp(p, "numeric", 7) == 0) {
00981         result = SQL_DOUBLE;
00982     } else if (strncmp(p, "tinyint", 7) == 0) {
00983         testsign = 1;
00984         result = SQL_TINYINT;
00985     } else if (strncmp(p, "smallint", 8) == 0) {
00986         testsign = 1;
00987         result = SQL_SMALLINT;
00988     } else if (strncmp(p, "float", 5) == 0) {
00989         result = SQL_DOUBLE;
00990     } else if (strncmp(p, "double", 6) == 0 ||
00991         strncmp(p, "real", 4) == 0) {
00992         result = SQL_DOUBLE;
00993     } else if (strncmp(p, "timestamp", 9) == 0) {
00994 #ifdef SQL_TYPE_TIMESTAMP
00995         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
00996 #else
00997         result = SQL_TIMESTAMP;
00998 #endif
00999     } else if (strncmp(p, "datetime", 8) == 0) {
01000 #ifdef SQL_TYPE_TIMESTAMP
01001         result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
01002 #else
01003         result = SQL_TIMESTAMP;
01004 #endif
01005     } else if (strncmp(p, "time", 4) == 0) {
01006 #ifdef SQL_TYPE_TIME
01007         result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
01008 #else
01009         result = SQL_TIME;
01010 #endif
01011     } else if (strncmp(p, "date", 4) == 0) {
01012 #ifdef SQL_TYPE_DATE
01013         result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
01014 #else
01015         result = SQL_DATE;
01016 #endif
01017 #ifdef SQL_LONGVARCHAR
01018     } else if (strncmp(p, "text", 4) == 0) {
01019         result = SQL_LONGVARCHAR;
01020 #endif
01021 #ifdef SQL_BIT
01022     } else if (strncmp(p, "bool", 4) == 0 ||
01023                strncmp(p, "bit", 3) == 0) {
01024         result = SQL_BIT;
01025 #endif
01026 #ifdef SQL_BIGINT
01027     } else if (strncmp(p, "bigint", 6) == 0) {
01028         result = SQL_BIGINT;
01029 #endif
01030     } else if (strncmp(p, "blob", 4) == 0) {
01031         result = SQL_BINARY;
01032     }
01033     if (nosign) {
01034         if (testsign) {
01035             *nosign = strstr(p, "unsigned") != NULL;
01036         } else {
01037             *nosign = 1;
01038         }
01039     }
01040     xfree(p);
01041     return result;
01042 }
01043 
01053 static void
01054 getmd(const char *typename, int sqltype, int *mp, int *dp)
01055 {
01056     int m = 0, d = 0;
01057 
01058     switch (sqltype) {
01059     case SQL_INTEGER:       m = 10; d = 9; break;
01060     case SQL_TINYINT:       m = 4; d = 3; break;
01061     case SQL_SMALLINT:      m = 6; d = 5; break;
01062     case SQL_FLOAT:         m = 25; d = 24; break;
01063     case SQL_DOUBLE:        m = 54; d = 53; break;
01064     case SQL_VARCHAR:       m = 255; d = 0; break;
01065 #ifdef SQL_TYPE_DATE
01066     case SQL_TYPE_DATE:
01067 #endif
01068     case SQL_DATE:          m = 10; d = 0; break;
01069 #ifdef SQL_TYPE_TIME
01070     case SQL_TYPE_TIME:
01071 #endif
01072     case SQL_TIME:          m = 8; d = 0; break;
01073 #ifdef SQL_TYPE_TIMESTAMP
01074     case SQL_TYPE_TIMESTAMP:
01075 #endif
01076     case SQL_TIMESTAMP:     m = 32; d = 0; break;
01077 #ifdef SQL_LONGVARCHAR
01078     case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
01079 #endif
01080     case SQL_VARBINARY:     m = 255; d = 0; break;
01081     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
01082 #ifdef SQL_BIGINT
01083     case SQL_BIGINT:        m = 20; d = 19; break;
01084 #endif
01085     }
01086     if (m && typename) {
01087         int mm, dd;
01088 
01089         if (sscanf(typename, "%*[^(](%d)", &mm) == 1) {
01090             m = d = mm;
01091         } else if (sscanf(typename, "%*[^(](%d,%d)", &mm, &dd) == 2) {
01092             m = mm;
01093             d = dd;
01094         }
01095     }
01096     if (mp) {
01097         *mp = m;
01098     }
01099     if (dp) {
01100         *dp = d;
01101     }
01102 }
01103 
01112 static int
01113 mapdeftype(int type, int stype, int nosign)
01114 {
01115     if (type == SQL_C_DEFAULT) {
01116         switch (stype) {
01117         case SQL_INTEGER:
01118             type = nosign > 0 ? SQL_C_ULONG : SQL_C_LONG;
01119             break;
01120         case SQL_TINYINT:
01121             type = nosign > 0 ? SQL_C_UTINYINT : SQL_C_TINYINT;
01122             break;
01123         case SQL_SMALLINT:
01124             type = nosign > 0 ? SQL_C_USHORT : SQL_C_SHORT;
01125             break;
01126         case SQL_FLOAT:
01127             type = SQL_C_FLOAT;
01128             break;
01129         case SQL_DOUBLE:
01130             type = SQL_C_DOUBLE;
01131             break;
01132         case SQL_TIMESTAMP:
01133             type = SQL_C_TIMESTAMP;
01134             break;
01135         case SQL_TIME:
01136             type = SQL_C_TIME;
01137             break;
01138         case SQL_DATE:
01139             type = SQL_C_DATE;
01140             break;
01141 #ifdef SQL_C_TYPE_TIMESTAMP
01142         case SQL_TYPE_TIMESTAMP:
01143             type = SQL_C_TYPE_TIMESTAMP;
01144             break;
01145 #endif
01146 #ifdef SQL_C_TYPE_TIME
01147         case SQL_TYPE_TIME:
01148             type = SQL_C_TYPE_TIME;
01149             break;
01150 #endif
01151 #ifdef SQL_C_TYPE_DATE
01152         case SQL_TYPE_DATE:
01153             type = SQL_C_TYPE_DATE;
01154             break;
01155 #endif
01156         case SQL_BINARY:
01157         case SQL_VARBINARY:
01158         case SQL_LONGVARBINARY:
01159             type = SQL_C_BINARY;
01160             break;
01161 #ifdef SQL_BIT
01162         case SQL_BIT:
01163             type = SQL_C_BIT;
01164             break;
01165 #endif
01166 #ifdef SQL_BIGINT
01167         case SQL_BIGINT:
01168             type = nosign > 0 ? SQL_C_UBIGINT : SQL_C_SBIGINT;
01169             break;
01170 #endif
01171         default:
01172             type = SQL_C_CHAR;
01173         }
01174     }
01175     return type;
01176 }
01177 
01188 static char *
01189 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg)
01190 {
01191     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
01192     int np = 0, size;
01193 
01194     *errmsg = NULL;
01195     if (sqlLen != SQL_NTS) {
01196         qz = q = xmalloc(sqlLen + 1);
01197         if (!qz) {
01198             return NULL;
01199         }
01200         memcpy(q, sql, sqlLen);
01201         q[sqlLen] = '\0';
01202         size = sqlLen * 4;
01203     } else {
01204         size = strlen(sql) * 4;
01205     }
01206     size += sizeof (char *) - 1;
01207     size &= ~(sizeof (char *) - 1);
01208     p = xmalloc(size);
01209     if (!p) {
01210 errout:
01211         freep(&qz);
01212         return NULL;
01213     }
01214     out = p;
01215     while (*q) {
01216         switch (*q) {
01217         case '\'':
01218         case '\"':
01219             if (q == inq) {
01220                 inq = NULL;
01221             } else if (!inq) {
01222                 inq = q + 1;
01223 
01224                 while (*inq) {
01225                     if (*inq == *q) {
01226                         if (inq[1] == *q) {
01227                             inq++;
01228                         } else {
01229                             break;
01230                         }
01231                     }
01232                     inq++;
01233                 }
01234             }
01235             *p++ = *q;
01236             break;
01237         case '?':
01238             if (inq) {
01239                 *p++ = *q;
01240             } else {
01241                 *p++ = '%';
01242                 *p++ = 'Q';
01243                 np++;
01244             }
01245             break;
01246         case ';':
01247             if (inq) {
01248                 *p++ = *q;
01249             } else {
01250                 do {
01251                     ++q;
01252                 } while (*q && ISSPACE(*q));
01253                 if (*q) {               
01254                     freep(&out);
01255                     *errmsg = "only one SQL statement allowed";
01256                     goto errout;
01257                 }
01258                 --q;
01259             }
01260             break;
01261         case '%':
01262             *p++ = '%';
01263             *p++ = '%';
01264             break;
01265         case '{':
01266             /* deal with {d 'YYYY-MM-DD'}, {t ...}, and {ts ...} */
01267             if (!inq) {
01268                 char *end = q + 1;
01269 
01270                 while (*end && *end != '}') {
01271                     ++end;
01272                 }
01273                 if (*end == '}') {
01274                     char *start = q + 1;
01275                     char *end2 = end - 1;
01276 
01277                     while (start < end2 && *start != '\'') {
01278                         ++start;
01279                     }
01280                     while (end2 > start && *end2 != '\'') {
01281                         --end2;
01282                     }
01283                     if (*start == '\'' && *end2 == '\'') {
01284                         while (start <= end2) {
01285                             *p++ = *start;
01286                             ++start;
01287                         }
01288                         q = end;
01289                         break;
01290                     }
01291                 }
01292             }
01293             /* FALL THROUGH */
01294         default:
01295             *p++ = *q;
01296         }
01297         ++q;
01298     }
01299     freep(&qz);
01300     *p = '\0';
01301     if (nparam) {
01302         *nparam = np;
01303     }
01304     if (isselect) {
01305         p = out;
01306         while (*p && ISSPACE(*p)) {
01307             ++p;
01308         }
01309         *isselect = strncasecmp(p, "select", 6) == 0;
01310     }
01311     return out;
01312 }
01313 
01322 static int
01323 findcol(char **cols, int ncols, char *name)
01324 {
01325     int i;
01326 
01327     if (cols) {
01328         for (i = 0; i < ncols; i++) {
01329             if (strcmp(cols[i], name) == 0) {
01330                 return i;
01331             }
01332         }
01333     }
01334     return -1;
01335 }
01336 
01353 static void
01354 fixupdyncols(STMT *s, DBC *d)
01355 {
01356     int i, k, pk, t, r, nrows, ncols, doautoinc = 0;
01357     char **rowp, *flagp, flags[128];
01358 
01359     if (!s->dyncols) {
01360         return;
01361     }
01362     /* fixup labels */
01363     if (!s->longnames) {
01364         if (s->dcols > 1) {
01365             char *table = s->dyncols[0].table;
01366 
01367             for (i = 1; table[0] && i < s->dcols; i++) {
01368                 if (strcmp(s->dyncols[i].table, table)) {
01369                     break;
01370                 }
01371             }
01372             if (i >= s->dcols) {
01373                 for (i = 0; i < s->dcols; i++) {
01374                     s->dyncols[i].label = s->dyncols[i].column;
01375                 }
01376             }
01377         } else if (s->dcols == 1) {
01378             s->dyncols[0].label = s->dyncols[0].column;
01379         }
01380     }
01381     for (i = 0; i < s->dcols; i++) {
01382         s->dyncols[i].type =
01383             mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3);
01384         getmd(s->dyncols[i].typename, s->dyncols[i].type,
01385               &s->dyncols[i].size, NULL);
01386 #ifdef SQL_LONGVARCHAR
01387         if (s->dyncols[i].type == SQL_VARCHAR &&
01388             s->dyncols[i].size > 255) {
01389             s->dyncols[i].type = SQL_LONGVARCHAR;
01390         }
01391 #endif
01392         if (s->dyncols[i].type == SQL_VARBINARY &&
01393             s->dyncols[i].size > 255) {
01394             s->dyncols[i].type = SQL_LONGVARBINARY;
01395         }
01396         if (s->dyncols[i].typename && strlen(s->dyncols[i].typename) == 7 &&
01397             strncasecmp(s->dyncols[i].typename, "integer", 7) == 0) {
01398             doautoinc++;
01399             s->dyncols[i].autoinc = -1;
01400         } else {
01401             s->dyncols[i].autoinc = 0;
01402         }
01403     }
01404     if (!doautoinc) {
01405         return;
01406     }
01407     if (s->dcols > array_size(flags)) {
01408         flagp = xmalloc(sizeof (flags[0]) * s->dcols);
01409         if (flagp == NULL) {
01410             return;
01411         }
01412     } else {
01413         flagp = flags;
01414     }
01415     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
01416     for (i = 0; i < s->dcols; i++) {
01417         s->dyncols[i].autoinc = 0;
01418     }
01419     for (i = 0; i < s->dcols; i++) {
01420         int ret, lastpk = -1, autoinccount = 0;
01421         char *sql;
01422 
01423         if (!s->dyncols[i].table[0]) {
01424             continue;
01425         }
01426         if (flagp[i]) {
01427             continue;
01428         }
01429         sql = sqlite3_mprintf("PRAGMA table_info('%q')", s->dyncols[i].table);
01430         if (!sql) {
01431             continue;
01432         }
01433         dbtraceapi(d, "sqlite3_get_table", sql);
01434         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, NULL);
01435         sqlite3_free(sql);
01436         if (ret != SQLITE_OK) {
01437             continue;
01438         }
01439         k = findcol(rowp, ncols, "name");
01440         t = findcol(rowp, ncols, "type");
01441         pk = findcol(rowp, ncols, "pk");
01442         if (k < 0 || t < 0) {
01443             goto freet;
01444         }
01445         for (r = 1; r <= nrows; r++) {
01446             int m;
01447 
01448             for (m = i; m < s->dcols; m++) {
01449                 if (!flagp[m] &&
01450                     strcmp(s->dyncols[m].column, rowp[r * ncols + k]) == 0 &&
01451                     strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
01452                     char *typename = rowp[r * ncols + t];
01453 
01454                     flagp[m] = 1;
01455                     freep(&s->dyncols[m].typename);
01456                     s->dyncols[m].typename = xstrdup(typename);
01457                     s->dyncols[m].type =
01458                         mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3);
01459                     getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
01460                           NULL);
01461 #ifdef SQL_LONGVARCHAR
01462                     if (s->dyncols[m].type == SQL_VARCHAR &&
01463                         s->dyncols[m].size > 255) {
01464                         s->dyncols[m].type = SQL_LONGVARCHAR;
01465                     }
01466 #endif
01467                     if (s->dyncols[i].type == SQL_VARBINARY &&
01468                         s->dyncols[i].size > 255) {
01469                         s->dyncols[i].type = SQL_LONGVARBINARY;
01470                     }
01471                     if (pk >= 0 && strcmp(rowp[r * ncols + pk], "1") == 0) {
01472                         if (++autoinccount > 1) {
01473                             if (lastpk >= 0) {
01474                                 s->dyncols[lastpk].autoinc = 0;
01475                                 lastpk = -1;
01476                             }
01477                         } else {
01478                             lastpk = m;
01479                             if (strlen(typename) == 7 &&
01480                                 strncasecmp(typename, "integer", 7) == 0) {
01481                                 s->dyncols[m].autoinc = 1;
01482                             }
01483                         }
01484                     }
01485                 }
01486             }
01487         }
01488 freet:
01489         sqlite3_free_table(rowp);
01490     }
01491     if (flagp != flags) {
01492         freep(&flagp);
01493     }
01494 }
01495 
01503 static int
01504 getmdays(int year, int month)
01505 {
01506     static const int mdays[] = {
01507         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
01508     };
01509     int mday;
01510 
01511     if (month < 1) {
01512         return 0;
01513     }
01514     mday = mdays[(month - 1) % 12];
01515     if (mday == 28 && year % 4 == 0 &&
01516         (!(year % 100 == 0) || year % 400 == 0)) {
01517         mday++;
01518     }
01519     return mday;
01520 }
01521 
01532 static int
01533 str2date(char *str, DATE_STRUCT *ds)
01534 {
01535     int i, err = 0;
01536     char *p, *q;
01537 
01538     ds->year = ds->month = ds->day = 0;
01539     p = str;
01540     while (*p && !ISDIGIT(*p)) {
01541         ++p;
01542     }
01543     q = p;
01544     i = 0;
01545     while (*q && !ISDIGIT(*q)) {
01546         ++i;
01547         ++q;
01548     }
01549     if (i >= 8) {
01550         char buf[8];
01551 
01552         strncpy(buf, p + 0, 4); buf[4] = '\0';
01553         ds->year = strtol(buf, NULL, 10);
01554         strncpy(buf, p + 4, 2); buf[2] = '\0';
01555         ds->month = strtol(buf, NULL, 10);
01556         strncpy(buf, p + 6, 2); buf[2] = '\0';
01557         ds->day = strtol(buf, NULL, 10);
01558         goto done;
01559     }
01560     i = 0;
01561     while (i < 3) {
01562         int n;
01563 
01564         q = NULL; 
01565         n = strtol(p, &q, 10);
01566         if (!q || q == p) {
01567             if (*q == '\0') {
01568                 if (i == 0) {
01569                     err = 1;
01570                 }
01571                 goto done;
01572             }
01573         }
01574         if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
01575             switch (i) {
01576             case 0: ds->year = n; break;
01577             case 1: ds->month = n; break;
01578             case 2: ds->day = n; break;
01579             }
01580             ++i;
01581             if (*q) {
01582                 ++q;
01583             }
01584         } else {
01585             i = 0;
01586             while (*q && !ISDIGIT(*q)) {
01587                 ++q;
01588             }
01589         }
01590         p = q;
01591     }
01592 done:
01593     /* final check for overflow */
01594     if (err ||
01595         ds->month < 1 || ds->month > 12 ||
01596         ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
01597         return -1;
01598     }
01599     return 0;
01600 }
01601 
01612 static int
01613 str2time(char *str, TIME_STRUCT *ts)
01614 {
01615     int i, err = 0;
01616     char *p, *q;
01617 
01618     ts->hour = ts->minute = ts->second = 0;
01619     p = str;
01620     while (*p && !ISDIGIT(*p)) {
01621         ++p;
01622     }
01623     q = p;
01624     i = 0;
01625     while (*q && ISDIGIT(*q)) {
01626         ++i;
01627         ++q;
01628     }
01629     if (i >= 6) {
01630         char buf[4];
01631 
01632         strncpy(buf, p + 0, 2); buf[2] = '\0';
01633         ts->hour = strtol(buf, NULL, 10);
01634         strncpy(buf, p + 2, 2); buf[2] = '\0';
01635         ts->minute = strtol(buf, NULL, 10);
01636         strncpy(buf, p + 4, 2); buf[2] = '\0';
01637         ts->second = strtol(buf, NULL, 10);
01638         goto done;
01639     }
01640     i = 0;
01641     while (i < 3) {
01642         int n;
01643 
01644         q = NULL; 
01645         n = strtol(p, &q, 10);
01646         if (!q || q == p) {
01647             if (*q == '\0') {
01648                 if (i == 0) {
01649                     err = 1;
01650                 }
01651                 goto done;
01652             }
01653         }
01654         if (*q == ':' || *q == '\0' || i == 2) {
01655             switch (i) {
01656             case 0: ts->hour = n; break;
01657             case 1: ts->minute = n; break;
01658             case 2: ts->second = n; break;
01659             }
01660             ++i;
01661             if (*q) {
01662                 ++q;
01663             }
01664         } else {
01665             i = 0;
01666             while (*q && !ISDIGIT(*q)) {
01667                 ++q;
01668             }
01669         }
01670         p = q;
01671     }
01672 done:
01673     /* final check for overflow */
01674     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
01675         return -1;
01676     }
01677     return 0;
01678 }
01679 
01695 static int
01696 str2timestamp(char *str, TIMESTAMP_STRUCT *tss)
01697 {
01698     int i, m, n, err = 0;
01699     char *p, *q, in = '\0';
01700 
01701     tss->year = tss->month = tss->day = 0;
01702     tss->hour = tss->minute = tss->second = 0;
01703     tss->fraction = 0;
01704     p = str;
01705     while (*p && !ISDIGIT(*p)) {
01706         ++p;
01707     }
01708     q = p;
01709     i = 0;
01710     while (*q && ISDIGIT(*q)) {
01711         ++i;
01712         ++q;
01713     }
01714     if (i >= 14) {
01715         char buf[16];
01716 
01717         strncpy(buf, p + 0, 4); buf[4] = '\0';
01718         tss->year = strtol(buf, NULL, 10);
01719         strncpy(buf, p + 4, 2); buf[2] = '\0';
01720         tss->month = strtol(buf, NULL, 10);
01721         strncpy(buf, p + 6, 2); buf[2] = '\0';
01722         tss->day = strtol(buf, NULL, 10);
01723         strncpy(buf, p + 8, 2); buf[2] = '\0';
01724         tss->hour = strtol(buf, NULL, 10);
01725         strncpy(buf, p + 10, 2); buf[2] = '\0';
01726         tss->minute = strtol(buf, NULL, 10);
01727         strncpy(buf, p + 12, 2); buf[2] = '\0';
01728         tss->second = strtol(buf, NULL, 10);
01729         if (i > 14) {
01730             m = i - 14;
01731             strncpy(buf, p + 14, m);
01732             while (m < 9) {
01733                 buf[m] = '0';
01734                 ++m;
01735             }
01736             buf[m] = '\0';
01737             tss->fraction = strtol(buf, NULL, 0);
01738         }
01739         m = 7;
01740         goto done;
01741     }
01742     m = i = 0;
01743     while ((m & 7) != 7) {
01744         q = NULL; 
01745         n = strtol(p, &q, 10);
01746         if (!q || q == p) {
01747             if (*q == '\0') {
01748                 if (m < 1) {
01749                     err = 1;
01750                 }
01751                 goto done;
01752             }
01753         }
01754         if (in == '\0') {
01755             switch (*q) {
01756             case '-':
01757             case '/':
01758                 if ((m & 1) == 0) {
01759                     in = *q;
01760                     i = 0;
01761                 }
01762                 break;
01763             case ':':
01764                 if ((m & 2) == 0) {
01765                     in = *q;
01766                     i = 0;
01767                 }
01768                 break;
01769             case ' ':
01770             case '.':
01771                 break;
01772             default:
01773                 in = '\0';
01774                 i = 0;
01775                 break;
01776             }
01777         }
01778         switch (in) {
01779         case '-':
01780         case '/':
01781             switch (i) {
01782             case 0: tss->year = n; break;
01783             case 1: tss->month = n; break;
01784             case 2: tss->day = n; break;
01785             }
01786             if (++i >= 3) {
01787                 i = 0;
01788                 m |= 1;
01789                 if (!(m & 2)) {
01790                     m |= 8;
01791                 }
01792                 goto skip;
01793             } else {
01794                 ++q;
01795             }
01796             break;
01797         case ':':
01798             switch (i) {
01799             case 0: tss->hour = n; break;
01800             case 1: tss->minute = n; break;
01801             case 2: tss->second = n; break;
01802             }
01803             if (++i >= 3) {
01804                 i = 0;
01805                 m |= 2;
01806                 if (*q == '.') {
01807                     in = '.';
01808                     goto skip2;
01809                 }
01810                 if (*q == ' ') {
01811                     if ((m & 1) == 0) {
01812                         char *e = NULL;
01813 
01814                         strtol(q + 1, &e, 10);
01815                         if (e && *e == '-') {
01816                             goto skip;
01817                         }
01818                     }
01819                     in = '.';
01820                     goto skip2;
01821                 }
01822                 goto skip;
01823             } else {
01824                 ++q;
01825             }
01826             break;
01827         case '.':
01828             if (++i >= 1) {
01829                 int ndig = q - p;
01830 
01831                 if (p[0] == '+' || p[0] == '-') {
01832                     ndig--;
01833                 }
01834                 while (ndig < 9) {
01835                     n = n * 10;
01836                     ++ndig;
01837                 }
01838                 tss->fraction = n;
01839                 m |= 4;
01840                 i = 0;
01841             }
01842         default:
01843         skip:
01844             in = '\0';
01845         skip2:
01846             while (*q && !ISDIGIT(*q)) {
01847                 ++q;
01848             }
01849         }
01850         p = q;
01851     }
01852     if ((m & 7) > 1 && (m & 8)) {
01853         /* ISO8601 timezone */
01854         if (p > str && ISDIGIT(*p)) {
01855             int nn, sign;
01856 
01857             q = p - 1;
01858             if (*q != '+' && *q != '-') {
01859                 goto done;
01860             }
01861             sign = *q == '+' ? -1 : 1;
01862             q = NULL;
01863             n = strtol(p, &q, 10);
01864             if (!q || *q++ != ':' || !ISDIGIT(*q)) {
01865                 goto done;
01866             }
01867             p = q;
01868             q = NULL;
01869             nn = strtol(p, &q, 0);
01870             tss->minute += nn * sign;
01871             if ((SQLSMALLINT) tss->minute < 0) {
01872                 tss->hour -= 1;
01873                 tss->minute += 60;
01874             } else if (tss->minute >= 60) {
01875                 tss->hour += 1;
01876                 tss->minute -= 60;
01877             }
01878             tss->hour += n * sign;
01879             if ((SQLSMALLINT) tss->hour < 0) {
01880                 tss->day -= 1;
01881                 tss->hour += 24;
01882             } else if (tss->hour >= 24) {
01883                 tss->day += 1;
01884                 tss->hour -= 24;
01885             }
01886             if ((short) tss->day < 1 || tss->day >= 28) {
01887                 int mday, pday, pmon;
01888 
01889                 mday = getmdays(tss->year, tss->month);
01890                 pmon = tss->month - 1;
01891                 if (pmon < 1) {
01892                     pmon = 12;
01893                 }
01894                 pday = getmdays(tss->year, pmon);
01895                 if ((SQLSMALLINT) tss->day < 1) {
01896                     tss->month -= 1;
01897                     tss->day = pday;
01898                 } else if (tss->day > mday) {
01899                     tss->month += 1;
01900                     tss->day = 1;
01901                 }
01902                 if ((SQLSMALLINT) tss->month < 1) {
01903                     tss->year -= 1;
01904                     tss->month = 12;
01905                 } else if (tss->month > 12) {
01906                     tss->year += 1;
01907                     tss->month = 1;
01908                 }
01909             }
01910         }
01911     }
01912 done:
01913     /* final check for overflow */
01914     if (err ||
01915         tss->month < 1 || tss->month > 12 ||
01916         tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
01917         tss->hour > 23 || tss->minute > 60 || tss->second > 60) {
01918         return -1;
01919     }
01920     return (m & 7) < 1 ? -1 : 0;
01921 }
01922 
01929 static int
01930 getbool(char *string)
01931 {
01932     if (string) {
01933         return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
01934     }
01935     return 0;
01936 }
01937 
01943 static void
01944 dbtrace(void *arg, const char *msg)
01945 {
01946     DBC *d = (DBC *) arg;
01947 
01948     if (msg && d->trace) {
01949         int len = strlen(msg);
01950 
01951         if (len > 0) {
01952             char *end = "\n";
01953 
01954             if (msg[len - 1] != ';') {
01955                 end = ";\n";
01956             }
01957             fprintf(d->trace, "%s%s", msg, end);
01958             fflush(d->trace);
01959         }
01960     }
01961 }
01962 
01963 /* see doc on top */
01964 
01965 static void
01966 dbtraceapi(DBC *d, char *fn, const char *sql)
01967 {
01968     if (fn && d->trace) {
01969         if (sql) {
01970             fprintf(d->trace, "-- %s: %s\n", fn, sql);
01971         } else {
01972             fprintf(d->trace, "-- %s\n", fn);
01973         }
01974         fflush(d->trace);
01975     }
01976 }
01977 
01984 static void
01985 dbtracerc(DBC *d, int rc, char *err)
01986 {
01987     if (rc != SQLITE_OK && d->trace) {
01988         fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
01989         fprintf(d->trace, err ? ": %s\n" : "\n", err);
01990         fflush(d->trace);
01991     }
01992 }
01993 
02006 static SQLRETURN
02007 dbopen(DBC *d, char *name, char *dsn, char *sflag, char *spflag, char *ntflag,
02008        char *busy)
02009 {
02010     char *endp = NULL;
02011     int rc, tmp, busyto = 1000;
02012 
02013     if (d->sqlite) {
02014         if (d->trace) {
02015             fprintf(d->trace, "-- sqlite3_close (deferred): '%s'\n",
02016                     d->dbname);
02017             fflush(d->trace);
02018         }
02019         sqlite3_close(d->sqlite);
02020         d->sqlite = NULL;
02021     }
02022     rc = sqlite3_open(name, &d->sqlite);
02023     if (rc != SQLITE_OK) {
02024 connfail:
02025         setstatd(d, rc, "connect failed", (*d->ov3) ? "HY000" : "S1000");
02026         return SQL_ERROR;
02027     }
02028     if (d->trace) {
02029         sqlite3_trace(d->sqlite, dbtrace, d);
02030     }
02031     d->step_enable = getbool(sflag);
02032     d->trans_disable = getbool(ntflag);
02033     d->curtype = d->step_enable ?
02034         SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
02035     tmp = strtol(busy, &endp, 0);
02036     if (endp && *endp == '\0' && endp != busy) {
02037         busyto = tmp;
02038     }
02039     if (busyto < 1 || busyto > 1000000) {
02040         busyto = 1000000;
02041     }
02042     d->timeout = busyto;
02043     if (setsqliteopts(d->sqlite, d) != SQLITE_OK) {
02044         if (d->trace) {
02045             fprintf(d->trace, "-- sqlite3_close: '%s'\n",
02046                     d->dbname);
02047             fflush(d->trace);
02048         }
02049         sqlite3_close(d->sqlite);
02050         d->sqlite = NULL;
02051         goto connfail;
02052     }
02053     if (spflag && spflag[0] != '\0') {
02054         char syncp[128];
02055 
02056         sprintf(syncp, "PRAGMA synchronous = %8.8s;", spflag);
02057         sqlite3_exec(d->sqlite, syncp, NULL, NULL, NULL);
02058     }
02059     freep(&d->dbname);
02060     d->dbname = xstrdup(name);
02061     freep(&d->dsn);
02062     d->dsn = xstrdup(dsn);
02063     if (d->trace) {
02064         fprintf(d->trace, "-- sqlite3_open: '%s'\n", d->dbname);
02065         fflush(d->trace);
02066     }
02067     return SQL_SUCCESS;
02068 }
02069 
02078 static char *
02079 s3stmt_coltype(sqlite3_stmt *s3stmt, int col, DBC *d)
02080 {
02081     int guessed = 0;
02082     char *typename = (char *) sqlite3_column_decltype(s3stmt, col);
02083 
02084     if (!typename) {
02085         guessed++;
02086         switch (sqlite3_column_type(s3stmt, col)) {
02087         case SQLITE_INTEGER: typename = "integer"; break;
02088         case SQLITE_FLOAT:   typename = "double";  break;
02089         default:
02090         case SQLITE_TEXT:    typename = "varchar"; break;
02091         case SQLITE_BLOB:    typename = "blob";    break;
02092 #if 0
02093         case SQLITE_NULL:    typename = "null";    break;
02094 #endif
02095         }
02096     }
02097     if (d->trace) {
02098         fprintf(d->trace, "-- column %d type%s: '%s'\n", col + 1,
02099                 guessed ? " (guessed)" : "", typename);
02100         fflush(d->trace);
02101     }
02102     return typename;
02103 }
02104 
02111 static int
02112 s3stmt_step(STMT *s)
02113 {
02114     DBC *d = (DBC *) s->dbc;
02115     char **rowd = NULL;
02116     const char *errp = NULL;
02117     int i, ncols, rc;
02118 
02119     if (s != d->cur_s3stmt || !s->s3stmt) {
02120         setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
02121         return SQL_ERROR;
02122     }
02123     rc = sqlite3_step(s->s3stmt);
02124     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
02125         ++d->s3stmt_rownum;
02126         ncols = sqlite3_column_count(s->s3stmt);
02127         if (d->s3stmt_rownum == 0 && ncols > 0) {
02128             int size;
02129             char *p;
02130             COL *dyncols;
02131             const char *colname, *typename;
02132 
02133             for (i = size = 0; i < ncols; i++) {
02134                 colname = sqlite3_column_name(s->s3stmt, i);
02135                 size += 3 + 3 * strlen(colname);
02136             }
02137             dyncols = xmalloc(ncols * sizeof (COL) + size);
02138             if (!dyncols) {
02139                 freedyncols(s);
02140                 s->ncols = 0;
02141                 dbtraceapi(d, "sqlite3_finalize", 0);
02142                 sqlite3_finalize(s->s3stmt);
02143                 s->s3stmt = NULL;
02144                 d->cur_s3stmt = NULL;
02145                 return nomem(s);
02146             }
02147             p = (char *) (dyncols + ncols);
02148             for (i = 0; i < ncols; i++) {
02149                 char *q;
02150 
02151                 colname = sqlite3_column_name(s->s3stmt, i);
02152                 if (d->trace) {
02153                     fprintf(d->trace, "-- column %d name: '%s'\n",
02154                             i + 1, colname);
02155                     fflush(d->trace);
02156                 }
02157                 typename = s3stmt_coltype(s->s3stmt, i, d);
02158                 dyncols[i].db = ((DBC *) (s->dbc))->dbname;
02159                 strcpy(p, colname);
02160                 dyncols[i].label = p;
02161                 p += strlen(p) + 1;
02162                 q = strchr(colname, '.');
02163                 if (q) {
02164                     char *q2 = strchr(q + 1, '.');
02165 
02166                     /* SQLite 3.3.4 produces view.table.column sometimes */
02167                     if (q2) {
02168                         q = q2;
02169                     }
02170                 }
02171                 if (q) {
02172                     dyncols[i].table = p;
02173                     strncpy(p, colname, q - colname);
02174                     p[q - colname] = '\0';
02175                     p += strlen(p) + 1;
02176                     strcpy(p, q + 1);
02177                     dyncols[i].column = p;
02178                     p += strlen(p) + 1;
02179                 } else {
02180                     dyncols[i].table = "";
02181                     strcpy(p, colname);
02182                     dyncols[i].column = p;
02183                     p += strlen(p) + 1;
02184                 }
02185                 if (s->longnames) {
02186                     dyncols[i].column = dyncols[i].label;
02187                 }
02188 #ifdef SQL_LONGVARCHAR
02189                 dyncols[i].type = SQL_LONGVARCHAR;
02190                 dyncols[i].size = 65536;
02191 #else
02192                 dyncols[i].type = SQL_VARCHAR;
02193                 dyncols[i].size = 255;
02194 #endif
02195                 dyncols[i].index = i;
02196                 dyncols[i].scale = 0;
02197                 dyncols[i].prec = 0;
02198                 dyncols[i].nosign = 1;
02199                 dyncols[i].autoinc = -1;
02200                 dyncols[i].typename = xstrdup(typename);
02201             }
02202             freedyncols(s);
02203             s->ncols = s->dcols = ncols;
02204             s->dyncols = s->cols = dyncols;
02205             fixupdyncols(s, d);
02206             mkbindcols(s, s->ncols);
02207         }
02208         if (ncols <= 0) {
02209             goto killstmt;
02210         }
02211         if (rc == SQLITE_DONE) {
02212             freeresult(s, 0);
02213             s->nrows = 0;
02214             dbtraceapi(d, "sqlite3_finalize", 0);
02215             sqlite3_finalize(s->s3stmt);
02216             s->s3stmt = NULL;
02217             d->cur_s3stmt = NULL;
02218             return SQL_SUCCESS;
02219         }
02220         rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
02221         if (rowd) {
02222             const unsigned char *value;
02223 
02224             rowd[0] = (char *) (ncols * 2);
02225             ++rowd;
02226             for (i = 0; i < ncols; i++) {
02227                 int coltype = sqlite3_column_type(s->s3stmt, i);
02228 
02229                 rowd[i] = NULL;
02230                 if (coltype == SQLITE_BLOB) {
02231                     int k, nbytes = sqlite3_column_bytes(s->s3stmt, i);
02232                     char *qp;
02233                     unsigned const char *bp;
02234 
02235                     bp = sqlite3_column_blob(s->s3stmt, i);
02236                     qp = xmalloc(nbytes * 2 + 4);
02237                     if (qp) {
02238                         rowd[i + ncols] = qp;
02239                         *qp++ = 'X';
02240                         *qp++ = '\'';
02241                         for (k = 0; k < nbytes; k++) {
02242                             *qp++ = xdigits[(bp[k] >> 4)];
02243                             *qp++ = xdigits[(bp[k] & 0xF)];
02244                         }
02245                         *qp++ = '\'';
02246                         *qp = '\0';
02247                     }
02248                 } else if (coltype != SQLITE_NULL) {
02249                     value = sqlite3_column_text(s->s3stmt, i);
02250                     rowd[i + ncols] = xstrdup((char *) value);
02251                 }
02252             }
02253             for (i = 0; i < ncols; i++) {
02254                 int coltype = sqlite3_column_type(s->s3stmt, i);
02255 
02256                 value = NULL;
02257                 if (coltype == SQLITE_BLOB) {
02258                     value = sqlite3_column_blob(s->s3stmt, i);
02259                 } else if (coltype != SQLITE_NULL) {
02260                     value = sqlite3_column_text(s->s3stmt, i);
02261                 }
02262                 if (value && !rowd[i + ncols]) {
02263                     freerows(rowd);
02264                     rowd = 0;
02265                     break;
02266                 }
02267             }
02268         }
02269         if (rowd) {
02270             freeresult(s, 0);
02271             s->nrows = 1;
02272             s->rows = rowd;
02273             s->rowfree = freerows;
02274             if (rc == SQLITE_DONE) {
02275                 dbtraceapi(d, "sqlite3_finalize", 0);
02276                 sqlite3_finalize(s->s3stmt);
02277                 s->s3stmt = NULL;
02278                 d->cur_s3stmt = NULL;
02279             }
02280             return SQL_SUCCESS;
02281         }
02282     }
02283 killstmt:
02284     dbtraceapi(d, "sqlite3_finalize", 0);
02285     rc = sqlite3_finalize(s->s3stmt);
02286     errp = sqlite3_errmsg(d->sqlite);
02287     s->s3stmt = NULL;
02288     d->cur_s3stmt = NULL;
02289     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
02290             errp ? errp : "unknown error", rc);
02291     return SQL_ERROR;   
02292 }
02293 
02299 static void
02300 s3stmt_end(STMT *s)
02301 {
02302     DBC *d;
02303 
02304     if (!s || !s->s3stmt) {
02305         return;
02306     }
02307     d = (DBC *) s->dbc;
02308     dbtraceapi(d, "sqlite3_finalize", 0);
02309     sqlite3_finalize(s->s3stmt);
02310     s->s3stmt = NULL;
02311     d->cur_s3stmt = NULL;
02312 }
02313 
02319 static void
02320 s3stmt_end_if(STMT *s)
02321 {
02322     DBC *d = (DBC *) s->dbc;
02323 
02324     if (d && d->cur_s3stmt == s) {
02325         s3stmt_end(s);
02326     }
02327 }
02328 
02336 static SQLRETURN
02337 s3stmt_start(STMT *s, char **params)
02338 {
02339     DBC *d = (DBC *) s->dbc;
02340     char *sql = NULL;
02341     const char *endp;
02342     sqlite3_stmt *s3stmt = NULL;
02343     int rc;
02344 
02345 #ifdef CANT_PASS_VALIST_AS_CHARPTR
02346     /* adjust with MAX_PARAMS_FOR_MPRINTF */
02347     sql = sqlite3_mprintf(s->query,
02348                           params[0], params[1],
02349                           params[2], params[3],
02350                           params[4], params[5],
02351                           params[6], params[7],
02352                           params[8], params[9],
02353                           params[10], params[11],
02354                           params[12], params[13],
02355                           params[14], params[15],
02356                           params[16], params[17],
02357                           params[18], params[19],
02358                           params[20], params[21],
02359                           params[22], params[23],
02360                           params[24], params[25],
02361                           params[26], params[27],
02362                           params[28], params[29],
02363                           params[30], params[31]);
02364 #else
02365     sql = sqlite3_vmprintf((char *) s->query, (char *) params);
02366 #endif
02367     if (!sql) {
02368         return nomem(s);
02369     }
02370     dbtraceapi(d, "sqlite3_prepare", sql);
02371     rc = sqlite3_prepare(d->sqlite, sql, -1, &s3stmt, &endp);
02372     dbtracerc(d, rc, NULL);
02373     sqlite3_free(sql);
02374     if (rc != SQLITE_OK) {
02375         if (s3stmt) {
02376             dbtraceapi(d, "sqlite3_finalize", NULL);
02377             sqlite3_finalize(s3stmt);
02378         }
02379         setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
02380                 sqlite3_errmsg(d->sqlite), rc);
02381         return SQL_ERROR;
02382     }
02383     s->s3stmt = s3stmt;
02384     d->cur_s3stmt = s;
02385     d->s3stmt_rownum = -1;
02386     return SQL_SUCCESS;
02387 }
02388 
02393 SQLRETURN SQL_API
02394 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
02395 {
02396     return drvunimplstmt(stmt);
02397 }
02398 
02403 SQLRETURN SQL_API
02404 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
02405                SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
02406                SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
02407 {
02408     if (env == SQL_NULL_HENV) {
02409         return SQL_INVALID_HANDLE;
02410     }
02411     return SQL_ERROR;
02412 }
02413 
02418 SQLRETURN SQL_API
02419 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
02420            SQLSMALLINT descmax, SQLSMALLINT *desclenp,
02421            SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
02422 {
02423     if (env == SQL_NULL_HENV) {
02424         return SQL_INVALID_HANDLE;
02425     }
02426     return SQL_ERROR;
02427 }
02428 
02433 SQLRETURN SQL_API
02434 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
02435                  SQLCHAR *connout, SQLSMALLINT connoutMax,
02436                  SQLSMALLINT *connoutLen)
02437 {
02438     return drvunimpldbc(dbc);
02439 }
02440 
02449 SQLRETURN SQL_API
02450 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
02451 {
02452     STMT *s;
02453     int i, dlen, done = 0;
02454     BINDPARM *p;
02455 
02456     if (stmt == SQL_NULL_HSTMT) {
02457         return SQL_INVALID_HANDLE;
02458     }
02459     s = (STMT *) stmt;
02460     if (!s->query || s->nparams <= 0) {
02461 seqerr:
02462         setstat(s, -1, "sequence error", "HY010");
02463         return SQL_ERROR;
02464     }
02465     for (i = 0; i < s->nparams; i++) {
02466         p = &s->bindparms[i];
02467         if (p->need > 0) {
02468             int type = mapdeftype(p->type, p->stype, -1);
02469 
02470             if (len == SQL_NULL_DATA) {
02471                 freep(&p->parbuf);
02472                 p->param = NULL;
02473                 p->len = SQL_NULL_DATA;
02474                 p->need = -1;
02475             } else if (type != SQL_C_CHAR && type != SQL_C_BINARY) {
02476                 int size = 0;
02477 
02478                 switch (type) {
02479                 case SQL_C_TINYINT:
02480                 case SQL_C_UTINYINT:
02481                 case SQL_C_STINYINT:
02482 #ifdef SQL_BIT
02483                 case SQL_C_BIT:
02484 #endif
02485                     size = sizeof (char);
02486                     break;
02487                 case SQL_C_SHORT:
02488                 case SQL_C_USHORT:
02489                 case SQL_C_SSHORT:
02490                     size = sizeof (short);
02491                     break;
02492                 case SQL_C_LONG:
02493                 case SQL_C_ULONG:
02494                 case SQL_C_SLONG:
02495                     size = sizeof (long);
02496                     break;
02497 #ifdef SQL_BIGINT
02498                 case SQL_C_UBIGINT:
02499                 case SQL_C_SBIGINT:
02500                     size = sizeof (SQLBIGINT);
02501                     break;
02502 #endif
02503                 case SQL_C_FLOAT:
02504                     size = sizeof (float);
02505                     break;
02506                 case SQL_C_DOUBLE:
02507                     size = sizeof (double);
02508                     break;
02509 #ifdef SQL_C_TYPE_DATE
02510                 case SQL_C_TYPE_DATE:
02511 #endif
02512                 case SQL_C_DATE:
02513                     size = sizeof (DATE_STRUCT);
02514                     break;
02515 #ifdef SQL_C_TYPE_DATE
02516                 case SQL_C_TYPE_TIME:
02517 #endif
02518                 case SQL_C_TIME:
02519                     size = sizeof (TIME_STRUCT);
02520                     break;
02521 #ifdef SQL_C_TYPE_DATE
02522                 case SQL_C_TYPE_TIMESTAMP:
02523 #endif
02524                 case SQL_C_TIMESTAMP:
02525                     size = sizeof (TIMESTAMP_STRUCT);
02526                     break;
02527                 }
02528                 freep(&p->parbuf);
02529                 p->parbuf = xmalloc(size);
02530                 if (!p->parbuf) {
02531                     return nomem(s);
02532                 }
02533                 p->param = p->parbuf;
02534                 memcpy(p->param, data, size);
02535                 p->len = size;
02536                 p->need = -1;
02537             } else if (type == SQL_C_CHAR && len == SQL_NTS) {
02538                 char *dp = data;
02539 
02540                 dlen = strlen(dp);
02541                 freep(&p->parbuf);
02542                 p->parbuf = xmalloc(dlen + 1);
02543                 if (!p->parbuf) {
02544                     return nomem(s);
02545                 }
02546                 p->param = p->parbuf;
02547                 strcpy(p->param, dp);
02548                 p->len = dlen;
02549                 p->need = -1;
02550             } else if (len <= 0) {
02551                 setstat(s, -1, "invalid length", "HY090");
02552                 return SQL_ERROR;
02553             } else {
02554                 dlen = min(p->len - p->offs, len);
02555                 if (!p->param) {
02556                     setstat(s, -1, "no memory for parameter", "HY013");
02557                     return SQL_ERROR;
02558                 }
02559                 memcpy((char *) p->param + p->offs, data, dlen);
02560                 p->offs += dlen;
02561                 if (p->offs >= p->len) {
02562                     *((char *) p->param + p->len) = '\0';
02563                     p->need = (type == SQL_C_CHAR) ? -1 : 0;
02564                 }
02565             }
02566             done = 1;
02567             break;
02568         }
02569     }
02570     if (!done) {
02571         goto seqerr;
02572     }
02573     return SQL_SUCCESS;
02574 }
02575 
02581 static SQLRETURN
02582 freeparams(STMT *s)
02583 {
02584     if (s->bindparms) {
02585         int n;
02586 
02587         for (n = 0; n < s->nbindparms; n++) {
02588             freep(&s->bindparms[n].parbuf);
02589             memset(&s->bindparms[n], 0, sizeof (BINDPARM));
02590         }
02591     }
02592     return SQL_SUCCESS;
02593 }
02594 
02595 /* see doc on top */
02596 
02597 static SQLRETURN
02598 substparam(STMT *s, char **sqlp, int pnum, char **outp)
02599 {
02600     char *outdata = NULL, *sql = NULL;
02601     int type, len = 0, isnull = 0, needalloc = 0;
02602     BINDPARM *p;
02603     double dval;
02604 
02605     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
02606         goto error;
02607     }
02608     if (sqlp) {
02609         char *q;
02610 
02611         sql = *sqlp;
02612         q = sql;
02613         while (1) {
02614             q = strchr(q, '%');
02615             if (!q) {
02616                 sql = *sqlp = q;
02617                 break;
02618             }
02619             ++q;
02620             if (*q == 'q' || *q == 'Q' || *q == 's') {
02621                 sql = *sqlp = q;
02622                 break;
02623             }
02624         }
02625     }
02626     p = &s->bindparms[pnum];
02627     type = mapdeftype(p->type, p->stype, -1);
02628     if (p->need > 0) {
02629         if (!p->parbuf) {
02630             p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
02631             if (p->len <= 0 && p->len != SQL_NTS && p->len != SQL_NULL_DATA) {
02632                 setstat(s, -1, "invalid length", "HY009");
02633                 return SQL_ERROR;
02634             }
02635             if (p->len > 0) {
02636                 p->parbuf = xmalloc(p->len + 1);
02637                 if (!p->parbuf) {
02638                     return nomem(s);
02639                 }
02640                 p->param = p->parbuf;
02641             } else {
02642                 p->param = NULL;
02643             }
02644         }
02645         return SQL_NEED_DATA;
02646     }
02647     p->strbuf[0] = '\0';
02648     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
02649         isnull = 1;
02650         goto bind;
02651     }
02652     switch (type) {
02653     case SQL_C_BINARY: {
02654         char *param, *pp;
02655         int i;
02656 
02657         if (p->need < 0 && p->parbuf == p->param) {
02658             outdata = p->param;
02659             if (sql) {
02660                 *sql = 's';
02661             }
02662             goto putp;
02663         }
02664         if (p->param == p->parbuf) {
02665             param = p->param;
02666             len = p->len;
02667             if ((param[0] == 'x' || param[0] == 'X') &&
02668                 param[1] == '\'' &&
02669                 param[len - 1] == '\'') {
02670                 break;
02671             }
02672         }
02673         if (!p->lenp) {
02674             len = p->len;
02675         } else {
02676             len = *p->lenp;
02677             if (len <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
02678                 len = SQL_LEN_DATA_AT_EXEC(len);
02679             }
02680         }
02681         if (len < 0) {
02682             setstat(s, -1, "invalid length", "HY009");
02683             return SQL_ERROR;
02684         }
02685         param = xmalloc(len * 2 + 4);
02686         if (!param) {
02687             return nomem(s);
02688         }
02689         pp = param;
02690         *pp++ = 'x';
02691         *pp++ = '\'';
02692         for (i = 0; i < len; i++) {
02693             *pp++ = xdigits[(((char *) p->param)[i] >> 4) & 0xF];
02694             *pp++ = xdigits[((char *) p->param)[i] & 0xF];
02695         }
02696         *pp++ = '\'';
02697         *pp++ = '\0';
02698         freep(&p->parbuf);
02699         p->parbuf = p->param = param;
02700         p->len = len * 2 + 4 - 1;
02701         p->max = p->len;
02702         p->need = -1;
02703         if (sql) {
02704             *sql = 's';
02705         }
02706         break;
02707     }
02708     case SQL_C_CHAR:
02709         if (sql) {
02710             *sql = 'Q';
02711         }
02712         break;
02713     case SQL_C_UTINYINT:
02714         sprintf(p->strbuf, "%d", *((unsigned char *) p->param));
02715         goto bind;
02716     case SQL_C_TINYINT:
02717     case SQL_C_STINYINT:
02718         sprintf(p->strbuf, "%d", *((char *) p->param));
02719         goto bind;
02720     case SQL_C_USHORT:
02721         sprintf(p->strbuf, "%d", *((unsigned short *) p->param));
02722         goto bind;
02723     case SQL_C_SHORT:
02724     case SQL_C_SSHORT:
02725         sprintf(p->strbuf, "%d", *((short *) p->param));
02726         goto bind;
02727     case SQL_C_ULONG:
02728     case SQL_C_LONG:
02729     case SQL_C_SLONG:
02730         sprintf(p->strbuf, "%ld", *((long *) p->param));
02731         goto bind;
02732 #ifdef SQL_BIT
02733     case SQL_C_BIT:
02734         strcpy(p->strbuf, (*((unsigned char *) p->param)) ? "1" : "0");
02735         goto bind;
02736 #endif
02737 #ifdef SQL_BIGINT
02738     case SQL_C_SBIGINT:
02739 #ifdef _WIN32
02740         sprintf(p->strbuf, "%I64d", *(SQLBIGINT *) p->param);
02741 #else
02742         sprintf(p->strbuf, "%lld", *(SQLBIGINT *) p->param);
02743 #endif
02744         goto bind;
02745     case SQL_C_UBIGINT:
02746 #ifdef _WIN32
02747         sprintf(p->strbuf, "%I64u", *(SQLUBIGINT *) p->param);
02748 #else
02749         sprintf(p->strbuf, "%llu", *(SQLUBIGINT *) p->param);
02750 #endif
02751         goto bind;
02752 #endif
02753     case SQL_C_FLOAT:
02754         dval = *((float *) p->param);
02755         goto dodouble;
02756     case SQL_C_DOUBLE:
02757         dval = *((double *) p->param);
02758     dodouble: {
02759         char *buf2 = sqlite3_mprintf("%.16g", dval);
02760 
02761         if (buf2) {
02762             strcpy(p->strbuf, buf2);
02763             sqlite3_free(buf2);
02764         } else {
02765             isnull = 1;
02766         }
02767         goto bind;
02768     }
02769 #ifdef SQL_C_TYPE_DATE
02770     case SQL_C_TYPE_DATE:
02771 #endif
02772     case SQL_C_DATE:
02773         sprintf(p->strbuf, "%04d-%02d-%02d",
02774                 ((DATE_STRUCT *) p->param)->year,
02775                 ((DATE_STRUCT *) p->param)->month,
02776                 ((DATE_STRUCT *) p->param)->day);
02777         goto bind;
02778 #ifdef SQL_C_TYPE_TIME
02779     case SQL_C_TYPE_TIME:
02780 #endif
02781     case SQL_C_TIME:
02782         sprintf(p->strbuf, "%02d:%02d:%02d",
02783                 ((TIME_STRUCT *) p->param)->hour,
02784                 ((TIME_STRUCT *) p->param)->minute,
02785                 ((TIME_STRUCT *) p->param)->second);
02786         goto bind;
02787 #ifdef SQL_C_TYPE_TIMESTAMP
02788     case SQL_C_TYPE_TIMESTAMP:
02789 #endif
02790     case SQL_C_TIMESTAMP:
02791         sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%d",
02792                 ((TIMESTAMP_STRUCT *) p->param)->year,
02793                 ((TIMESTAMP_STRUCT *) p->param)->month,
02794                 ((TIMESTAMP_STRUCT *) p->param)->day,
02795                 ((TIMESTAMP_STRUCT *) p->param)->hour,
02796                 ((TIMESTAMP_STRUCT *) p->param)->minute,
02797                 ((TIMESTAMP_STRUCT *) p->param)->second,
02798                 (int) ((TIMESTAMP_STRUCT *) p->param)->fraction);
02799     bind:
02800         if (sql) {
02801             *sql = 'Q';
02802         }
02803         if (outp) {
02804             *outp = isnull ? NULL : p->strbuf;
02805         }
02806         return SQL_SUCCESS;
02807     default:
02808     error:
02809         setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
02810         return SQL_ERROR;
02811     }
02812     if (!p->parbuf && p->lenp) {
02813         if (p->type == SQL_C_CHAR) {
02814             if (*p->lenp == SQL_NTS) {
02815                 p->len = p->max = strlen(p->param);
02816             } else if (*p->lenp >= 0) {
02817                 p->len = p->max = *p->lenp;
02818                 needalloc = 1;
02819             }
02820         }
02821     }
02822     if (p->need < 0 && p->parbuf == p->param) {
02823         outdata = p->param;
02824         goto putp;
02825     }
02826     if (p->type == SQL_C_CHAR) {
02827         outdata = p->param;
02828         if (needalloc) {
02829             char *dp;
02830 
02831             freep(&p->parbuf);
02832             dp = xmalloc(p->len + 1);
02833             if (!dp) {
02834                 return nomem(s);
02835             }
02836             memcpy(dp, p->param, p->len);
02837             dp[p->len] = '\0';
02838             p->parbuf = p->param = dp;
02839             outdata = p->param;
02840         }
02841     } else {
02842         outdata = p->param;
02843     }
02844 putp:
02845     if (outp) {
02846         *outp = outdata;
02847     }
02848     return SQL_SUCCESS;
02849 }
02850 
02866 static SQLRETURN
02867 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
02868              SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
02869              SQLSMALLINT scale,
02870              SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
02871 {
02872     STMT *s;
02873     BINDPARM *p;
02874 
02875     if (stmt == SQL_NULL_HSTMT) {
02876         return SQL_INVALID_HANDLE;
02877     }
02878     s = (STMT *) stmt;
02879     if (pnum == 0) {
02880         setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
02881         return SQL_ERROR;
02882     }
02883     if (!data && (!len || (*len != SQL_NULL_DATA &&
02884                            *len > SQL_LEN_DATA_AT_EXEC_OFFSET))) {
02885         setstat(s, -1, "invalid buffer", "HY003");
02886         return SQL_ERROR;
02887     }
02888     if (len && *len < 0 && *len > SQL_LEN_DATA_AT_EXEC_OFFSET &&
02889         *len != SQL_NTS && *len != SQL_NULL_DATA) {
02890         setstat(s, -1, "invalid length reference", "HY009");
02891         return SQL_ERROR;
02892     }
02893 #if 0
02894     if (iotype != SQL_PARAM_INPUT)
02895         return SQL_ERROR;
02896 #endif
02897     --pnum;
02898     if (s->bindparms) {
02899         if (pnum >= s->nbindparms) {
02900             BINDPARM *newparms;
02901             
02902             newparms = xrealloc(s->bindparms,
02903                                 (pnum + 1) * sizeof (BINDPARM));
02904             if (!newparms) {
02905 outofmem:
02906                 return nomem(s);
02907             }
02908             s->bindparms = newparms;
02909             memset(&s->bindparms[s->nbindparms], 0,
02910                    (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
02911             s->nbindparms = pnum + 1;
02912         }
02913     } else {
02914         int npar = max(10, pnum + 1);
02915 
02916         s->bindparms = xmalloc(npar * sizeof (BINDPARM));
02917         if (!s->bindparms) {
02918             goto outofmem;
02919         }
02920         memset(s->bindparms, 0, npar * sizeof (BINDPARM));
02921         s->nbindparms = npar;
02922     }
02923     p = &s->bindparms[pnum];
02924     p->type = buftype; 
02925     p->stype = ptype; 
02926     p->max = buflen;
02927     p->inc = buflen;
02928     p->lenp = (int *) len;
02929     p->offs = 0;
02930     p->len = 0;
02931     p->param0 = p->param = data;
02932     freep(&p->parbuf);
02933     p->param = p->param0;
02934     p->need = 0;
02935     if (p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
02936         p->need = 1;       
02937     }
02938     return SQL_SUCCESS;
02939 }
02940 #if NOOOOOOOO
02941     if (p->lenp) {
02942         if (buftype == SQL_C_CHAR) {
02943             if (*p->lenp == SQL_NTS) {
02944                 p->len = p->max = buflen = strlen(data);
02945             } else if (*p->lenp >= 0) {
02946                 p->len = p->max = buflen = *p->lenp;
02947             }
02948         } else if (buftype == SQL_C_BINARY) {
02949             p->len = p->max = buflen = *p->lenp;
02950         }
02951     }
02952     if (p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
02953         p->param = NULL;
02954         p->ind = p->param0;
02955         p->need = 1;
02956     } else if (p->lenp && *p->lenp == SQL_NULL_DATA) {
02957         p->param = NULL;
02958         p->ind = NULL;
02959         p->need = 0;
02960     } else {
02961         p->param = p->param0;
02962         p->ind = NULL;
02963         p->need = 0;
02964     }
02965     return SQL_SUCCESS;
02966 #endif
02967 
02983 SQLRETURN SQL_API
02984 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
02985                  SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
02986                  SQLSMALLINT scale,
02987                  SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
02988 {
02989     return drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
02990                         scale, data, buflen, len);
02991 }
02992 
03006 SQLRETURN SQL_API
03007 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
03008              SQLSMALLINT ptype, SQLULEN lenprec,
03009              SQLSMALLINT scale, SQLPOINTER val,
03010              SQLLEN *lenp)
03011 {
03012     return drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
03013                         lenprec, scale, val, 0, lenp);
03014 }
03015 
03023 SQLRETURN SQL_API
03024 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
03025 {
03026     STMT *s;
03027     SQLSMALLINT dummy;
03028 
03029     if (stmt == SQL_NULL_HSTMT) {
03030         return SQL_INVALID_HANDLE;
03031     }
03032     s = (STMT *) stmt;
03033     if (!nparam) {
03034         nparam = &dummy;
03035     }
03036     *nparam = s->nparams;
03037     return SQL_SUCCESS;
03038 }
03039 
03047 SQLRETURN SQL_API
03048 SQLParamData(SQLHSTMT stmt, SQLPOINTER *p)
03049 {
03050     STMT *s;
03051     int i;
03052     SQLPOINTER dummy;
03053 
03054     if (stmt == SQL_NULL_HSTMT) {
03055         return SQL_INVALID_HANDLE;
03056     }
03057     s = (STMT *) stmt;
03058     if (!p) {
03059         p = &dummy;
03060     }
03061     for (i = 0; i < s->nparams; i++) {
03062         if (s->bindparms[i].need > 0) {
03063             *p = (SQLPOINTER) s->bindparms[i].param0;
03064             return SQL_NEED_DATA;
03065         }
03066     }
03067     return drvexecute(stmt, 0);
03068 }
03069 
03081 SQLRETURN SQL_API
03082 SQLDescribeParam(SQLHSTMT stmt, UWORD pnum, SWORD *dtype, UDWORD *size,
03083                  SWORD *decdigits, SWORD *nullable)
03084 {
03085     STMT *s;
03086 
03087     if (stmt == SQL_NULL_HSTMT) {
03088         return SQL_INVALID_HANDLE;
03089     }
03090     s = (STMT *) stmt;
03091     --pnum;
03092     if (pnum >= s->nparams) {
03093         setstat(s, -1, "invalid parameter index",
03094                 (*s->ov3) ? "HY000" : "S1000");
03095         return SQL_ERROR;
03096     }
03097     if (dtype) {
03098 #ifdef SQL_LONGVARCHAR
03099         *dtype = SQL_LONGVARCHAR;
03100 #else
03101         *dtype = SQL_VARCHAR;
03102 #endif
03103     }
03104     if (size) {
03105 #ifdef SQL_LONGVARCHAR
03106         *size = 65536;
03107 #else
03108         *size = 255;
03109 #endif
03110     }
03111     if (decdigits) {
03112         *decdigits = 0;
03113     }
03114     if (nullable) {
03115         *nullable = SQL_NULLABLE;
03116     }
03117     return SQL_SUCCESS;
03118 }
03119 
03133 SQLRETURN SQL_API
03134 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
03135             SQLSMALLINT sqltype, SQLULEN coldef,
03136             SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
03137 {
03138     return drvbindparam(stmt, par, SQL_PARAM_INPUT,
03139                         type, sqltype, coldef, scale, val,
03140                         SQL_SETPARAM_VALUE_MAX, nval);
03141 }
03142 
03147 SQLRETURN SQL_API
03148 SQLParamOptions(SQLHSTMT stmt, UDWORD rows, UDWORD *rowp)
03149 {
03150     return drvunimplstmt(stmt);
03151 }
03152 
03157 SQLRETURN SQL_API
03158 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
03159                 SQLSMALLINT fieldid, SQLPOINTER value,
03160                 SQLINTEGER buflen, SQLINTEGER *strlen)
03161 {
03162     return SQL_ERROR;
03163 }
03164 
03169 SQLRETURN SQL_API
03170 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
03171                 SQLSMALLINT fieldid, SQLPOINTER value,
03172                 SQLINTEGER buflen)
03173 {
03174     return SQL_ERROR;
03175 }
03176 
03181 SQLRETURN SQL_API
03182 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
03183               SQLCHAR *name, SQLSMALLINT buflen,
03184               SQLSMALLINT *strlen, SQLSMALLINT *type,
03185               SQLSMALLINT *subtype, SQLLEN *len,
03186               SQLSMALLINT *prec, SQLSMALLINT *scale,
03187               SQLSMALLINT *nullable)
03188 {
03189     return SQL_ERROR;
03190 }
03191 
03196 SQLRETURN SQL_API
03197 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
03198               SQLSMALLINT type, SQLSMALLINT subtype,
03199               SQLLEN len, SQLSMALLINT prec,
03200               SQLSMALLINT scale, SQLPOINTER data,
03201               SQLLEN *strlen, SQLLEN *indicator)
03202 {
03203     return SQL_ERROR;
03204 }
03205 
03214 static SQLRETURN
03215 mkresultset(HSTMT stmt, COL *colspec, int ncols)
03216 {
03217     STMT *s;
03218     DBC *d;
03219 
03220     if (stmt == SQL_NULL_HSTMT) {
03221         return SQL_INVALID_HANDLE;
03222     }
03223     s = (STMT *) stmt;
03224     if (s->dbc == SQL_NULL_HDBC) {
03225 noconn:
03226         return noconn(s);
03227     }
03228     d = (DBC *) s->dbc;
03229     if (!d->sqlite) {
03230         goto noconn;
03231     }
03232     s3stmt_end_if(s);
03233     freeresult(s, 0);
03234     s->ncols = ncols;
03235     s->cols = colspec;
03236     mkbindcols(s, s->ncols);
03237     s->nrows = 0;
03238     s->rowp = -1;
03239     s->isselect = -1;
03240     return SQL_SUCCESS;
03241 }
03242 
03247 static COL tablePrivSpec[] = {
03248     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03249     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
03250     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
03251     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
03252     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
03253     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
03254     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
03255 };
03256 
03269 SQLRETURN SQL_API
03270 SQLTablePrivileges(SQLHSTMT stmt,
03271                    SQLCHAR *catalog, SQLSMALLINT catalogLen,
03272                    SQLCHAR *schema, SQLSMALLINT schemaLen,
03273                    SQLCHAR *table, SQLSMALLINT tableLen)
03274 {
03275     return mkresultset(stmt, tablePrivSpec, array_size(tablePrivSpec));
03276 }
03277 
03282 static COL colPrivSpec[] = {
03283     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03284     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
03285     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
03286     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
03287     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
03288     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
03289     { "SYSTEM", "COLPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
03290 };
03291 
03306 SQLRETURN SQL_API
03307 SQLColumnPrivileges(SQLHSTMT stmt,
03308                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
03309                     SQLCHAR *schema, SQLSMALLINT schemaLen,
03310                     SQLCHAR *table, SQLSMALLINT tableLen,
03311                     SQLCHAR *column, SQLSMALLINT columnLen)
03312 {
03313     return mkresultset(stmt, colPrivSpec, array_size(colPrivSpec));
03314 }
03315 
03320 static COL pkeySpec[] = {
03321     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03322     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
03323     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
03324     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
03325     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
03326     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
03327 };
03328 
03341 static SQLRETURN
03342 drvprimarykeys(SQLHSTMT stmt,
03343                SQLCHAR *cat, SQLSMALLINT catLen,
03344                SQLCHAR *schema, SQLSMALLINT schemaLen,
03345                SQLCHAR *table, SQLSMALLINT tableLen)
03346 {
03347     STMT *s;
03348     DBC *d;
03349     SQLRETURN sret;
03350     int i, size, ret, nrows, ncols, offs, namec, uniquec;
03351     char **rowp, *errp = NULL, *sql, tname[512];
03352 
03353     sret = mkresultset(stmt, pkeySpec, array_size(pkeySpec));
03354     if (sret != SQL_SUCCESS) {
03355         return sret;
03356     }
03357     s = (STMT *) stmt;
03358     d = (DBC *) s->dbc;
03359     if (!table || table[0] == '\0' || table[0] == '%') {
03360         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
03361         return SQL_ERROR;
03362     }
03363     if (tableLen == SQL_NTS) {
03364         size = sizeof (tname) - 1;
03365     } else {
03366         size = min(sizeof (tname) - 1, tableLen);
03367     }
03368     strncpy(tname, (char *) table, size);
03369     tname[size] = '\0';
03370     sql = sqlite3_mprintf("PRAGMA index_list('%q')", tname);
03371     if (!sql) {
03372         return nomem(s);
03373     }
03374     dbtraceapi(d, "sqlite3_get_table", sql);
03375     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
03376     sqlite3_free(sql);
03377     if (ret != SQLITE_OK) {
03378         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
03379                 errp ? errp : "unknown error", ret);
03380         if (errp) {
03381             sqlite3_free(errp);
03382             errp = NULL;
03383         }
03384         return SQL_ERROR;
03385     }
03386     if (errp) {
03387         sqlite3_free(errp);
03388         errp = NULL;
03389     }
03390     if (ncols * nrows <= 0) {
03391 nodata:
03392         sqlite3_free_table(rowp);
03393         /* try table_info for integer primary keys */
03394         ret = SQLITE_ERROR;
03395         sql = sqlite3_mprintf("PRAGMA table_info('%q')", tname);
03396         if (sql) {
03397             dbtraceapi(d, "sqlite3_get_table", sql);
03398             ret = sqlite3_get_table(d->sqlite, sql, &rowp,
03399                                     &nrows, &ncols, NULL);
03400             sqlite3_free(sql);
03401         }
03402         if (ret == SQLITE_OK) {
03403             int typec, roffs;
03404 
03405             namec = findcol(rowp, ncols, "name");
03406             uniquec = findcol(rowp, ncols, "pk");
03407             typec = findcol(rowp, ncols, "type");
03408             if (namec < 0 || uniquec < 0 || typec < 0) {
03409                 goto nodata2;
03410             }
03411             for (i = 1; i <= nrows; i++) {
03412                 if (*rowp[i * ncols + uniquec] != '0' &&
03413                     strlen(rowp[i * ncols + typec]) == 7 &&
03414                     strncasecmp(rowp[i * ncols + typec], "integer", 7) == 0) {
03415                     break;
03416                 }
03417             }
03418             if (i > nrows) {
03419                 goto nodata2;
03420             }
03421             size = (1 + 1) * array_size(pkeySpec);
03422             s->rows = xmalloc((size + 1) * sizeof (char *));
03423             if (!s->rows) {
03424                 s->nrows = 0;
03425                 return nomem(s);
03426             }
03427             s->rows[0] = (char *) size;
03428             s->rows += 1;
03429             memset(s->rows, 0, sizeof (char *) * size);
03430             s->rowfree = freerows;
03431             s->nrows = 1;
03432             roffs = s->ncols;
03433             s->rows[roffs + 0] = xstrdup("");
03434             s->rows[roffs + 1] = xstrdup("");
03435             s->rows[roffs + 2] = xstrdup(tname);
03436             s->rows[roffs + 3] = xstrdup(rowp[i * ncols + namec]);
03437             s->rows[roffs + 4] = xstrdup("1");
03438 nodata2:
03439             sqlite3_free_table(rowp);
03440         }
03441         return SQL_SUCCESS;
03442     }
03443     size = 0;
03444     namec = findcol(rowp, ncols, "name");
03445     uniquec = findcol(rowp, ncols, "unique");
03446     if (namec < 0 || uniquec < 0) {
03447         goto nodata;
03448     }
03449     for (i = 1; i <= nrows; i++) {
03450         int nnrows, nncols;
03451         char **rowpp;
03452 
03453         if (*rowp[i * ncols + uniquec] != '0') {
03454             ret = SQLITE_ERROR;
03455             sql = sqlite3_mprintf("PRAGMA index_info('%q')",
03456                                   rowp[i * ncols + namec]);
03457             if (sql) {
03458                 dbtraceapi(d, "sqlite3_get_table", sql);
03459                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
03460                                         &nnrows, &nncols, NULL);
03461                 sqlite3_free(sql);
03462             }
03463             if (ret == SQLITE_OK) {
03464                 size += nnrows;
03465                 sqlite3_free_table(rowpp);
03466             }
03467         }
03468     }
03469     if (size == 0) {
03470         goto nodata;
03471     }
03472     s->nrows = size;
03473     size = (size + 1) * array_size(pkeySpec);
03474     s->rows = xmalloc((size + 1) * sizeof (char *));
03475     if (!s->rows) {
03476         s->nrows = 0;
03477         return nomem(s);
03478     }
03479     s->rows[0] = (char *) size;
03480     s->rows += 1;
03481     memset(s->rows, 0, sizeof (char *) * size);
03482     s->rowfree = freerows;
03483     offs = 0;
03484     for (i = 1; i <= nrows; i++) {
03485         int nnrows, nncols;
03486         char **rowpp;
03487 
03488         if (*rowp[i * ncols + uniquec] != '0') {
03489             int k;
03490 
03491             ret = SQLITE_ERROR;
03492             sql = sqlite3_mprintf("PRAGMA index_info('%q')",
03493                                   rowp[i * ncols + namec]);
03494             if (sql) {
03495                 dbtraceapi(d, "sqlite3_get_table", sql);
03496                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
03497                                         &nnrows, &nncols, NULL);
03498                 sqlite3_free(sql);
03499             }
03500             if (ret != SQLITE_OK) {
03501                 continue;
03502             }
03503             for (k = 0; nnrows && k < nncols; k++) {
03504                 if (strcmp(rowpp[k], "name") == 0) {
03505                     int m;
03506 
03507                     for (m = 1; m <= nnrows; m++) {
03508                         int roffs = (offs + m) * s->ncols;
03509 
03510                         s->rows[roffs + 0] = xstrdup("");
03511                         s->rows[roffs + 1] = xstrdup("");
03512                         s->rows[roffs + 2] = xstrdup(tname);
03513                         s->rows[roffs + 3] = xstrdup(rowpp[m * nncols + k]);
03514                         s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
03515                     }
03516                 } else if (strcmp(rowpp[k], "seqno") == 0) {
03517                     int m;
03518 
03519                     for (m = 1; m <= nnrows; m++) {
03520                         int roffs = (offs + m) * s->ncols;
03521                         int pos = m - 1;
03522                         char buf[32];
03523 
03524                         sscanf(rowpp[m * nncols + k], "%d", &pos);
03525                         sprintf(buf, "%d", pos + 1);
03526                         s->rows[roffs + 4] = xstrdup(buf);
03527                     }
03528                 }
03529             }
03530             offs += nnrows;
03531             sqlite3_free_table(rowpp);
03532         }
03533     }
03534     sqlite3_free_table(rowp);
03535     return SQL_SUCCESS;
03536 }
03537 
03550 SQLRETURN SQL_API
03551 SQLPrimaryKeys(SQLHSTMT stmt,
03552                SQLCHAR *cat, SQLSMALLINT catLen,
03553                SQLCHAR *schema, SQLSMALLINT schemaLen,
03554                SQLCHAR *table, SQLSMALLINT tableLen)
03555 {
03556     return drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
03557                           table, tableLen);
03558 }
03559 
03564 static COL scolSpec[] = {
03565     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
03566     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
03567     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
03568     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
03569     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
03570     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
03571     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
03572     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
03573     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
03574 };
03575 
03591 static SQLRETURN
03592 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
03593                   SQLCHAR *cat, SQLSMALLINT catLen,
03594                   SQLCHAR *schema, SQLSMALLINT schemaLen,
03595                   SQLCHAR *table, SQLSMALLINT tableLen,
03596                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
03597 {
03598     STMT *s;
03599     DBC *d;
03600     SQLRETURN sret;
03601     int i, size, ret, nrows, ncols, nnnrows, nnncols, offs;
03602     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
03603     int notnullcc = -1, mkrowid = 0;
03604     char *errp = NULL, *sql, tname[512];
03605     char **rowp = NULL, **rowppp = NULL;
03606 
03607     sret = mkresultset(stmt, scolSpec, array_size(scolSpec));
03608     if (sret != SQL_SUCCESS) {
03609         return sret;
03610     }
03611     s = (STMT *) stmt;
03612     d = (DBC *) s->dbc;
03613     if (!table || table[0] == '\0' || table[0] == '%') {
03614         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
03615         return SQL_ERROR;
03616     }
03617     if (tableLen == SQL_NTS) {
03618         size = sizeof (tname) - 1;
03619     } else {
03620         size = min(sizeof (tname) - 1, tableLen);
03621     }
03622     strncpy(tname, (char *) table, size);
03623     tname[size] = '\0';
03624     if (id != SQL_BEST_ROWID) {
03625         return SQL_SUCCESS;
03626     }
03627     sql = sqlite3_mprintf("PRAGMA index_list('%q')", tname);
03628     if (!sql) {
03629         return nomem(s);
03630     }
03631     dbtraceapi(d, "sqlite3_get_table", sql);
03632     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
03633     sqlite3_free(sql);
03634     if (ret != SQLITE_OK) {
03635 doerr:
03636         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
03637                 errp ? errp : "unknown error", ret);
03638         if (errp) {
03639             sqlite3_free(errp);
03640             errp = NULL;
03641         }
03642         return SQL_ERROR;       
03643     }
03644     if (errp) {
03645         sqlite3_free(errp);
03646         errp = NULL;
03647     }
03648     size = 0; /* number result rows */
03649     if (ncols * nrows <= 0) {
03650         goto nodata_but_rowid;
03651     }
03652     sql = sqlite3_mprintf("PRAGMA table_info('%q')", tname);
03653     if (!sql) {
03654         return nomem(s);
03655     }
03656     dbtraceapi(d, "sqlite3_get_table", sql);
03657     ret = sqlite3_get_table(d->sqlite, sql, &rowppp, &nnnrows, &nnncols,
03658                             &errp);
03659     sqlite3_free(sql);
03660     if (ret != SQLITE_OK) {
03661         sqlite3_free_table(rowp);
03662         goto doerr;
03663     }
03664     if (errp) {
03665         sqlite3_free(errp);
03666         errp = NULL;
03667     }
03668     namec = findcol(rowp, ncols, "name");
03669     uniquec = findcol(rowp, ncols, "unique");
03670     if (namec < 0 || uniquec < 0) {
03671         goto nodata_but_rowid;
03672     }
03673     namecc = findcol(rowppp, nnncols, "name");
03674     typecc = findcol(rowppp, nnncols, "type");
03675     notnullcc = findcol(rowppp, nnncols, "notnull");
03676     for (i = 1; i <= nrows; i++) {
03677         int nnrows, nncols;
03678         char **rowpp = NULL;
03679 
03680         if (*rowp[i * ncols + uniquec] != '0') {
03681             ret = SQLITE_ERROR;
03682             sql = sqlite3_mprintf("PRAGMA index_info('%q')",
03683                                   rowp[i * ncols + namec]);
03684             if (sql) {
03685                 dbtraceapi(d, "sqlite3_get_table", sql);
03686                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
03687                                         &nnrows, &nncols, NULL);
03688                 sqlite3_free(sql);
03689             }
03690             if (ret == SQLITE_OK) {
03691                 size += nnrows;
03692                 sqlite3_free_table(rowpp);
03693             }
03694         }
03695     }
03696 nodata_but_rowid:
03697     if (size == 0) {
03698         size = 1;
03699         mkrowid = 1;
03700     }
03701     s->nrows = size;
03702     size = (size + 1) * array_size(scolSpec);
03703     s->rows = xmalloc((size + 1) * sizeof (char *));
03704     if (!s->rows) {
03705         s->nrows = 0;
03706         sqlite3_free_table(rowp);
03707         sqlite3_free_table(rowppp);
03708         return nomem(s);
03709     }
03710     s->rows[0] = (char *) size;
03711     s->rows += 1;
03712     memset(s->rows, 0, sizeof (char *) * size);
03713     s->rowfree = freerows;
03714     if (mkrowid) {
03715         s->nrows = 0;
03716         goto mkrowid;
03717     }
03718     offs = 0;
03719     for (i = 1; i <= nrows; i++) {
03720         int nnrows, nncols;
03721         char **rowpp = NULL;
03722 
03723         if (*rowp[i * ncols + uniquec] != '0') {
03724             int k;
03725 
03726             ret = SQLITE_ERROR;
03727             sql = sqlite3_mprintf("PRAGMA index_info('%q')",
03728                                   rowp[i * ncols + namec]);
03729             if (sql) {
03730                 dbtraceapi(d, "sqlite3_get_table", sql);
03731                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
03732                                         &nnrows, &nncols, NULL);
03733                 sqlite3_free(sql);
03734             }
03735             if (ret != SQLITE_OK) {
03736                 continue;
03737             }
03738             for (k = 0; nnrows && k < nncols; k++) {
03739                 if (strcmp(rowpp[k], "name") == 0) {
03740                     int m;
03741 
03742                     for (m = 1; m <= nnrows; m++) {
03743                         int roffs = (offs + m) * s->ncols;
03744 
03745                         s->rows[roffs + 0] =
03746                             xstrdup(stringify(SQL_SCOPE_SESSION));
03747                         s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
03748                         s->rows[roffs + 4] = xstrdup("0");
03749                         s->rows[roffs + 7] =
03750                             xstrdup(stringify(SQL_PC_NOT_PSEUDO));
03751                         if (namecc >= 0 && typecc >= 0) {
03752                             int ii;
03753 
03754                             for (ii = 1; ii <= nnnrows; ii++) {
03755                                 if (strcmp(rowppp[ii * nnncols + namecc],
03756                                            rowpp[m * nncols + k]) == 0) {
03757                                     char *typen = rowppp[ii * nnncols + typecc];
03758                                     int sqltype, mm, dd, isnullable = 0;
03759                                     char buf[32];
03760                                         
03761                                     s->rows[roffs + 3] = xstrdup(typen);
03762                                     sqltype = mapsqltype(typen, NULL, *s->ov3);
03763                                     getmd(typen, sqltype, &mm, &dd);
03764 #ifdef SQL_LONGVARCHAR
03765                                     if (sqltype == SQL_VARCHAR && mm > 255) {
03766                                         sqltype = SQL_LONGVARCHAR;
03767                                     }
03768 #endif
03769                                     if (sqltype == SQL_VARBINARY && mm > 255) {
03770                                         sqltype = SQL_LONGVARBINARY;
03771                                     }
03772                                     sprintf(buf, "%d", sqltype);
03773                                     s->rows[roffs + 2] = xstrdup(buf);
03774                                     sprintf(buf, "%d", mm);
03775                                     s->rows[roffs + 5] = xstrdup(buf);
03776                                     sprintf(buf, "%d", dd);
03777                                     s->rows[roffs + 6] = xstrdup(buf);
03778                                     if (notnullcc >= 0) {
03779                                         char *inp =
03780                                            rowppp[ii * nnncols + notnullcc];
03781 
03782                                         isnullable = inp[0] != '0';
03783                                     }
03784                                     sprintf(buf, "%d", isnullable);
03785                                     s->rows[roffs + 8] = xstrdup(buf);
03786                                 }
03787                             }
03788                         }
03789                     }
03790                 }
03791             }
03792             offs += nnrows;
03793             sqlite3_free_table(rowpp);
03794         }
03795     }
03796     if (nullable == SQL_NO_NULLS) {
03797         for (i = 1; i < s->nrows; i++) {
03798             if (s->rows[i * s->ncols + 8][0] == '0') {
03799                 int m, i1 = i + 1;
03800 
03801                 for (m = 0; m < s->ncols; m++) {
03802                     freep(&s->rows[i * s->ncols + m]);
03803                 }
03804                 size = s->ncols * sizeof (char *) * (s->nrows - i1);
03805                 if (size > 0) {
03806                     memmove(s->rows + i * s->ncols,
03807                             s->rows + i1 * s->ncols,
03808                             size);
03809                     memset(s->rows + s->nrows * s->ncols, 0,
03810                            s->ncols * sizeof (char *));
03811                 }
03812                 s->nrows--;
03813                 --i;
03814             }
03815         }
03816     }
03817 mkrowid:
03818     sqlite3_free_table(rowp);
03819     sqlite3_free_table(rowppp);
03820     if (s->nrows == 0) {
03821         s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
03822         s->rows[s->ncols + 1] = xstrdup("_ROWID_");
03823         s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
03824         s->rows[s->ncols + 3] = xstrdup("integer");
03825         s->rows[s->ncols + 4] = xstrdup("0");
03826         s->rows[s->ncols + 5] = xstrdup("10");
03827         s->rows[s->ncols + 6] = xstrdup("9");
03828         s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
03829         s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
03830         s->nrows = 1;
03831     }
03832     return SQL_SUCCESS;
03833 }
03834 
03850 SQLRETURN SQL_API
03851 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
03852                   SQLCHAR *cat, SQLSMALLINT catLen,
03853                   SQLCHAR *schema, SQLSMALLINT schemaLen,
03854                   SQLCHAR *table, SQLSMALLINT tableLen,
03855                   SQLUSMALLINT scope, SQLUSMALLINT nullable)
03856 {
03857     return drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
03858                              table, tableLen, scope, nullable);
03859 }
03860 
03865 static COL fkeySpec[] = {
03866     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03867     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
03868     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
03869     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
03870     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
03871     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
03872     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
03873     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
03874     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
03875     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
03876     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
03877     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
03878     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
03879     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
03880 };
03881 
03900 static SQLRETURN SQL_API
03901 drvforeignkeys(SQLHSTMT stmt,
03902                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
03903                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
03904                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
03905                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
03906                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
03907                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
03908 {
03909     STMT *s;
03910     DBC *d;
03911     SQLRETURN sret;
03912     int i, size, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
03913     char **rowp, *errp = NULL, *sql, pname[512], fname[512];
03914 
03915     sret = mkresultset(stmt, fkeySpec, array_size(fkeySpec));
03916     if (sret != SQL_SUCCESS) {
03917         return sret;
03918     }
03919     s = (STMT *) stmt;
03920     d = (DBC *) s->dbc;
03921     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
03922         (!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
03923         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
03924         return SQL_ERROR;
03925     }
03926     size = 0;
03927     if (PKtable) {
03928         if (PKtableLen == SQL_NTS) {
03929             size = sizeof (pname) - 1;
03930         } else {
03931             size = min(sizeof (pname) - 1, PKtableLen);
03932         }
03933         strncpy(pname, (char *) PKtable, size);
03934     }
03935     pname[size] = '\0';
03936     size = 0;
03937     if (FKtable) {
03938 
03939         if (FKtableLen == SQL_NTS) {
03940             size = sizeof (fname) - 1;
03941         } else {
03942             size = min(sizeof (fname) - 1, FKtableLen);
03943         }
03944         strncpy(fname, (char *) FKtable, size);
03945     }
03946     fname[size] = '\0';
03947     if (fname[0] != '\0') {
03948         int plen;
03949 
03950         ret = SQLITE_ERROR;
03951         sql = sqlite3_mprintf("PRAGMA foreign_key_list('%q')", fname);
03952         if (sql) {
03953             dbtraceapi(d, "sqlite3_get_table", sql);
03954             ret = sqlite3_get_table(d->sqlite, sql, &rowp,
03955                                     &nrows, &ncols, &errp);
03956             sqlite3_free(sql);
03957         }
03958         if (ret != SQLITE_OK) {
03959             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
03960                     errp ? errp : "unknown error", ret);
03961             if (errp) {
03962                 sqlite3_free(errp);
03963                 errp = NULL;
03964             }
03965             return SQL_ERROR;
03966         }
03967         if (errp) {
03968             sqlite3_free(errp);
03969             errp = NULL;
03970         }
03971         if (ncols * nrows <= 0) {
03972 nodata:
03973             sqlite3_free_table(rowp);
03974             return SQL_SUCCESS;
03975         }
03976         size = 0;
03977         namec = findcol(rowp, ncols, "table");
03978         seqc = findcol(rowp, ncols, "seq");
03979         fromc = findcol(rowp, ncols, "from");
03980         toc = findcol(rowp, ncols, "to");
03981         if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
03982             goto nodata;
03983         }
03984         plen = strlen(pname);
03985         for (i = 1; i <= nrows; i++) {
03986             char *ptab = rowp[i * ncols + namec];
03987 
03988             if (plen && ptab) {
03989                 int len = strlen(ptab);
03990 
03991                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
03992                     continue;
03993                 }
03994             }
03995             size++;
03996         }
03997         if (size == 0) {
03998             goto nodata;
03999         }
04000         s->nrows = size;
04001         size = (size + 1) * array_size(fkeySpec);
04002         s->rows = xmalloc((size + 1) * sizeof (char *));
04003         if (!s->rows) {
04004             s->nrows = 0;
04005             return nomem(s);
04006         }
04007         s->rows[0] = (char *) size;
04008         s->rows += 1;
04009         memset(s->rows, 0, sizeof (char *) * size);
04010         s->rowfree = freerows;
04011         offs = 0;
04012         for (i = 1; i <= nrows; i++) {
04013             int pos = 0, roffs = (offs + 1) * s->ncols;
04014             char *ptab = rowp[i * ncols + namec];
04015             char buf[32];
04016 
04017             if (plen && ptab) {
04018                 int len = strlen(ptab);
04019 
04020                 if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
04021                     continue;
04022                 }
04023             }
04024             s->rows[roffs + 0] = xstrdup("");
04025             s->rows[roffs + 1] = xstrdup("");
04026             s->rows[roffs + 2] = xstrdup(ptab);
04027             s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
04028             s->rows[roffs + 4] = xstrdup("");
04029             s->rows[roffs + 5] = xstrdup("");
04030             s->rows[roffs + 6] = xstrdup(fname);
04031             s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
04032             sscanf(rowp[i * ncols + seqc], "%d", &pos);
04033             sprintf(buf, "%d", pos + 1);
04034             s->rows[roffs + 8] = xstrdup(buf);
04035             s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
04036             s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
04037             s->rows[roffs + 11] = NULL;
04038             s->rows[roffs + 12] = NULL;
04039             s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
04040             offs++;
04041         }
04042         sqlite3_free_table(rowp);
04043     } else {
04044         int nnrows, nncols, plen = strlen(pname);
04045         char **rowpp;
04046 
04047         sql = "select name from sqlite_master where type='table'";
04048         dbtraceapi(d, "sqlite3_get_table", sql);
04049         ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
04050         if (ret != SQLITE_OK) {
04051             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
04052                     errp ? errp : "unknown error", ret);
04053             if (errp) {
04054                 sqlite3_free(errp);
04055                 errp = NULL;
04056             }
04057             return SQL_ERROR;
04058         }
04059         if (errp) {
04060             sqlite3_free(errp);
04061             errp = NULL;
04062         }
04063         if (ncols * nrows <= 0) {
04064             goto nodata;
04065         }
04066         size = 0;
04067         for (i = 1; i <= nrows; i++) {
04068             int k, len;
04069 
04070             if (!rowp[i]) {
04071                 continue;
04072             }
04073             len = strlen(rowp[i]);
04074             if (len == plen && strncasecmp(pname, rowp[i], plen) == 0) {
04075                 continue;
04076             }
04077             rowpp = NULL;
04078             ret = SQLITE_ERROR;
04079             sql = sqlite3_mprintf("PRAGMA foreign_key_list('%q')", rowp[i]);
04080             if (sql) {
04081                 dbtraceapi(d, "sqlite3_get_table", sql);
04082                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
04083                                       &nnrows, &nncols, NULL);
04084                 sqlite3_free(sql);
04085             }
04086             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
04087                 sqlite3_free_table(rowpp);
04088                 continue;
04089             }
04090             namec = findcol(rowpp, nncols, "table");
04091             seqc = findcol(rowpp, nncols, "seq");
04092             fromc = findcol(rowpp, nncols, "from");
04093             toc = findcol(rowpp, nncols, "to");
04094             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
04095                 sqlite3_free_table(rowpp);
04096                 continue;
04097             }
04098             for (k = 1; k <= nnrows; k++) {
04099                 char *ptab = rowpp[k * nncols + namec];
04100 
04101                 if (plen && ptab) {
04102                     len = strlen(ptab);
04103                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
04104                         continue;
04105                     }
04106                 }
04107                 size++;
04108             }
04109             sqlite3_free_table(rowpp);
04110         }
04111         if (size == 0) {
04112             goto nodata;
04113         }
04114         s->nrows = size;
04115         size = (size + 1) * array_size(fkeySpec);
04116         s->rows = xmalloc((size + 1) * sizeof (char *));
04117         if (!s->rows) {
04118             s->nrows = 0;
04119             return nomem(s);
04120         }
04121         s->rows[0] = (char *) size;
04122         s->rows += 1;
04123         memset(s->rows, 0, sizeof (char *) * size);
04124         s->rowfree = freerows;
04125         offs = 0;
04126         for (i = 1; i <= nrows; i++) {
04127             int k, len;
04128 
04129             if (!rowp[i]) {
04130                 continue;
04131             }
04132             len = strlen(rowp[i]);
04133             if (len == plen && strncasecmp(pname, rowp[i], plen) == 0) {
04134                 continue;
04135             }
04136             rowpp = NULL;
04137             ret = SQLITE_ERROR;
04138             sql = sqlite3_mprintf("PRAGMA foreign_key_list('%q')", rowp[i]);
04139             if (sql) {
04140                 dbtraceapi(d, "sqlite3_get_table", sql);
04141                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
04142                                         &nnrows, &nncols, NULL);
04143                 sqlite3_free(sql);
04144             }
04145             if (ret != SQLITE_OK || nncols * nnrows <= 0) {
04146                 sqlite3_free_table(rowpp);
04147                 continue;
04148             }
04149             namec = findcol(rowpp, nncols, "table");
04150             seqc = findcol(rowpp, nncols, "seq");
04151             fromc = findcol(rowpp, nncols, "from");
04152             toc = findcol(rowpp, nncols, "to");
04153             if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
04154                 sqlite3_free_table(rowpp);
04155                 continue;
04156             }
04157             for (k = 1; k <= nnrows; k++) {
04158                 int pos = 0, roffs = (offs + 1) * s->ncols;
04159                 char *ptab = rowpp[k * nncols + namec];
04160                 char buf[32];
04161 
04162                 if (plen && ptab) {
04163                     len = strlen(ptab);
04164                     if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
04165                         continue;
04166                     }
04167                 }
04168                 s->rows[roffs + 0] = xstrdup("");
04169                 s->rows[roffs + 1] = xstrdup("");
04170                 s->rows[roffs + 2] = xstrdup(ptab);
04171                 s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
04172                 s->rows[roffs + 4] = xstrdup("");
04173                 s->rows[roffs + 5] = xstrdup("");
04174                 s->rows[roffs + 6] = xstrdup(rowp[i]);
04175                 s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
04176                 sscanf(rowpp[k * nncols + seqc], "%d", &pos);
04177                 sprintf(buf, "%d", pos + 1);
04178                 s->rows[roffs + 8] = xstrdup(buf);
04179                 s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
04180                 s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
04181                 s->rows[roffs + 11] = NULL;
04182                 s->rows[roffs + 12] = NULL;
04183                 s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
04184                 offs++;
04185             }
04186             sqlite3_free_table(rowpp);
04187         }
04188         sqlite3_free_table(rowp);
04189     }
04190     return SQL_SUCCESS;
04191 }
04192 
04211 SQLRETURN SQL_API
04212 SQLForeignKeys(SQLHSTMT stmt,
04213                SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
04214                SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
04215                SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
04216                SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
04217                SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
04218                SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
04219 {
04220     return drvforeignkeys(stmt,
04221                           PKcatalog, PKcatalogLen,
04222                           PKschema, PKschemaLen, PKtable, PKtableLen,
04223                           FKcatalog, FKcatalogLen,
04224                           FKschema, FKschemaLen,
04225                           FKtable, FKtableLen);
04226 }
04227 
04235 static SQLRETURN
04236 endtran(DBC *d, SQLSMALLINT comptype)
04237 {
04238     int fail = 0, ret, busy_count = 0;
04239     char *sql, *errp = NULL;
04240 
04241     if (!d->sqlite) {
04242         setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
04243         return SQL_ERROR;
04244     }
04245     if (d->autocommit || !d->intrans) {
04246         return SQL_SUCCESS;
04247     }
04248     switch (comptype) {
04249     case SQL_COMMIT:
04250         sql = "COMMIT TRANSACTION";
04251         goto doit;
04252     case SQL_ROLLBACK:
04253     rollback:
04254         sql = "ROLLBACK TRANSACTION";
04255     doit:
04256         ret = sqlite3_exec(d->sqlite, sql, NULL, NULL, &errp);
04257         dbtracerc(d, ret, errp);
04258         if (ret == SQLITE_BUSY && !fail && comptype == SQL_COMMIT) {
04259             if (busy_handler((void *) d, ++busy_count)) {
04260                 if (errp) {
04261                     sqlite3_free(errp);
04262                     errp = NULL;
04263                 }
04264                 goto doit;
04265             }
04266         }
04267         d->intrans = 0;
04268         if (ret != SQLITE_OK) {
04269             if (!fail) {
04270                 setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
04271                          errp ? errp : "transaction failed");
04272                 if (errp) {
04273                     sqlite3_free(errp);
04274                     errp = NULL;
04275                 }
04276                 fail = 1;
04277                 goto rollback;
04278             }
04279             if (errp) {
04280                 sqlite3_free(errp);
04281                 errp = NULL;
04282             }
04283             return SQL_ERROR;
04284         }
04285         if (errp) {
04286             sqlite3_free(errp);
04287             errp = NULL;
04288         }
04289         return SQL_SUCCESS;
04290     }
04291     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
04292     return SQL_ERROR;
04293 }
04294 
04303 static SQLRETURN
04304 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
04305 {
04306     DBC *d;
04307     int fail = 0;
04308 
04309     switch (type) {
04310     case SQL_HANDLE_DBC:
04311         if (handle == SQL_NULL_HDBC) {
04312             return SQL_INVALID_HANDLE;
04313         }
04314         d = (DBC *) handle;
04315         return endtran(d, comptype);
04316     case SQL_HANDLE_ENV:
04317         if (handle == SQL_NULL_HENV) {
04318             return SQL_INVALID_HANDLE;
04319         }
04320         d = ((ENV *) handle)->dbcs;
04321         while (d) {
04322             SQLRETURN ret;
04323 
04324             ret = endtran(d, comptype);
04325             if (ret != SQL_SUCCESS) {
04326                 fail++;
04327                 comptype = SQL_ROLLBACK;
04328             }
04329             d = d->next;
04330         }
04331         return fail ? SQL_ERROR : SQL_SUCCESS;
04332     }
04333     return SQL_INVALID_HANDLE;
04334 }
04335 
04344 SQLRETURN SQL_API
04345 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
04346 {
04347     return drvendtran(type, handle, comptype);
04348 }
04349 
04358 SQLRETURN SQL_API
04359 SQLTransact(SQLHENV env, SQLHDBC dbc, UWORD type)
04360 {
04361     if (env != SQL_NULL_HENV) {
04362         return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
04363     }
04364     return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
04365 }
04366 
04371 SQLRETURN SQL_API
04372 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
04373 {
04374     return SQL_ERROR;
04375 }
04376 
04388 SQLRETURN SQL_API
04389 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
04390              SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
04391 {
04392     int outLen = 0;
04393 
04394     if (sqlinLen == SQL_NTS) {
04395         sqlinLen = strlen((char *) sqlin);
04396     }
04397     if (sql) {
04398         if (sqlMax > 0) {
04399             strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
04400             sqlin[sqlMax - 1] = '\0';
04401             outLen = min(sqlMax - 1, sqlinLen);
04402         }
04403     } else {
04404         outLen = sqlinLen;
04405     }
04406     if (sqlLen) {
04407         *sqlLen = outLen;
04408     }
04409     if (sql && outLen < sqlinLen) {
04410         setstat((STMT *) stmt, -1, "data right truncated", "01004");
04411         return SQL_SUCCESS_WITH_INFO;
04412     }
04413     return SQL_SUCCESS;
04414 }
04415 
04420 static COL procSpec[] = {
04421     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
04422     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
04423     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
04424     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
04425     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
04426     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
04427     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
04428     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
04429 };
04430 
04443 SQLRETURN SQL_API
04444 SQLProcedures(SQLHSTMT stmt,
04445               SQLCHAR *catalog, SQLSMALLINT catalogLen,
04446               SQLCHAR *schema, SQLSMALLINT schemaLen,
04447               SQLCHAR *proc, SQLSMALLINT procLen)
04448 {
04449     return mkresultset(stmt, procSpec, array_size(procSpec));
04450 }
04451 
04456 static COL procColSpec[] = {
04457     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
04458     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
04459     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
04460     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
04461     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
04462     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
04463     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
04464     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
04465     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
04466     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
04467     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
04468     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
04469     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
04470     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
04471     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
04472     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
04473     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
04474     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
04475     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
04476 };
04477 
04492 SQLRETURN SQL_API
04493 SQLProcedureColumns(SQLHSTMT stmt,
04494                     SQLCHAR *catalog, SQLSMALLINT catalogLen,
04495                     SQLCHAR *schema, SQLSMALLINT schemaLen,
04496                     SQLCHAR *proc, SQLSMALLINT procLen,
04497                     SQLCHAR *column, SQLSMALLINT columnLen)
04498 {
04499     return mkresultset(stmt, procColSpec, array_size(procColSpec));
04500 
04501 }
04502 
04513 SQLRETURN SQL_API
04514 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
04515               SQLINTEGER len, SQLINTEGER *lenp)
04516 {
04517     ENV *e;
04518 
04519     if (env == SQL_NULL_HENV) {
04520         return SQL_INVALID_HANDLE;
04521     }
04522     e = (ENV *) env;
04523     if (!e || e->magic != ENV_MAGIC) {
04524         return SQL_INVALID_HANDLE;
04525     }
04526     switch (attr) {
04527     case SQL_ATTR_CONNECTION_POOLING:
04528         return SQL_ERROR;
04529     case SQL_ATTR_CP_MATCH:
04530         return SQL_NO_DATA;
04531     case SQL_ATTR_OUTPUT_NTS:
04532         if (val) {
04533             *((SQLINTEGER *) val) = SQL_TRUE;
04534         }
04535         if (lenp) {
04536             *lenp = sizeof (SQLINTEGER);
04537         }
04538         return SQL_SUCCESS;
04539     case SQL_ATTR_ODBC_VERSION:
04540         if (val) {
04541             *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
04542         }
04543         if (lenp) {
04544             *lenp = sizeof (SQLINTEGER);
04545         }
04546         return SQL_SUCCESS;
04547     }
04548     return SQL_ERROR;
04549 }
04550 
04560 SQLRETURN SQL_API
04561 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
04562 {
04563     ENV *e;
04564 
04565     if (env == SQL_NULL_HENV) {
04566         return SQL_INVALID_HANDLE;
04567     }
04568     e = (ENV *) env;
04569     if (!e || e->magic != ENV_MAGIC) {
04570         return SQL_INVALID_HANDLE;
04571     }
04572     switch (attr) {
04573     case SQL_ATTR_CONNECTION_POOLING:
04574         return SQL_SUCCESS;
04575     case SQL_ATTR_CP_MATCH:
04576         return SQL_NO_DATA;
04577     case SQL_ATTR_OUTPUT_NTS:
04578         if ((SQLINTEGER) val == SQL_TRUE) {
04579             return SQL_SUCCESS;
04580         }
04581         return SQL_ERROR;
04582     case SQL_ATTR_ODBC_VERSION:
04583         if (!val) {
04584             return SQL_ERROR;
04585         }
04586         if ((SQLINTEGER) val == SQL_OV_ODBC2) {
04587             e->ov3 = 0;
04588             return SQL_SUCCESS;
04589         }
04590         if ((SQLINTEGER) val == SQL_OV_ODBC3) {
04591             e->ov3 = 1;
04592             return SQL_SUCCESS;
04593         }
04594         return SQL_ERROR;
04595     }
04596     return SQL_ERROR;
04597 }
04598 
04612 static SQLRETURN
04613 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
04614               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
04615               SQLSMALLINT buflen, SQLSMALLINT *msglen)
04616 {
04617     DBC *d = NULL;
04618     STMT *s = NULL;
04619     int len, naterr;
04620     char *logmsg, *sqlst;
04621 
04622     if (handle == SQL_NULL_HANDLE) {
04623         return SQL_INVALID_HANDLE;
04624     }
04625     if (sqlstate) {
04626         sqlstate[0] = '\0';
04627     }
04628     if (msg && buflen > 0) {
04629         msg[0] = '\0';
04630     }
04631     if (msglen) {
04632         *msglen = 0;
04633     }
04634     if (nativeerr) {
04635         *nativeerr = 0;
04636     }
04637     switch (htype) {
04638     case SQL_HANDLE_ENV:
04639     case SQL_HANDLE_DESC:
04640         return SQL_NO_DATA;
04641     case SQL_HANDLE_DBC:
04642         d = (DBC *) handle;
04643         logmsg = (char *) d->logmsg;
04644         sqlst = d->sqlstate;
04645         naterr = d->naterr;
04646         break;
04647     case SQL_HANDLE_STMT:
04648         s = (STMT *) handle;
04649         logmsg = (char *) s->logmsg;
04650         sqlst = s->sqlstate;
04651         naterr = s->naterr;
04652         break;
04653     default:
04654         return SQL_INVALID_HANDLE;
04655     }
04656     if (buflen < 0) {
04657         return SQL_ERROR;
04658     }
04659     if (recno > 1) {
04660         return SQL_NO_DATA;
04661     }
04662     len = strlen(logmsg);
04663     if (len == 0) {
04664         return SQL_NO_DATA;
04665     }
04666     if (nativeerr) {
04667         *nativeerr = naterr;
04668     }
04669     if (sqlstate) {
04670         strcpy((char *) sqlstate, sqlst);
04671     }
04672     if (msglen) {
04673         *msglen = len;
04674     }
04675     if (len >= buflen) {
04676         if (msg && buflen > 0) {
04677             strncpy((char *) msg, logmsg, buflen);
04678             msg[buflen - 1] = '\0';
04679             logmsg[0] = '\0';
04680         }
04681     } else if (msg) {
04682         strcpy((char *) msg, logmsg);
04683         logmsg[0] = '\0';
04684     }
04685     return SQL_SUCCESS;
04686 }
04687 
04701 SQLRETURN SQL_API
04702 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
04703               SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
04704               SQLSMALLINT buflen, SQLSMALLINT *msglen)
04705 {
04706     return drvgetdiagrec(htype, handle, recno, sqlstate,
04707                          nativeerr, msg, buflen, msglen);
04708 }
04709 
04714 SQLRETURN SQL_API
04715 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
04716                 SQLSMALLINT id, SQLPOINTER info, 
04717                 SQLSMALLINT buflen, SQLSMALLINT *strlen)
04718 {
04719     return SQL_ERROR;
04720 }
04721 
04732 static SQLRETURN
04733 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
04734                SQLINTEGER bufmax, SQLINTEGER *buflen)
04735 {
04736     STMT *s = (STMT *) stmt;
04737     SQLUINTEGER *uval = (SQLUINTEGER *) val;
04738 
04739     switch (attr) {
04740     case SQL_QUERY_TIMEOUT:
04741         *uval = 0;
04742         return SQL_SUCCESS;
04743     case SQL_ATTR_CURSOR_TYPE:
04744         *uval = s->curtype;
04745         return SQL_SUCCESS;
04746     case SQL_ATTR_CURSOR_SCROLLABLE:
04747         *uval = s->curtype != SQL_CURSOR_FORWARD_ONLY ?
04748             SQL_SCROLLABLE : SQL_NONSCROLLABLE;
04749         return SQL_SUCCESS;
04750 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
04751     case SQL_ATTR_CURSOR_SENSITIVITY:
04752         *uval = SQL_UNSPECIFIED;
04753         return SQL_SUCCESS;
04754 #endif
04755     case SQL_ATTR_ROW_NUMBER:
04756         {
04757             STMT *s = (STMT *) stmt;
04758             DBC *d = (DBC *) s->dbc;
04759 
04760             if (s == d->cur_s3stmt) {
04761                 *uval = d->s3stmt_rownum < 0 ?
04762                     SQL_ROW_NUMBER_UNKNOWN : d->s3stmt_rownum;
04763             }
04764         }
04765         *uval = s->rowp < 0 ? SQL_ROW_NUMBER_UNKNOWN : s->rowp;
04766         return SQL_SUCCESS;
04767     case SQL_ATTR_ASYNC_ENABLE:
04768         *uval = SQL_ASYNC_ENABLE_OFF;
04769         return SQL_SUCCESS;
04770     case SQL_CONCURRENCY:
04771         *uval = SQL_CONCUR_LOCK;
04772         return SQL_SUCCESS;
04773     case SQL_ATTR_RETRIEVE_DATA:
04774         *uval = s->retr_data;
04775         return SQL_SUCCESS;
04776     case SQL_ROWSET_SIZE:
04777     case SQL_ATTR_ROW_ARRAY_SIZE:
04778         *uval = s->rowset_size;
04779         return SQL_SUCCESS;
04780     /* Needed for some driver managers, but dummies for now */
04781     case SQL_ATTR_IMP_ROW_DESC:
04782     case SQL_ATTR_APP_ROW_DESC:
04783     case SQL_ATTR_IMP_PARAM_DESC:
04784     case SQL_ATTR_APP_PARAM_DESC:
04785         *((SQLHDESC *) val) = (SQLHDESC) DEAD_MAGIC;
04786         return SQL_SUCCESS;
04787     case SQL_ATTR_ROW_STATUS_PTR:
04788         *((SQLUSMALLINT **) val) = s->row_status;
04789         return SQL_SUCCESS;
04790     case SQL_ATTR_ROWS_FETCHED_PTR:
04791         *((SQLUINTEGER **) val) = s->row_count;
04792         return SQL_SUCCESS;
04793     case SQL_ATTR_USE_BOOKMARKS: {
04794         STMT *s = (STMT *) stmt;
04795 
04796         *(SQLUINTEGER *) val = s->bkmrk ? SQL_UB_ON : SQL_UB_OFF;
04797         return SQL_SUCCESS;
04798     }
04799     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
04800         *((SQLUINTEGER **) val) = s->parm_bind_offs;
04801         return SQL_SUCCESS;
04802     case SQL_ATTR_PARAM_BIND_TYPE:
04803         *((SQLUINTEGER *) val) = SQL_PARAM_BIND_BY_COLUMN;
04804         return SQL_SUCCESS;
04805     case SQL_ATTR_PARAM_OPERATION_PTR:
04806         *((SQLUSMALLINT **) val) = s->parm_oper;
04807         return SQL_SUCCESS;
04808     case SQL_ATTR_PARAM_STATUS_PTR:
04809         *((SQLUSMALLINT **) val) = s->parm_status;
04810         return SQL_SUCCESS;
04811     case SQL_ATTR_PARAMS_PROCESSED_PTR:
04812         *((SQLUINTEGER **) val) = s->parm_proc;
04813         return SQL_SUCCESS;
04814     case SQL_ATTR_PARAMSET_SIZE:
04815         *((SQLUINTEGER *) val) = s->paramset_size;
04816         return SQL_SUCCESS;
04817     case SQL_ATTR_ROW_BIND_TYPE:
04818         *(SQLUINTEGER *) val = s->bind_type;
04819         return SQL_SUCCESS;
04820     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
04821         *((SQLUINTEGER **) val) = s->bind_offs;
04822         return SQL_SUCCESS;
04823     case SQL_ATTR_MAX_ROWS:
04824     case SQL_ATTR_MAX_LENGTH:
04825         *((SQLINTEGER *) val) = 1000000000;
04826         return SQL_SUCCESS;
04827     }
04828     return drvunimplstmt(stmt);
04829 }
04830 
04841 SQLRETURN SQL_API
04842 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
04843                SQLINTEGER bufmax, SQLINTEGER *buflen)
04844 {
04845     return drvgetstmtattr(stmt, attr, val, bufmax, buflen);
04846 }
04847 
04857 static SQLRETURN
04858 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
04859                SQLINTEGER buflen)
04860 {
04861     STMT *s = (STMT *) stmt;
04862 
04863     switch (attr) {
04864     case SQL_ATTR_CURSOR_TYPE:
04865         if ((SQLUINTEGER) val == SQL_CURSOR_FORWARD_ONLY) {
04866             s->curtype = SQL_CURSOR_FORWARD_ONLY;
04867         } else {
04868             s->curtype = SQL_CURSOR_STATIC;
04869         }
04870         if ((SQLUINTEGER) val != SQL_CURSOR_FORWARD_ONLY &&
04871             (SQLUINTEGER) val != SQL_CURSOR_STATIC) {
04872             goto e01s02;
04873         }
04874         return SQL_SUCCESS;
04875     case SQL_ATTR_CURSOR_SCROLLABLE:
04876         if ((SQLUINTEGER) val == SQL_NONSCROLLABLE) {
04877             s->curtype = SQL_CURSOR_FORWARD_ONLY;
04878         } else {
04879             s->curtype = SQL_CURSOR_STATIC;
04880         }
04881         return SQL_SUCCESS;
04882     case SQL_ATTR_ASYNC_ENABLE:
04883         if ((SQLUINTEGER) val != SQL_ASYNC_ENABLE_OFF) {
04884     e01s02:
04885             setstat(s, -1, "option value changed", "01S02");
04886             return SQL_SUCCESS_WITH_INFO;
04887         }
04888         return SQL_SUCCESS;
04889     case SQL_CONCURRENCY:
04890         if ((SQLUINTEGER) val != SQL_CONCUR_LOCK) {
04891             goto e01s02;
04892         }
04893         return SQL_SUCCESS;
04894     case SQL_ATTR_QUERY_TIMEOUT:
04895         return SQL_SUCCESS;
04896     case SQL_ATTR_RETRIEVE_DATA:
04897         if ((SQLUINTEGER) val != SQL_RD_ON &&
04898             (SQLUINTEGER) val != SQL_RD_OFF) {
04899             goto e01s02;
04900         }
04901         s->retr_data = (int) val;
04902         return SQL_SUCCESS;
04903     case SQL_ROWSET_SIZE:
04904     case SQL_ATTR_ROW_ARRAY_SIZE:
04905         if ((SQLUINTEGER) val < 1) {
04906             setstat(s, -1, "invalid rowset size", "HY000");
04907             return SQL_ERROR;
04908         } else {
04909             SQLUSMALLINT *rst = &s->row_status1;
04910 
04911             if ((SQLUINTEGER) val > 1) {
04912                 rst = xmalloc(sizeof (SQLUSMALLINT) * (SQLUINTEGER) val);
04913                 if (!rst) {
04914                     return nomem(s);
04915                 }
04916             }
04917             if (s->row_status0 != &s->row_status1) {
04918                 freep(&s->row_status0);
04919             }
04920             s->row_status0 = rst;
04921             s->rowset_size = (SQLUINTEGER) val;
04922         }
04923         return SQL_SUCCESS;
04924     case SQL_ATTR_ROW_STATUS_PTR:
04925         s->row_status = (SQLUSMALLINT *) val;
04926         return SQL_SUCCESS;
04927     case SQL_ATTR_ROWS_FETCHED_PTR:
04928         s->row_count = (SQLUINTEGER *) val;
04929         return SQL_SUCCESS;
04930     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
04931         s->parm_bind_offs = (SQLUINTEGER *) val;
04932         return SQL_SUCCESS;
04933     case SQL_ATTR_PARAM_BIND_TYPE:
04934         if ((SQLUINTEGER) val != SQL_PARAM_BIND_BY_COLUMN) {
04935             goto e01s02;
04936         }
04937         return SQL_SUCCESS;
04938     case SQL_ATTR_PARAM_OPERATION_PTR:
04939         s->parm_oper = (SQLUSMALLINT *) val;
04940         return SQL_SUCCESS;
04941     case SQL_ATTR_PARAM_STATUS_PTR:
04942         s->parm_status = (SQLUSMALLINT *) val;
04943         return SQL_SUCCESS;
04944     case SQL_ATTR_PARAMS_PROCESSED_PTR:
04945         s->parm_proc = (SQLUINTEGER *) val;
04946         return SQL_SUCCESS;
04947     case SQL_ATTR_PARAMSET_SIZE:
04948         if ((SQLUINTEGER) val < 1) {
04949             goto e01s02;
04950         }
04951         s->paramset_size = (SQLUINTEGER) val;
04952         s->paramset_count = 0;
04953         return SQL_SUCCESS;
04954     case SQL_ATTR_ROW_BIND_TYPE:
04955         s->bind_type = (SQLUINTEGER) val;
04956         return SQL_SUCCESS;
04957     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
04958         s->bind_offs = (SQLUINTEGER *) val;
04959         return SQL_SUCCESS;
04960     case SQL_ATTR_USE_BOOKMARKS:
04961         if ((SQLUINTEGER) val != SQL_UB_OFF &&
04962             (SQLUINTEGER) val != SQL_UB_ON) {
04963             goto e01s02;
04964         }
04965         s->bkmrk = (SQLUINTEGER) val == SQL_UB_ON;
04966         return SQL_SUCCESS;
04967     case SQL_ATTR_MAX_ROWS:
04968     case SQL_ATTR_MAX_LENGTH:
04969         if ((SQLINTEGER) val != 1000000000) {
04970             goto e01s02;
04971         }
04972         return SQL_SUCCESS;
04973     }
04974     return drvunimplstmt(stmt);
04975 }
04976 
04986 SQLRETURN SQL_API
04987 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
04988                SQLINTEGER buflen)
04989 {
04990     return drvsetstmtattr(stmt, attr, val, buflen);
04991 }
04992 
05001 static SQLRETURN
05002 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
05003 {
05004     STMT *s = (STMT *) stmt;
05005     SQLUINTEGER *ret = (SQLUINTEGER *) param;
05006 
05007     switch (opt) {
05008     case SQL_QUERY_TIMEOUT:
05009         *ret = 0;
05010         return SQL_SUCCESS;
05011     case SQL_CURSOR_TYPE:
05012         *ret = s->curtype;
05013         return SQL_SUCCESS;
05014     case SQL_ROW_NUMBER:
05015         {
05016             DBC *d = (DBC *) s->dbc;
05017 
05018             if (s == d->cur_s3stmt) {
05019                 *ret = d->s3stmt_rownum < 0 ?
05020                     SQL_ROW_NUMBER_UNKNOWN : d->s3stmt_rownum;
05021             }
05022         }
05023         *ret = s->rowp < 0 ? SQL_ROW_NUMBER_UNKNOWN : s->rowp;
05024         return SQL_SUCCESS;
05025     case SQL_ASYNC_ENABLE:
05026         *ret = SQL_ASYNC_ENABLE_OFF;
05027         return SQL_SUCCESS;
05028     case SQL_CONCURRENCY:
05029         *ret = SQL_CONCUR_LOCK;
05030         return SQL_SUCCESS;
05031     case SQL_ATTR_RETRIEVE_DATA:
05032         *ret = s->retr_data;
05033         return SQL_SUCCESS;
05034     case SQL_ROWSET_SIZE:
05035     case SQL_ATTR_ROW_ARRAY_SIZE:
05036         *ret = s->rowset_size;
05037         return SQL_SUCCESS;
05038     case SQL_ATTR_MAX_ROWS:
05039     case SQL_ATTR_MAX_LENGTH:
05040         *ret = 1000000000;
05041         return SQL_SUCCESS;
05042     }
05043     return drvunimplstmt(stmt);
05044 }
05045 
05054 SQLRETURN SQL_API
05055 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
05056 {
05057     return drvgetstmtoption(stmt, opt, param);
05058 }
05059 
05068 static SQLRETURN
05069 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
05070 {
05071     STMT *s = (STMT *) stmt;
05072 
05073     switch (opt) {
05074     case SQL_CURSOR_TYPE:
05075         if (param == SQL_CURSOR_FORWARD_ONLY) {
05076             s->curtype = param;
05077         } else {
05078             s->curtype = SQL_CURSOR_STATIC;
05079         }
05080         if (param != SQL_CURSOR_FORWARD_ONLY &&
05081             param != SQL_CURSOR_STATIC) {
05082             goto e01s02;
05083         }
05084         return SQL_SUCCESS;
05085     case SQL_ASYNC_ENABLE:
05086         if (param != SQL_ASYNC_ENABLE_OFF) {
05087             goto e01s02;
05088         }
05089         return SQL_SUCCESS;
05090     case SQL_CONCURRENCY:
05091         if (param != SQL_CONCUR_LOCK) {
05092             goto e01s02;
05093         }
05094         return SQL_SUCCESS;
05095     case SQL_QUERY_TIMEOUT:
05096         return SQL_SUCCESS;
05097     case SQL_RETRIEVE_DATA:
05098         if (param != SQL_RD_ON && param != SQL_RD_OFF) {
05099     e01s02:
05100             setstat(s, -1, "option value changed", "01S02");
05101             return SQL_SUCCESS_WITH_INFO;
05102         }
05103         s->retr_data = (int) param;
05104         return SQL_SUCCESS;
05105     case SQL_ROWSET_SIZE:
05106     case SQL_ATTR_ROW_ARRAY_SIZE:
05107         if (param < 1) {
05108             setstat(s, -1, "invalid rowset size", "HY000");
05109             return SQL_ERROR;
05110         } else {
05111             SQLUSMALLINT *rst = &s->row_status1;
05112 
05113             if (param > 1) {
05114                 rst = xmalloc(sizeof (SQLUSMALLINT) * param);
05115                 if (!rst) {
05116                     return nomem(s);
05117                 }
05118             }
05119             if (s->row_status0 != &s->row_status1) {
05120                 freep(&s->row_status0);
05121             }
05122             s->row_status0 = rst;
05123             s->rowset_size = param;
05124         }
05125         return SQL_SUCCESS;
05126     case SQL_ATTR_MAX_ROWS:
05127     case SQL_ATTR_MAX_LENGTH:
05128         if (param != 1000000000) {
05129             goto e01s02;
05130         }
05131         return SQL_SUCCESS;
05132     }
05133     return drvunimplstmt(stmt);
05134 }
05135 
05144 SQLRETURN SQL_API
05145 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLROWCOUNT param)
05146 {
05147     return drvsetstmtoption(stmt, opt, param);
05148 }
05149 
05154 SQLRETURN SQL_API
05155 SQLSetPos(SQLHSTMT stmt, SQLUSMALLINT row, SQLUSMALLINT op, SQLUSMALLINT lock)
05156 {
05157     return drvunimplstmt(stmt);
05158 }
05159 
05164 SQLRETURN SQL_API
05165 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
05166                     SQLUSMALLINT rowset)
05167 {
05168     return drvunimplstmt(stmt);
05169 }
05170 
05171 #define strmak(dst, src, max, lenp) { \
05172     int len = strlen(src); \
05173     int cnt = min(len + 1, max); \
05174     strncpy(dst, src, cnt); \
05175     *lenp = (cnt > len) ? len : cnt; \
05176 }
05177 
05188 static SQLRETURN
05189 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
05190            SQLSMALLINT *valLen)
05191 {
05192     DBC *d;
05193     char dummyc[16];
05194     SQLSMALLINT dummy;
05195     static char drvname[] =
05196 #ifdef _WIN32
05197         "sqlite3odbc.dll";
05198 #else
05199         "sqlite3odbc.so";
05200 #endif
05201 
05202     if (dbc == SQL_NULL_HDBC) {
05203         return SQL_INVALID_HANDLE;
05204     }
05205     d = (DBC *) dbc;
05206     if (valMax) {
05207         valMax--;
05208     }
05209     if (!valLen) {
05210         valLen = &dummy;
05211     }
05212     if (!val) {
05213         val = dummyc;
05214         valMax = sizeof (dummyc) - 1;
05215     }
05216     switch (type) {
05217     case SQL_MAX_USER_NAME_LEN:
05218         *((SQLSMALLINT *) val) = 16;
05219         *valLen = sizeof (SQLSMALLINT);
05220         break;
05221     case SQL_USER_NAME:
05222         strmak(val, "", valMax, valLen);
05223         break;
05224     case SQL_DRIVER_ODBC_VER:
05225 #if 0
05226         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
05227 #else
05228         strmak(val, "03.00", valMax, valLen);
05229 #endif
05230         break;
05231     case SQL_ACTIVE_CONNECTIONS:
05232     case SQL_ACTIVE_STATEMENTS:
05233         *((SQLSMALLINT *) val) = 0;
05234         *valLen = sizeof (SQLSMALLINT);
05235         break;
05236 #ifdef SQL_ASYNC_MODE
05237     case SQL_ASYNC_MODE:
05238         *((SQLUINTEGER *) val) = SQL_AM_NONE;
05239         *valLen = sizeof (SQLUINTEGER);
05240         break;
05241 #endif
05242 #ifdef SQL_CREATE_TABLE
05243     case SQL_CREATE_TABLE:
05244         *((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
05245                                  SQL_CT_COLUMN_DEFAULT |
05246                                  SQL_CT_COLUMN_CONSTRAINT |
05247                                  SQL_CT_CONSTRAINT_NON_DEFERRABLE;
05248         *valLen = sizeof (SQLUINTEGER);
05249         break;
05250 #endif
05251 #ifdef SQL_CREATE_VIEW
05252     case SQL_CREATE_VIEW:
05253         *((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
05254         *valLen = sizeof (SQLUINTEGER);
05255         break;
05256 #endif
05257 #ifdef SQL_DDL_INDEX
05258     case SQL_DDL_INDEX:
05259         *((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
05260         *valLen = sizeof (SQLUINTEGER);
05261         break;
05262 #endif
05263 #ifdef SQL_DROP_TABLE
05264     case SQL_DROP_TABLE:
05265         *((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
05266         *valLen = sizeof (SQLUINTEGER);
05267         break;
05268 #endif
05269 #ifdef SQL_DROP_VIEW
05270     case SQL_DROP_VIEW:
05271         *((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
05272         *valLen = sizeof (SQLUINTEGER);
05273         break;
05274 #endif
05275 #ifdef SQL_INDEX_KEYWORDS
05276     case SQL_INDEX_KEYWORDS:
05277         *((SQLUINTEGER *) val) = SQL_IK_ALL;
05278         *valLen = sizeof (SQLUINTEGER);
05279         break;
05280 #endif
05281     case SQL_DATA_SOURCE_NAME:
05282         strmak(val, (d->dsn ? d->dsn : ""), valMax, valLen);
05283         break;
05284     case SQL_DRIVER_NAME:
05285         strmak(val, drvname, valMax, valLen);
05286         break;
05287     case SQL_DRIVER_VER:
05288         strmak(val, DRIVER_VER_INFO, valMax, valLen);
05289         break;
05290     case SQL_FETCH_DIRECTION:
05291         *((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
05292             SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
05293         *valLen = sizeof (SQLUINTEGER);
05294         break;
05295     case SQL_ODBC_VER:
05296         strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
05297         break;
05298     case SQL_ODBC_SAG_CLI_CONFORMANCE:
05299         *((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
05300         *valLen = sizeof (SQLSMALLINT);
05301         break;
05302     case SQL_STANDARD_CLI_CONFORMANCE:
05303         *((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
05304         *valLen = sizeof (SQLUINTEGER);
05305         break;
05306     case SQL_SERVER_NAME:
05307     case SQL_DATABASE_NAME:
05308         strmak(val, (d->dbname ? d->dbname : ""), valMax, valLen);
05309         break;
05310     case SQL_SEARCH_PATTERN_ESCAPE:
05311         strmak(val, "", valMax, valLen);
05312         break;
05313     case SQL_ODBC_SQL_CONFORMANCE:
05314         *((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
05315         *valLen = sizeof (SQLSMALLINT);
05316         break;
05317     case SQL_ODBC_API_CONFORMANCE:
05318         *((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
05319         *valLen = sizeof (SQLSMALLINT);
05320         break;
05321     case SQL_DBMS_NAME:
05322         strmak(val, "SQLite", valMax, valLen);
05323         break;
05324     case SQL_DBMS_VER:
05325         strmak(val, SQLITE_VERSION, valMax, valLen);
05326         break;
05327     case SQL_COLUMN_ALIAS:
05328     case SQL_NEED_LONG_DATA_LEN:
05329         strmak(val, "Y", valMax, valLen);
05330         break;
05331     case SQL_ROW_UPDATES:
05332     case SQL_ACCESSIBLE_PROCEDURES:
05333     case SQL_PROCEDURES:
05334     case SQL_EXPRESSIONS_IN_ORDERBY:
05335     case SQL_ODBC_SQL_OPT_IEF:
05336     case SQL_LIKE_ESCAPE_CLAUSE:
05337     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
05338     case SQL_OUTER_JOINS:
05339     case SQL_ACCESSIBLE_TABLES:
05340     case SQL_MULT_RESULT_SETS:
05341     case SQL_MULTIPLE_ACTIVE_TXN:
05342     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
05343         strmak(val, "N", valMax, valLen);
05344         break;
05345     case SQL_DATA_SOURCE_READ_ONLY:
05346         strmak(val, "N", valMax, valLen);
05347         break;
05348 #ifdef SQL_OJ_CAPABILITIES
05349     case SQL_OJ_CAPABILITIES:
05350         *((SQLUINTEGER *) val) = 0;
05351         *valLen = sizeof (SQLUINTEGER);
05352         break;
05353 #endif
05354 #ifdef SQL_MAX_IDENTIFIER_LEN
05355     case SQL_MAX_IDENTIFIER_LEN:
05356         *((SQLUSMALLINT *) val) = 255;
05357         *valLen = sizeof (SQLUSMALLINT);
05358         break;
05359 #endif
05360     case SQL_CONCAT_NULL_BEHAVIOR:
05361         *((SQLSMALLINT *) val) = SQL_CB_NULL;
05362         *valLen = sizeof (SQLSMALLINT);
05363         break;
05364     case SQL_CURSOR_COMMIT_BEHAVIOR:
05365     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
05366         *((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
05367         *valLen = sizeof (SQLSMALLINT);
05368         break;
05369 #ifdef SQL_CURSOR_SENSITIVITY
05370     case SQL_CURSOR_SENSITIVITY:
05371         *((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
05372         *valLen = sizeof (SQLUINTEGER);
05373         break;
05374 #endif
05375     case SQL_DEFAULT_TXN_ISOLATION:
05376         *((SQLUINTEGER *) val) = SQL_TXN_READ_UNCOMMITTED;
05377         *valLen = sizeof (SQLUINTEGER);
05378         break;
05379 #ifdef SQL_DESCRIBE_PARAMETER
05380     case SQL_DESCRIBE_PARAMETER:
05381         strmak(val, "Y", valMax, valLen);
05382         break;
05383 #endif
05384     case SQL_TXN_ISOLATION_OPTION:
05385         *((SQLUINTEGER *) val) = SQL_TXN_READ_UNCOMMITTED;
05386         *valLen = sizeof (SQLUINTEGER);
05387         break;
05388     case SQL_IDENTIFIER_CASE:
05389         *((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
05390         *valLen = sizeof (SQLSMALLINT);
05391         break;
05392     case SQL_IDENTIFIER_QUOTE_CHAR:
05393         strmak(val, "\"", valMax, valLen);
05394         break;
05395     case SQL_MAX_TABLE_NAME_LEN:
05396     case SQL_MAX_COLUMN_NAME_LEN:
05397         *((SQLSMALLINT *) val) = 255;
05398         *valLen = sizeof (SQLSMALLINT);
05399         break;
05400     case SQL_MAX_CURSOR_NAME_LEN:
05401         *((SWORD *) val) = 255;
05402         *valLen = sizeof (SWORD);
05403         break;
05404     case SQL_MAX_PROCEDURE_NAME_LEN:
05405         *((SQLSMALLINT *) val) = 0;
05406         break;
05407     case SQL_MAX_QUALIFIER_NAME_LEN:
05408     case SQL_MAX_OWNER_NAME_LEN:
05409         *((SQLSMALLINT *) val) = 255;
05410         break;
05411     case SQL_OWNER_TERM:
05412         strmak(val, "owner", valMax, valLen);
05413         break;
05414     case SQL_PROCEDURE_TERM:
05415         strmak(val, "procedure", valMax, valLen);
05416         break;
05417     case SQL_QUALIFIER_NAME_SEPARATOR:
05418         strmak(val, ".", valMax, valLen);
05419         break;
05420     case SQL_QUALIFIER_TERM:
05421         strmak(val, "database", valMax, valLen);
05422         break;
05423     case SQL_QUALIFIER_USAGE:
05424         *((SQLUINTEGER *) val) = 0;
05425         *valLen = sizeof (SQLUINTEGER);
05426         break;
05427     case SQL_SCROLL_CONCURRENCY:
05428         *((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
05429         *valLen = sizeof (SQLUINTEGER);
05430         break;
05431     case SQL_SCROLL_OPTIONS:
05432         *((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
05433         *valLen = sizeof (SQLUINTEGER);
05434         break;
05435     case SQL_TABLE_TERM:
05436         strmak(val, "table", valMax, valLen);
05437         break;
05438     case SQL_TXN_CAPABLE:
05439         *((SQLSMALLINT *) val) = SQL_TC_ALL;
05440         *valLen = sizeof (SQLSMALLINT);
05441         break;
05442     case SQL_CONVERT_FUNCTIONS:
05443         *((SQLUINTEGER *) val) = 0;
05444         *valLen = sizeof (SQLUINTEGER);
05445        break;
05446     case SQL_SYSTEM_FUNCTIONS:
05447     case SQL_NUMERIC_FUNCTIONS:
05448     case SQL_STRING_FUNCTIONS:
05449     case SQL_TIMEDATE_FUNCTIONS:
05450         *((SQLUINTEGER *) val) = 0;
05451         *valLen = sizeof (SQLUINTEGER);
05452         break;
05453     case SQL_CONVERT_BIGINT:
05454     case SQL_CONVERT_BIT:
05455     case SQL_CONVERT_CHAR:
05456     case SQL_CONVERT_DATE:
05457     case SQL_CONVERT_DECIMAL:
05458     case SQL_CONVERT_DOUBLE:
05459     case SQL_CONVERT_FLOAT:
05460     case SQL_CONVERT_INTEGER:
05461     case SQL_CONVERT_LONGVARCHAR:
05462     case SQL_CONVERT_NUMERIC:
05463     case SQL_CONVERT_REAL:
05464     case SQL_CONVERT_SMALLINT:
05465     case SQL_CONVERT_TIME:
05466     case SQL_CONVERT_TIMESTAMP:
05467     case SQL_CONVERT_TINYINT:
05468     case SQL_CONVERT_VARCHAR:
05469         *((SQLUINTEGER *) val) = 
05470             SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
05471             SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
05472             SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
05473             SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
05474             SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
05475         *valLen = sizeof (SQLUINTEGER);
05476         break;
05477     case SQL_CONVERT_BINARY:
05478     case SQL_CONVERT_VARBINARY:
05479     case SQL_CONVERT_LONGVARBINARY:
05480         *((SQLUINTEGER *) val) = 0;
05481         *valLen = sizeof (SQLUINTEGER);
05482         break;
05483     case SQL_POSITIONED_STATEMENTS:
05484     case SQL_LOCK_TYPES:
05485         *((SQLUINTEGER *) val) = 0;
05486         *valLen = sizeof (SQLUINTEGER);
05487         break;
05488     case SQL_BOOKMARK_PERSISTENCE:
05489         *((SQLUINTEGER *) val) = SQL_BP_SCROLL;
05490         *valLen = sizeof (SQLUINTEGER);
05491         break;
05492     case SQL_UNION:
05493         *((SQLUINTEGER *) val) = SQL_U_UNION;
05494         *valLen = sizeof (SQLUINTEGER);
05495         break;
05496     case SQL_OWNER_USAGE:
05497     case SQL_SUBQUERIES:
05498     case SQL_TIMEDATE_ADD_INTERVALS:
05499     case SQL_TIMEDATE_DIFF_INTERVALS:
05500         *((SQLUINTEGER *) val) = 0;
05501         *valLen = sizeof (SQLUINTEGER);
05502         break;
05503     case SQL_QUOTED_IDENTIFIER_CASE:
05504         *((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
05505         *valLen = sizeof (SQLUSMALLINT);
05506         break;
05507     case SQL_POS_OPERATIONS:
05508         *((SQLUINTEGER *) val) = 0;
05509         *valLen = sizeof (SQLUINTEGER);
05510         break;
05511     case SQL_ALTER_TABLE:
05512         *((SQLUINTEGER *) val) = 0;
05513         *valLen = sizeof (SQLUINTEGER);
05514         break;
05515     case SQL_CORRELATION_NAME:
05516         *((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
05517         *valLen = sizeof (SQLSMALLINT);
05518         break;
05519     case SQL_NON_NULLABLE_COLUMNS:
05520         *((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
05521         *valLen = sizeof (SQLSMALLINT);
05522         break;
05523     case SQL_NULL_COLLATION:
05524         *((SQLSMALLINT *) val) = SQL_NC_START;
05525         *valLen = sizeof (SQLSMALLINT);
05526         break;
05527     case SQL_MAX_COLUMNS_IN_GROUP_BY:
05528     case SQL_MAX_COLUMNS_IN_ORDER_BY:
05529     case SQL_MAX_COLUMNS_IN_SELECT:
05530     case SQL_MAX_COLUMNS_IN_TABLE:
05531     case SQL_MAX_ROW_SIZE:
05532     case SQL_MAX_TABLES_IN_SELECT:
05533         *((SQLSMALLINT *) val) = 0;
05534         *valLen = sizeof (SQLSMALLINT);
05535         break;
05536     case SQL_MAX_BINARY_LITERAL_LEN:
05537     case SQL_MAX_CHAR_LITERAL_LEN:
05538         *((SQLUINTEGER *) val) = 0;
05539         *valLen = sizeof (SQLUINTEGER);
05540         break;
05541     case SQL_MAX_COLUMNS_IN_INDEX:
05542         *((SQLSMALLINT *) val) = 0;
05543         *valLen = sizeof (SQLSMALLINT);
05544         break;
05545     case SQL_MAX_INDEX_SIZE:
05546         *((SQLUINTEGER *) val) = 0;
05547         *valLen = sizeof (SQLUINTEGER);
05548         break;
05549 #ifdef SQL_MAX_IDENTIFIER_LENGTH
05550     case SQL_MAX_IDENTIFIER_LENGTH:
05551         *((SQLUINTEGER *) val) = 255;
05552         *valLen = sizeof (SQLUINTEGER);
05553         break;
05554 #endif
05555     case SQL_MAX_STATEMENT_LEN:
05556         *((SQLUINTEGER *) val) = 16384;
05557         *valLen = sizeof (SQLUINTEGER);
05558         break;
05559     case SQL_QUALIFIER_LOCATION:
05560         *((SQLSMALLINT *) val) = SQL_QL_START;
05561         *valLen = sizeof (SQLSMALLINT);
05562         break;
05563     case SQL_GETDATA_EXTENSIONS:
05564         *((SQLUINTEGER *) val) =
05565             SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
05566         *valLen = sizeof (SQLUINTEGER);
05567         break;
05568     case SQL_STATIC_SENSITIVITY:
05569         *((SQLUINTEGER *) val) = 0;
05570         *valLen = sizeof (SQLUINTEGER);
05571         break;
05572     case SQL_FILE_USAGE:
05573         *((SQLSMALLINT *) val) = SQL_FILE_CATALOG;
05574         *valLen = sizeof (SQLSMALLINT);
05575         break;
05576     case SQL_GROUP_BY:
05577         *((SQLSMALLINT *) val) = 0;
05578         *valLen = sizeof (SQLSMALLINT);
05579         break;
05580     case SQL_KEYWORDS:
05581         strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
05582                "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
05583                valMax, valLen);
05584         break;
05585     case SQL_SPECIAL_CHARACTERS:
05586         strmak(val, "", valMax, valLen);
05587         break;
05588     case SQL_BATCH_SUPPORT:
05589     case SQL_BATCH_ROW_COUNT:
05590     case SQL_PARAM_ARRAY_ROW_COUNTS:
05591         *((SQLUINTEGER *) val) = 0;
05592         *valLen = sizeof (SQLUINTEGER);
05593         break;
05594     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
05595         *((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
05596         *valLen = sizeof (SQLUINTEGER);
05597         break;
05598     case SQL_STATIC_CURSOR_ATTRIBUTES1:
05599         *((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
05600             SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
05601         *valLen = sizeof (SQLUINTEGER);
05602         break;
05603     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
05604     case SQL_STATIC_CURSOR_ATTRIBUTES2:
05605         *((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
05606             SQL_CA2_LOCK_CONCURRENCY;
05607         *valLen = sizeof (SQLUINTEGER);
05608         break;
05609     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
05610     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
05611     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
05612     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
05613         *((SQLUINTEGER *) val) = 0;
05614         *valLen = sizeof (SQLUINTEGER);
05615         break;
05616     case SQL_ODBC_INTERFACE_CONFORMANCE:
05617         *((SQLUINTEGER *) val) = SQL_OIC_CORE;
05618         *valLen = sizeof (SQLUINTEGER);
05619         break;
05620     default:
05621         setstatd(d, -1, "unsupported info option %d",
05622                  (*d->ov3) ? "HYC00" : "S1C00", type);
05623         return SQL_ERROR;
05624     }
05625     return SQL_SUCCESS;
05626 }
05627 
05638 SQLRETURN SQL_API
05639 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
05640            SQLSMALLINT *valLen)
05641 {
05642     return drvgetinfo(dbc, type, val, valMax, valLen);
05643 }
05644 
05653 SQLRETURN SQL_API
05654 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
05655                 SQLUSMALLINT *flags)
05656 {
05657     DBC *d;
05658     int i;
05659     SQLUSMALLINT exists[100];
05660 
05661     if (dbc == SQL_NULL_HDBC) {
05662         return SQL_INVALID_HANDLE;
05663     }
05664     d = (DBC *) dbc;
05665     for (i = 0; i < array_size(exists); i++) {
05666         exists[i] = SQL_FALSE;
05667     }
05668     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
05669     exists[SQL_API_SQLFETCH] = SQL_TRUE;
05670     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
05671     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
05672     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
05673     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
05674     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
05675     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
05676     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
05677     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
05678     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
05679     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
05680     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
05681     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
05682     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
05683     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
05684     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
05685     exists[SQL_API_SQLSETCURSORNAME] = SQL_FALSE;
05686     exists[SQL_API_SQLERROR] = SQL_TRUE;
05687     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
05688     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
05689     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
05690     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
05691     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
05692     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
05693     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
05694     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
05695     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
05696     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
05697     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
05698     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
05699     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
05700     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
05701     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
05702     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
05703     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
05704     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
05705     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
05706     exists[SQL_API_SQLTABLES] = SQL_TRUE;
05707     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
05708     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
05709     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
05710     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
05711     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
05712     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
05713     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
05714     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
05715     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
05716     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
05717     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
05718     exists[SQL_API_SQLSETPOS] = SQL_FALSE;
05719     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
05720     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
05721     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
05722     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_FALSE;
05723     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
05724     if (func == SQL_API_ALL_FUNCTIONS) {
05725         memcpy(flags, exists, sizeof (exists));
05726     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
05727         int i;
05728 #define SET_EXISTS(x) \
05729         flags[(x) >> 4] |= (1 << ((x) & 0xF))
05730 #define CLR_EXISTS(x) \
05731         flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
05732 
05733         memset(flags, 0,
05734                sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
05735         for (i = 0; i < array_size(exists); i++) {
05736             if (exists[i]) {
05737                 flags[i >> 4] |= (1 << (i & 0xF));
05738             }
05739         }
05740         SET_EXISTS(SQL_API_SQLALLOCHANDLE);
05741         SET_EXISTS(SQL_API_SQLFREEHANDLE);
05742         SET_EXISTS(SQL_API_SQLGETSTMTATTR);
05743         SET_EXISTS(SQL_API_SQLSETSTMTATTR);
05744         SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
05745         SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
05746         SET_EXISTS(SQL_API_SQLGETENVATTR);
05747         SET_EXISTS(SQL_API_SQLSETENVATTR);
05748         SET_EXISTS(SQL_API_SQLCLOSECURSOR);
05749         SET_EXISTS(SQL_API_SQLBINDPARAM);
05750 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
05751         /*
05752          * Some unixODBC versions have problems with
05753          * SQLError() vs. SQLGetDiagRec() with loss
05754          * of error/warning messages.
05755          */
05756         SET_EXISTS(SQL_API_SQLGETDIAGREC);
05757 #endif
05758         SET_EXISTS(SQL_API_SQLFETCHSCROLL);
05759         SET_EXISTS(SQL_API_SQLENDTRAN);
05760     } else {
05761         if (func < array_size(exists)) {
05762             *flags = exists[func];
05763         } else {
05764             switch (func) {
05765             case SQL_API_SQLALLOCHANDLE:
05766             case SQL_API_SQLFREEHANDLE:
05767             case SQL_API_SQLGETSTMTATTR:
05768             case SQL_API_SQLSETSTMTATTR:
05769             case SQL_API_SQLGETCONNECTATTR:
05770             case SQL_API_SQLSETCONNECTATTR:
05771             case SQL_API_SQLGETENVATTR:
05772             case SQL_API_SQLSETENVATTR:
05773             case SQL_API_SQLCLOSECURSOR:
05774             case SQL_API_SQLBINDPARAM:
05775 #if !defined(HAVE_UNIXODBC) || !HAVE_UNIXODBC
05776             /*
05777              * Some unixODBC versions have problems with
05778              * SQLError() vs. SQLGetDiagRec() with loss
05779              * of error/warning messages.
05780              */
05781             case SQL_API_SQLGETDIAGREC:
05782 #endif
05783             case SQL_API_SQLFETCHSCROLL:
05784             case SQL_API_SQLENDTRAN:
05785                 *flags = SQL_TRUE;
05786                 break;
05787             default:
05788                 *flags = SQL_FALSE;
05789             }
05790         }
05791     }
05792     return SQL_SUCCESS;
05793 }
05794 
05801 static SQLRETURN
05802 drvallocenv(SQLHENV *env)
05803 {
05804     ENV *e;
05805 
05806     if (env == NULL) {
05807         return SQL_INVALID_HANDLE;
05808     }
05809     e = (ENV *) xmalloc(sizeof (ENV));
05810     if (e == NULL) {
05811         *env = SQL_NULL_HENV;
05812         return SQL_ERROR;
05813     }
05814     e->magic = ENV_MAGIC;
05815     e->ov3 = 0;
05816     e->dbcs = NULL;
05817     *env = (SQLHENV) e;
05818     return SQL_SUCCESS;
05819 }
05820 
05827 SQLRETURN SQL_API
05828 SQLAllocEnv(SQLHENV *env)
05829 {
05830     return drvallocenv(env);
05831 }
05832 
05839 static SQLRETURN
05840 drvfreeenv(SQLHENV env)
05841 {
05842     ENV *e;
05843 
05844     if (env == SQL_NULL_HENV) {
05845         return SQL_INVALID_HANDLE;
05846     }
05847     e = (ENV *) env;
05848     if (e->magic != ENV_MAGIC) {
05849         return SQL_SUCCESS;
05850     }
05851     if (e->dbcs) {
05852         return SQL_ERROR;
05853     }
05854     e->magic = DEAD_MAGIC;
05855     xfree(e);
05856     return SQL_SUCCESS;
05857 }
05858 
05865 SQLRETURN SQL_API
05866 SQLFreeEnv(SQLHENV env)
05867 {
05868     return drvfreeenv(env);
05869 }
05870 
05878 static SQLRETURN
05879 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
05880 {
05881     DBC *d;
05882     ENV *e;
05883     const char *verstr;
05884     int maj = 0, min = 0, lev = 0;
05885 
05886     if (dbc == NULL) {
05887         return SQL_ERROR;
05888     }
05889     d = (DBC *) xmalloc(sizeof (DBC));
05890     if (d == NULL) {
05891         *dbc = SQL_NULL_HDBC;
05892         return SQL_ERROR;
05893     }
05894     memset(d, 0, sizeof (DBC));
05895     d->curtype = SQL_CURSOR_STATIC;
05896     d->ov3 = &d->ov3val;
05897     verstr = sqlite3_libversion();
05898     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
05899     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
05900     e = (ENV *) env;
05901     if (e->magic == ENV_MAGIC) {
05902         DBC *n, *p;
05903 
05904         d->env = e;
05905         d->ov3 = &e->ov3;
05906         p = NULL;
05907         n = e->dbcs;
05908         while (n) {
05909             p = n;
05910             n = n->next;
05911         }
05912         if (p) {
05913             p->next = d;
05914         } else {
05915             e->dbcs = d;
05916         }
05917     }
05918     d->autocommit = 1;
05919     d->magic = DBC_MAGIC;
05920     *dbc = (SQLHDBC) d;
05921     drvgetgpps(d);
05922     return SQL_SUCCESS;
05923 }
05924 
05932 SQLRETURN SQL_API
05933 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
05934 {
05935     return drvallocconnect(env, dbc);
05936 }
05937 
05944 static SQLRETURN
05945 drvfreeconnect(SQLHDBC dbc)
05946 {
05947     DBC *d;
05948     ENV *e;
05949 
05950     if (dbc == SQL_NULL_HDBC) {
05951         return SQL_INVALID_HANDLE;
05952     }
05953     d = (DBC *) dbc;
05954     if (d->magic != DBC_MAGIC) {
05955         return SQL_INVALID_HANDLE;
05956     }
05957     if (d->sqlite) {
05958         setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
05959         return SQL_ERROR;
05960     }
05961     while (d->stmt) {
05962         freestmt((HSTMT) d->stmt);
05963     }
05964     e = d->env;
05965     if (e && e->magic == ENV_MAGIC) {
05966         DBC *n, *p;
05967 
05968         p = NULL;
05969         n = e->dbcs;
05970         while (n) {
05971             if (n == d) {
05972                 break;
05973             }
05974             p = n;
05975             n = n->next;
05976         }
05977         if (n) {
05978             if (p) {
05979                 p->next = d->next;
05980             } else {
05981                 e->dbcs = d->next;
05982             }
05983         }
05984     }
05985     drvrelgpps(d);
05986     d->magic = DEAD_MAGIC;
05987     if (d->trace) {
05988         fclose(d->trace);
05989     }
05990     xfree(d);
05991     return SQL_SUCCESS;
05992 }
05993 
06000 SQLRETURN SQL_API
06001 SQLFreeConnect(SQLHDBC dbc)
06002 {
06003     return drvfreeconnect(dbc);
06004 }
06005 
06016 static SQLRETURN
06017 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
06018                   SQLINTEGER bufmax, SQLINTEGER *buflen)
06019 {
06020     DBC *d;
06021     SQLINTEGER dummy;
06022 
06023     if (dbc == SQL_NULL_HDBC) {
06024         return SQL_INVALID_HANDLE;
06025     }
06026     d = (DBC *) dbc;
06027     if (!val) {
06028         val = (SQLPOINTER) &dummy;
06029     }
06030     if (!buflen) {
06031         buflen = &dummy;
06032     }
06033     switch (attr) {
06034     case SQL_ATTR_CONNECTION_DEAD:
06035         *((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
06036         *buflen = sizeof (SQLINTEGER);
06037         break;
06038     case SQL_ATTR_ACCESS_MODE:
06039         *((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
06040         *buflen = sizeof (SQLINTEGER);
06041         break;
06042     case SQL_ATTR_AUTOCOMMIT:
06043         *((SQLINTEGER *) val) =
06044             d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
06045         *buflen = sizeof (SQLINTEGER);
06046         break;
06047     case SQL_ATTR_LOGIN_TIMEOUT:
06048         *((SQLINTEGER *) val) = 100;
06049         *buflen = sizeof (SQLINTEGER);
06050         break;
06051     case SQL_ATTR_ODBC_CURSORS:
06052         *((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
06053         *buflen = sizeof (SQLINTEGER);
06054         break;
06055     case SQL_ATTR_PACKET_SIZE:
06056         *((SQLINTEGER *) val) = 16384;
06057         *buflen = sizeof (SQLINTEGER);
06058         break;
06059     case SQL_ATTR_TXN_ISOLATION:
06060         *((SQLINTEGER *) val) = SQL_TXN_READ_UNCOMMITTED;
06061         *buflen = sizeof (SQLINTEGER);
06062         break;
06063     case SQL_ATTR_TRACE:
06064     case SQL_ATTR_TRACEFILE:
06065     case SQL_ATTR_QUIET_MODE:
06066     case SQL_ATTR_TRANSLATE_OPTION:
06067     case SQL_ATTR_KEYSET_SIZE:
06068     case SQL_ATTR_QUERY_TIMEOUT:
06069     case SQL_ATTR_PARAM_BIND_TYPE:
06070     case SQL_ATTR_CURRENT_CATALOG:
06071         *((SQLINTEGER *) val) = 0;
06072         *buflen = sizeof (SQLINTEGER);
06073         break;
06074     case SQL_ATTR_ROW_BIND_TYPE:
06075         *((SQLUINTEGER *) val) = SQL_BIND_BY_COLUMN;
06076         *buflen = sizeof (SQLUINTEGER);
06077         break;
06078     case SQL_ATTR_USE_BOOKMARKS:
06079         *((SQLINTEGER *) val) = SQL_UB_OFF;
06080         *buflen = sizeof (SQLINTEGER);
06081         break;
06082     case SQL_ATTR_ASYNC_ENABLE:
06083         *((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
06084         *buflen = sizeof (SQLINTEGER);
06085         break;
06086     case SQL_ATTR_NOSCAN:
06087         *((SQLINTEGER *) val) = SQL_NOSCAN_ON;
06088         *buflen = sizeof (SQLINTEGER);
06089         break;
06090     case SQL_ATTR_CONCURRENCY:
06091         *((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
06092         *buflen = sizeof (SQLINTEGER);
06093         break;
06094     case SQL_ATTR_SIMULATE_CURSOR:
06095         *((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
06096         *buflen = sizeof (SQLINTEGER);
06097         break;
06098     case SQL_ATTR_MAX_ROWS:
06099     case SQL_ATTR_MAX_LENGTH:
06100         *((SQLINTEGER *) val) = 1000000000;
06101         *buflen = sizeof (SQLINTEGER);
06102         break;
06103     case SQL_ATTR_CURSOR_TYPE:
06104         *((SQLINTEGER *) val) = d->curtype;
06105         *buflen = sizeof (SQLINTEGER);
06106         break;
06107     case SQL_ATTR_RETRIEVE_DATA:
06108         *((SQLINTEGER *) val) = SQL_RD_ON;
06109         *buflen = sizeof (SQLINTEGER);
06110         break;
06111     default:
06112         *((SQLINTEGER *) val) = 0;
06113         *buflen = sizeof (SQLINTEGER);
06114         setstatd(d, -1, "unsupported connect attribute %d",
06115                  (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
06116         return SQL_ERROR;
06117     }
06118     return SQL_SUCCESS;
06119 }
06120 
06131 SQLRETURN SQL_API
06132 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
06133                   SQLINTEGER bufmax, SQLINTEGER *buflen)
06134 {
06135     return drvgetconnectattr(dbc, attr, val, bufmax, buflen);
06136 }
06137 
06147 static SQLRETURN
06148 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
06149                   SQLINTEGER len)
06150 {
06151     DBC *d;
06152 
06153     if (dbc == SQL_NULL_HDBC) {
06154         return SQL_INVALID_HANDLE;
06155     }
06156     d = (DBC *) dbc;
06157     switch (attr) {
06158     case SQL_AUTOCOMMIT:
06159         if (len == SQL_IS_INTEGER || len == SQL_IS_UINTEGER) {
06160             d->autocommit = (SQLINTEGER) val == SQL_AUTOCOMMIT_ON;
06161             goto doit;
06162         }
06163         if (val && len >= sizeof (SQLINTEGER)) {
06164             d->autocommit = *((SQLINTEGER *) val) == SQL_AUTOCOMMIT_ON;
06165 doit:
06166             if (d->autocommit && d->intrans) {
06167                 return endtran(d, SQL_COMMIT);
06168             } else if (!d->autocommit) {
06169                 s3stmt_end(d->cur_s3stmt);
06170             }
06171         }
06172         break;
06173     default:
06174         setstatd(d, -1, "option value changed", "01S02");
06175         return SQL_SUCCESS_WITH_INFO;
06176     }
06177     return SQL_SUCCESS;
06178 }
06179 
06189 SQLRETURN SQL_API
06190 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
06191                   SQLINTEGER len)
06192 {
06193     return drvsetconnectattr(dbc, attr, val, len);
06194 }
06195 
06204 static SQLRETURN
06205 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
06206 {
06207     DBC *d;
06208     SQLINTEGER dummy;
06209 
06210     if (dbc == SQL_NULL_HDBC) {
06211         return SQL_INVALID_HANDLE;
06212     }
06213     d = (DBC *) dbc;
06214     if (!param) {
06215         param = (SQLPOINTER) &dummy;
06216     }
06217     switch (opt) {
06218     case SQL_ACCESS_MODE:
06219         *((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
06220         break;
06221     case SQL_AUTOCOMMIT:
06222         *((SQLINTEGER *) param) =
06223             d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
06224         break;
06225     case SQL_LOGIN_TIMEOUT:
06226         *((SQLINTEGER *) param) = 100;
06227         break;
06228     case SQL_ODBC_CURSORS:
06229         *((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
06230         break;
06231     case SQL_PACKET_SIZE:
06232         *((SQLINTEGER *) param) = 16384;
06233         break;
06234     case SQL_TXN_ISOLATION:
06235         *((SQLINTEGER *) param) = SQL_TXN_READ_UNCOMMITTED;
06236         break;
06237     case SQL_OPT_TRACE:
06238     case SQL_OPT_TRACEFILE:
06239     case SQL_QUIET_MODE:
06240     case SQL_TRANSLATE_DLL:
06241     case SQL_TRANSLATE_OPTION:
06242     case SQL_KEYSET_SIZE:
06243     case SQL_QUERY_TIMEOUT:
06244     case SQL_BIND_TYPE:
06245     case SQL_CURRENT_QUALIFIER:
06246         *((SQLINTEGER *) param) = 0;
06247         break;
06248     case SQL_USE_BOOKMARKS:
06249         *((SQLINTEGER *) param) = SQL_UB_OFF;
06250         break;
06251     case SQL_ASYNC_ENABLE:
06252         *((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
06253         break;
06254     case SQL_NOSCAN:
06255         *((SQLINTEGER *) param) = SQL_NOSCAN_ON;
06256         break;
06257     case SQL_CONCURRENCY:
06258         *((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
06259         break;
06260     case SQL_SIMULATE_CURSOR:
06261         *((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
06262         break;
06263     case SQL_ROWSET_SIZE:
06264     case SQL_MAX_ROWS:
06265     case SQL_MAX_LENGTH:
06266         *((SQLINTEGER *) param) = 1000000000;
06267         break;
06268     case SQL_CURSOR_TYPE:
06269         *((SQLINTEGER *) param) = d->curtype;
06270         break;
06271     case SQL_RETRIEVE_DATA:
06272         *((SQLINTEGER *) param) = SQL_RD_ON;
06273         break;
06274     default:
06275         *((SQLINTEGER *) param) = 0;
06276         setstatd(d, -1, "unsupported connect option %d",
06277                  (*d->ov3) ? "HYC00" : "S1C00", opt);
06278         return SQL_ERROR;
06279     }
06280     return SQL_SUCCESS;
06281 }
06282 
06291 SQLRETURN SQL_API
06292 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
06293 {
06294     return drvgetconnectoption(dbc, opt, param);
06295 }
06296 
06305 static SQLRETURN
06306 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
06307 {
06308     DBC *d;
06309 
06310     if (dbc == SQL_NULL_HDBC) {
06311         return SQL_INVALID_HANDLE;
06312     }
06313     d = (DBC *) dbc;
06314     switch (opt) {
06315     case SQL_AUTOCOMMIT:
06316         d->autocommit = param == SQL_AUTOCOMMIT_ON;
06317         if (d->autocommit && d->intrans) {
06318             return endtran(d, SQL_COMMIT);
06319         } else if (!d->autocommit) {
06320             s3stmt_end(d->cur_s3stmt);
06321         }
06322         break;
06323     default:
06324         setstatd(d, -1, "option value changed", "01S02");
06325         return SQL_SUCCESS_WITH_INFO;
06326     }
06327     return SQL_SUCCESS;
06328 }
06329 
06338 SQLRETURN SQL_API
06339 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
06340 {
06341     return drvsetconnectoption(dbc, opt, param);
06342 }
06343 
06344 #if defined(WITHOUT_DRIVERMGR) || !defined(_WIN32)
06345 
06356 static int
06357 getdsnattr(char *dsn, char *attr, char *out, int outLen)
06358 {
06359     char *str = dsn, *start;
06360     int len = strlen(attr);
06361 
06362     while (*str) {
06363         while (*str && *str == ';') {
06364             ++str;
06365         }
06366         start = str;
06367         if ((str = strchr(str, '=')) == NULL) {
06368             return 0;
06369         }
06370         if (str - start == len &&
06371 #ifdef _WIN32
06372             _strnicmp(start, attr, len) == 0
06373 #else
06374             strncasecmp(start, attr, len) == 0
06375 #endif
06376            ) {
06377             start = ++str;
06378             while (*str && *str != ';') {
06379                 ++str;
06380             }
06381             len = min(outLen - 1, str - start);
06382             strncpy(out, start, len);
06383             out[len] = '\0';
06384             return 1;
06385         }
06386         while (*str && *str != ';') {
06387             ++str;
06388         }
06389     }
06390     return 0;
06391 }
06392 #endif
06393 
06402 static SQLRETURN
06403 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen)
06404 {
06405     DBC *d;
06406     int len;
06407     char buf[SQL_MAX_MESSAGE_LENGTH], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
06408     char busy[SQL_MAX_MESSAGE_LENGTH / 4], tracef[SQL_MAX_MESSAGE_LENGTH];
06409     char sflag[32], spflag[32], ntflag[32], lnflag[32];
06410 
06411     if (dbc == SQL_NULL_HDBC) {
06412         return SQL_INVALID_HANDLE;
06413     }
06414     d = (DBC *) dbc;
06415     if (d->magic != DBC_MAGIC) {
06416         return SQL_INVALID_HANDLE;
06417     }
06418     if (d->sqlite != NULL) {
06419         setstatd(d, -1, "connection already established", "08002");
06420         return SQL_ERROR;
06421     }
06422     buf[0] = '\0';
06423     if (dsnLen == SQL_NTS) {
06424         len = sizeof (buf) - 1;
06425     } else {
06426         len = min(sizeof (buf) - 1, dsnLen);
06427     }
06428     if (dsn != NULL) {
06429         strncpy(buf, (char *) dsn, len);
06430     }
06431     buf[len] = '\0';
06432     if (buf[0] == '\0') {
06433         setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
06434         return SQL_ERROR;
06435     }
06436     busy[0] = '\0';
06437     dbname[0] = '\0';
06438 #ifdef WITHOUT_DRIVERMGR
06439     getdsnattr(buf, "database", dbname, sizeof (dbname));
06440     if (dbname[0] == '\0') {
06441         strncpy(dbname, buf, sizeof (dbname));
06442         dbname[sizeof (dbname) - 1] = '\0';
06443     }
06444     getdsnattr(buf, "timeout", busy, sizeof (busy));
06445     sflag[0] = '\0';
06446     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
06447     spflag[0] = '\0';
06448     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
06449     ntflag[0] = '\0';
06450     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
06451     lnflag[0] = '\0';
06452     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
06453 #else
06454     SQLGetPrivateProfileString(buf, "timeout", "1000",
06455                                busy, sizeof (busy), ODBC_INI);
06456     SQLGetPrivateProfileString(buf, "database", "",
06457                                dbname, sizeof (dbname), ODBC_INI);
06458     SQLGetPrivateProfileString(buf, "stepapi", "",
06459                                sflag, sizeof (sflag), ODBC_INI);
06460     SQLGetPrivateProfileString(buf, "syncpragma", "NORMAL",
06461                                spflag, sizeof (spflag), ODBC_INI);
06462     SQLGetPrivateProfileString(buf, "notxn", "",
06463                                ntflag, sizeof (ntflag), ODBC_INI);
06464     SQLGetPrivateProfileString(buf, "longnames", "",
06465                                lnflag, sizeof (lnflag), ODBC_INI);
06466 #endif
06467     tracef[0] = '\0';
06468 #ifdef WITHOUT_DRIVERMGR
06469     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
06470 #else
06471     SQLGetPrivateProfileString(buf, "tracefile", "",
06472                                tracef, sizeof (tracef), ODBC_INI);
06473 #endif
06474     if (tracef[0] != '\0') {
06475         d->trace = fopen(tracef, "a");
06476     }
06477     d->longnames = getbool(lnflag);
06478     return dbopen(d, dbname, (char *) dsn, sflag, spflag, ntflag, busy);
06479 }
06480 
06493 SQLRETURN SQL_API
06494 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
06495            SQLCHAR *uid, SQLSMALLINT uidLen,
06496            SQLCHAR *pass, SQLSMALLINT passLen)
06497 {
06498     return drvconnect(dbc, dsn, dsnLen);
06499 }
06500 
06507 SQLRETURN SQL_API
06508 SQLDisconnect(SQLHDBC dbc)
06509 {
06510     DBC *d;
06511 
06512     if (dbc == SQL_NULL_HDBC) {
06513         return SQL_INVALID_HANDLE;
06514     }
06515     d = (DBC *) dbc;
06516     if (d->magic != DBC_MAGIC) {
06517         return SQL_INVALID_HANDLE;
06518     }
06519     if (d->intrans) {
06520         setstatd(d, -1, "incomplete transaction", "25000");
06521         return SQL_ERROR;
06522     }
06523     if (d->cur_s3stmt) {
06524         s3stmt_end(d->cur_s3stmt);
06525     }
06526     if (d->sqlite) {
06527         if (d->trace) {
06528             fprintf(d->trace, "-- sqlite3_close: '%s'\n",
06529                     d->dbname);
06530             fflush(d->trace);
06531         }
06532         sqlite3_close(d->sqlite);
06533         d->sqlite = NULL;
06534     }
06535     freep(&d->dbname);
06536     freep(&d->dsn);
06537     return SQL_SUCCESS;
06538 }
06539 
06540 #if defined(WITHOUT_DRIVERMGR) || !defined(_WIN32)
06541 
06555 static SQLRETURN
06556 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
06557                  SQLCHAR *connIn, SQLSMALLINT connInLen,
06558                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
06559                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
06560 {
06561     DBC *d;
06562     int len;
06563     char buf[SQL_MAX_MESSAGE_LENGTH], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
06564     char dsn[SQL_MAX_MESSAGE_LENGTH / 4], busy[SQL_MAX_MESSAGE_LENGTH / 4];
06565     char tracef[SQL_MAX_MESSAGE_LENGTH];
06566     char sflag[32], spflag[32], ntflag[32], lnflag[32];
06567 
06568     if (dbc == SQL_NULL_HDBC || hwnd != NULL) {
06569         return SQL_INVALID_HANDLE;
06570     }
06571     if (drvcompl != SQL_DRIVER_COMPLETE &&
06572         drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
06573         drvcompl != SQL_DRIVER_PROMPT &&
06574         drvcompl != SQL_DRIVER_NOPROMPT) {
06575         return SQL_NO_DATA;
06576     }
06577     d = (DBC *) dbc;
06578     if (d->sqlite) {
06579         setstatd(d, -1, "connection already established", "08002");
06580         return SQL_ERROR;
06581     }
06582     buf[0] = '\0';
06583     if (connInLen == SQL_NTS) {
06584         len = sizeof (buf) - 1;
06585     } else {
06586         len = min(connInLen, sizeof (buf) - 1);
06587     }
06588     if (connIn != NULL) {
06589         strncpy(buf, (char *) connIn, len);
06590     }
06591     buf[len] = '\0';
06592     if (!buf[0]) {
06593         setstatd(d, -1, "invalid connect attributes",
06594                  (*d->ov3) ? "HY090" : "S1090");
06595         return SQL_ERROR;
06596     }
06597     dsn[0] = '\0';
06598     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
06599 
06600     /* special case: connIn is sole DSN value without keywords */
06601     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
06602         strncpy(dsn, buf, sizeof (dsn) - 1);
06603         dsn[sizeof (dsn) - 1] = '\0';
06604     }
06605 
06606     busy[0] = '\0';
06607     getdsnattr(buf, "timeout", busy, sizeof (busy));
06608 #ifndef WITHOUT_DRIVERMGR
06609     if (dsn[0] && !busy[0]) {
06610         SQLGetPrivateProfileString(dsn, "timeout", "1000",
06611                                    busy, sizeof (busy), ODBC_INI);
06612     }
06613 #endif
06614     dbname[0] = '\0';
06615     getdsnattr(buf, "database", dbname, sizeof (dbname));
06616 #ifndef WITHOUT_DRIVERMGR
06617     if (dsn[0] && !dbname[0]) {
06618         SQLGetPrivateProfileString(dsn, "database", "",
06619                                    dbname, sizeof (dbname), ODBC_INI);
06620     }
06621 #endif
06622     sflag[0] = '\0';
06623     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
06624 #ifndef WITHOUT_DRIVERMGR
06625     if (dsn[0] && !sflag[0]) {
06626         SQLGetPrivateProfileString(dsn, "stepapi", "",
06627                                    sflag, sizeof (sflag), ODBC_INI);
06628     }
06629 #endif
06630     spflag[0] = '\0';
06631     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
06632 #ifndef WITHOUT_DRIVERMGR
06633     if (dsn[0] && !spflag[0]) {
06634         SQLGetPrivateProfileString(dsn, "syncpragma", "NORMAL",
06635                                    spflag, sizeof (spflag), ODBC_INI);
06636     }
06637 #endif
06638     ntflag[0] = '\0';
06639     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
06640 #ifndef WITHOUT_DRIVERMGR
06641     if (dsn[0] && !ntflag[0]) {
06642         SQLGetPrivateProfileString(dsn, "notxn", "",
06643                                    ntflag, sizeof (ntflag), ODBC_INI);
06644     }
06645 #endif
06646     lnflag[0] = '\0';
06647     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
06648 #ifndef WITHOUT_DRIVERMGR
06649     if (dsn[0] && !lnflag[0]) {
06650         SQLGetPrivateProfileString(dsn, "longnames", "",
06651                                    lnflag, sizeof (lnflag), ODBC_INI);
06652     }
06653 #endif
06654     if (!dbname[0] && !dsn[0]) {
06655         strcpy(dsn, "SQLite");
06656         strncpy(dbname, buf, sizeof (dbname));
06657         dbname[sizeof (dbname) - 1] = '\0';
06658     }
06659     tracef[0] = '\0';
06660     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
06661 #ifndef WITHOUT_DRIVERMGR
06662     if (dsn[0] && !tracef[0]) {
06663         SQLGetPrivateProfileString(dsn, "tracefile", "",
06664                                    tracef, sizeof (tracef), ODBC_INI);
06665     }
06666 #endif
06667     if (connOut || connOutLen) {
06668         int count;
06669 
06670         buf[0] = '\0';
06671         count = snprintf(buf, sizeof (buf),
06672                          "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s;"
06673                          "SyncPragma=%s;NoTXN=%s;LongNames=%s;Tracefile=%s",
06674                          dsn, dbname, sflag, busy, spflag, ntflag,
06675                          lnflag, tracef);
06676         if (count < 0) {
06677             buf[sizeof (buf) - 1] = '\0';
06678         }
06679         len = min(connOutMax - 1, strlen(buf));
06680         if (connOut) {
06681             strncpy((char *) connOut, buf, len);
06682             connOut[len] = '\0';
06683         }
06684         if (connOutLen) {
06685             *connOutLen = len;
06686         }
06687     }
06688     if (tracef[0] != '\0') {
06689         d->trace = fopen(tracef, "a");
06690     }
06691     d->longnames = getbool(lnflag);
06692     return dbopen(d, dbname, dsn, sflag, spflag, ntflag, busy);
06693 }
06694 #endif
06695 
06696 /* see doc on top */
06697 
06698 static SQLRETURN
06699 freestmt(SQLHSTMT stmt)
06700 {
06701     STMT *s;
06702     DBC *d;
06703 
06704     if (stmt == SQL_NULL_HSTMT) {
06705         return SQL_INVALID_HANDLE;
06706     }
06707     s = (STMT *) stmt;
06708     freeresult(s, 1);
06709     freep(&s->query);
06710     d = (DBC *) s->dbc;
06711     if (d && d->magic == DBC_MAGIC) {
06712         STMT *p, *n;
06713 
06714         p = NULL;
06715         n = d->stmt;
06716         while (n) {
06717             if (n == s) {
06718                 break;
06719             }
06720             p = n;
06721             n = n->next;
06722         }
06723         if (n) {
06724             if (p) {
06725                 p->next = s->next;
06726             } else {
06727                 d->stmt = s->next;
06728             }
06729         }
06730     }
06731     freeparams(s);
06732     freep(&s->bindparms);
06733     if (s->row_status0 != &s->row_status1) {
06734         freep(&s->row_status0);
06735         s->rowset_size = 1;
06736         s->row_status0 = &s->row_status1;
06737     }
06738     xfree(s);
06739     return SQL_SUCCESS;
06740 }
06741 
06749 static SQLRETURN
06750 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
06751 {
06752     DBC *d;
06753     STMT *s, *sl, *pl;
06754 
06755     if (dbc == SQL_NULL_HDBC) {
06756         return SQL_INVALID_HANDLE;
06757     }
06758     d = (DBC *) dbc;
06759     if (d->magic != DBC_MAGIC || stmt == NULL) {
06760         return SQL_INVALID_HANDLE;
06761     }
06762     s = (STMT *) xmalloc(sizeof (STMT));
06763     if (s == NULL) {
06764         *stmt = SQL_NULL_HSTMT;
06765         return SQL_ERROR;
06766     }
06767     *stmt = (SQLHSTMT) s;
06768     memset(s, 0, sizeof (STMT));
06769     s->dbc = dbc;
06770     s->ov3 = d->ov3;
06771     s->curtype = d->curtype;
06772     s->row_status0 = &s->row_status1;
06773     s->rowset_size = 1;
06774     s->longnames = d->longnames;
06775     s->retr_data = SQL_RD_ON;
06776     s->bind_type = SQL_BIND_BY_COLUMN;
06777     s->bind_offs = NULL;
06778     s->paramset_size = 1;
06779     sprintf((char *) s->cursorname, "CUR_%08lX", (long) *stmt);
06780     sl = d->stmt;
06781     pl = NULL;
06782     while (sl) {
06783         pl = sl;
06784         sl = sl->next;
06785     }
06786     if (pl) {
06787         pl->next = s;
06788     } else {
06789         d->stmt = s;
06790     }
06791     return SQL_SUCCESS;
06792 }
06793 
06801 SQLRETURN SQL_API
06802 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
06803 {
06804     return drvallocstmt(dbc, stmt);
06805 }
06806 
06814 static SQLRETURN
06815 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
06816 {
06817     STMT *s;
06818 
06819     if (stmt == SQL_NULL_HSTMT) {
06820         return SQL_INVALID_HANDLE;
06821     }
06822     s = (STMT *) stmt;
06823     switch (opt) {
06824     case SQL_RESET_PARAMS:
06825         freeparams(s);
06826         break;
06827     case SQL_UNBIND:
06828         unbindcols(s);
06829         break;
06830     case SQL_CLOSE:
06831         s3stmt_end_if(s);
06832         freeresult(s, 0);
06833         break;
06834     case SQL_DROP:
06835         s3stmt_end_if(s);
06836         return freestmt(stmt);
06837     default:
06838         setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
06839         return SQL_ERROR;
06840     }
06841     return SQL_SUCCESS;
06842 }
06843 
06851 SQLRETURN SQL_API
06852 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
06853 {
06854     return drvfreestmt(stmt, opt);
06855 }
06856 
06863 SQLRETURN SQL_API
06864 SQLCancel(SQLHSTMT stmt)
06865 {
06866     return drvfreestmt(stmt, SQL_CLOSE);
06867 }
06868 
06878 static SQLRETURN
06879 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
06880                  SQLSMALLINT *lenp)
06881 {
06882     STMT *s;
06883 
06884     if (stmt == SQL_NULL_HSTMT) {
06885         return SQL_INVALID_HANDLE;
06886     }
06887     s = (STMT *) stmt;
06888     if (lenp && !cursor) {
06889         *lenp = strlen((char *) s->cursorname);
06890         return SQL_SUCCESS;
06891     }
06892     if (cursor) {
06893         if (buflen > 0) {
06894             strncpy((char *) cursor, (char *) s->cursorname, buflen - 1);
06895             cursor[buflen - 1] = '\0';
06896         }
06897         if (lenp) {
06898             *lenp = min(strlen((char *) s->cursorname), buflen - 1);
06899         }
06900     }
06901     return SQL_SUCCESS;
06902 }
06903 
06913 SQLRETURN SQL_API
06914 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
06915                  SQLSMALLINT *lenp)
06916 {
06917     return drvgetcursorname(stmt, cursor, buflen, lenp);
06918 }
06919 
06928 static SQLRETURN
06929 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
06930 {
06931     STMT *s;
06932 
06933     if (stmt == SQL_NULL_HSTMT) {
06934         return SQL_INVALID_HANDLE;
06935     }
06936     s = (STMT *) stmt;
06937     if (!cursor ||
06938         !((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
06939           (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
06940         setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
06941         return SQL_ERROR;
06942     }
06943     if (len == SQL_NTS) {
06944         len = sizeof (s->cursorname) - 1;
06945     } else {
06946         len = min(sizeof (s->cursorname) - 1, len);
06947     }
06948     strncpy((char *) s->cursorname, (char *) cursor, len);
06949     s->cursorname[len] = '\0';
06950     return SQL_SUCCESS;
06951 }
06952 
06961 SQLRETURN SQL_API
06962 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
06963 {
06964     return drvsetcursorname(stmt, cursor, len);
06965 }
06966 
06973 SQLRETURN SQL_API
06974 SQLCloseCursor(SQLHSTMT stmt)
06975 {
06976     return drvfreestmt(stmt, SQL_CLOSE);
06977 }
06978 
06979 #if defined(WITHOUT_DRIVERMGR) || !defined(HAVE_IODBC) || defined(_WIN32)
06980 
06989 SQLRETURN SQL_API
06990 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
06991 {
06992     SQLRETURN ret;
06993 
06994     switch (type) {
06995     case SQL_HANDLE_ENV:
06996         ret = drvallocenv((SQLHENV *) output);
06997         if (ret == SQL_SUCCESS) {
06998             ENV *e = (ENV *) *output;
06999 
07000             if (e && e->magic == ENV_MAGIC) {
07001                 e->ov3 = 1;
07002             }
07003         }
07004         return ret;
07005     case SQL_HANDLE_DBC:
07006         return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
07007     case SQL_HANDLE_STMT:
07008         return drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
07009     }
07010     return SQL_ERROR;
07011 }
07012 #endif
07013 
07014 #if defined(WITHOUT_DRIVERMGR) || !defined(HAVE_IODBC) || defined(_WIN32)
07015 
07023 SQLRETURN SQL_API
07024 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
07025 {
07026     switch (type) {
07027     case SQL_HANDLE_ENV:
07028         return drvfreeenv((SQLHENV) h);
07029     case SQL_HANDLE_DBC:
07030         return drvfreeconnect((SQLHDBC) h);
07031     case SQL_HANDLE_STMT:
07032         return drvfreestmt((SQLHSTMT) h, SQL_DROP);
07033     }
07034     return SQL_ERROR;
07035 }
07036 #endif
07037 
07043 static void
07044 freedyncols(STMT *s)
07045 {
07046     if (s->dyncols) {
07047         int i;
07048 
07049         for (i = 0; i < s->dcols; i++) {
07050             freep(&s->dyncols[i].typename);
07051         }
07052         if (s->cols == s->dyncols) {
07053             s->cols = NULL;
07054             s->ncols = 0;
07055         }
07056         freep(&s->dyncols);
07057     }
07058     s->dcols = 0;
07059 }
07060 
07061 /* see doc on top */
07062 
07063 static void
07064 freeresult(STMT *s, int clrcols)
07065 {
07066     freep(&s->bincache);
07067     s->bincell = NULL;
07068     s->binlen = 0;
07069     if (s->rows) {
07070         if (s->rowfree) {
07071             s->rowfree(s->rows);
07072             s->rowfree = NULL;
07073         }
07074         s->rows = NULL;
07075     }
07076     s->nrows = -1;
07077     if (clrcols > 0) {
07078         freep(&s->bindcols);
07079         s->nbindcols = 0;
07080     }
07081     if (clrcols) {
07082         freedyncols(s);
07083         s->cols = NULL;
07084         s->ncols = 0;
07085     }
07086 }
07087 
07088 /* see doc on top */
07089 
07090 static void
07091 unbindcols(STMT *s)
07092 {
07093     int i;
07094 
07095     s->bkmrkcol.type = -1;
07096     s->bkmrkcol.max = 0;
07097     s->bkmrkcol.lenp = NULL;
07098     s->bkmrkcol.valp = NULL;
07099     s->bkmrkcol.index = 0;
07100     s->bkmrkcol.offs = 0;
07101     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
07102         s->bindcols[i].type = -1;
07103         s->bindcols[i].max = 0;
07104         s->bindcols[i].lenp = NULL;
07105         s->bindcols[i].valp = NULL;
07106         s->bindcols[i].index = i;
07107         s->bindcols[i].offs = 0;
07108     }
07109 }
07110 
07111 /* see doc on top */
07112 
07113 static SQLRETURN
07114 mkbindcols(STMT *s, int ncols)
07115 {
07116     if (s->bindcols) {
07117         if (s->nbindcols < ncols) {
07118             int i;
07119             BINDCOL *bindcols =
07120                 xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
07121 
07122             if (!bindcols) {
07123                 return nomem(s);
07124             }
07125             for (i = s->nbindcols; i < ncols; i++) {
07126                 bindcols[i].type = -1;
07127                 bindcols[i].max = 0;
07128                 bindcols[i].lenp = NULL;
07129                 bindcols[i].valp = NULL;
07130                 bindcols[i].index = i;
07131                 bindcols[i].offs = 0;
07132             }
07133             s->bindcols = bindcols;
07134             s->nbindcols = ncols;
07135         }
07136     } else if (ncols > 0) {
07137         s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
07138         if (!s->bindcols) {
07139             return nomem(s);
07140         }
07141         s->nbindcols = ncols;
07142         unbindcols(s);
07143     }
07144     return SQL_SUCCESS;
07145 }
07146 
07160 static SQLRETURN
07161 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
07162            SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp, int partial)
07163 {
07164     char **data, valdummy[16];
07165     SQLLEN dummy;
07166     int valnull = 0;
07167     int type = otype;
07168 
07169     if (!s->rows) {
07170         return SQL_NO_DATA;
07171     }
07172     if (col >= s->ncols) {
07173         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
07174         return SQL_ERROR;
07175     }
07176     if (s->rowp < 0 || s->rowp >= s->nrows) {
07177         return SQL_NO_DATA;
07178     }
07179     if (s->retr_data != SQL_RD_ON) {
07180         return SQL_SUCCESS;
07181     }
07182     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0);
07183 #if 0
07184     if (otype == SQL_C_CHAR) {
07185         switch (s->cols[col].type) {
07186         case SQL_BINARY:
07187         case SQL_VARBINARY:
07188         case SQL_LONGVARBINARY:
07189             type = SQL_C_BINARY;
07190             break;
07191         }
07192     }
07193 #endif
07194     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
07195     if (!lenp) {
07196         lenp = &dummy;
07197     }
07198     if (!val) {
07199         valnull = 1;
07200         val = (SQLPOINTER) valdummy;
07201     }
07202     if (*data == NULL) {
07203         *lenp = SQL_NULL_DATA;
07204         switch (type) {
07205         case SQL_C_UTINYINT:
07206         case SQL_C_TINYINT:
07207         case SQL_C_STINYINT:
07208 #ifdef SQL_BIT
07209         case SQL_C_BIT:
07210 #endif
07211             *((char *) val) = 0;
07212             break;
07213         case SQL_C_USHORT:
07214         case SQL_C_SHORT:
07215         case SQL_C_SSHORT:
07216             *((short *) val) = 0;
07217             break;
07218         case SQL_C_ULONG:
07219         case SQL_C_LONG:
07220         case SQL_C_SLONG:
07221             *((long *) val) = 0;
07222             break;
07223 #ifdef SQL_BIGINT
07224         case SQL_C_SBIGINT:
07225         case SQL_C_UBIGINT:
07226             *((SQLBIGINT *) val) = 0;
07227             break;
07228 #endif
07229         case SQL_C_FLOAT:
07230             *((float *) val) = 0;
07231             break;
07232         case SQL_C_DOUBLE:
07233             *((double *) val) = 0;
07234             break;
07235         case SQL_C_BINARY:
07236         case SQL_C_CHAR:
07237             *((char *) val) = '\0';
07238             break;
07239 #ifdef SQL_C_TYPE_DATE
07240         case SQL_C_TYPE_DATE:
07241 #endif
07242         case SQL_C_DATE:
07243             memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
07244             break;
07245 #ifdef SQL_C_TYPE_TIME
07246         case SQL_C_TYPE_TIME:
07247 #endif
07248         case SQL_C_TIME:
07249             memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
07250             break;
07251 #ifdef SQL_C_TYPE_TIMESTAMP
07252         case SQL_C_TYPE_TIMESTAMP:
07253 #endif
07254         case SQL_C_TIMESTAMP:
07255             memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
07256             break;
07257         default:
07258             return SQL_ERROR;
07259         }
07260     } else {
07261         char *endp = NULL;
07262 #ifdef _WIN32
07263 #ifdef SQL_BIGINT
07264         char endc;
07265 #endif
07266 #endif
07267 
07268         switch (type) {
07269         case SQL_C_UTINYINT:
07270         case SQL_C_TINYINT:
07271         case SQL_C_STINYINT:
07272             *((char *) val) = strtol(*data, &endp, 0);
07273             if (endp && endp == *data) {
07274                 *lenp = SQL_NULL_DATA;
07275             } else {
07276                 *lenp = sizeof (char);
07277             }
07278             break;
07279 #ifdef SQL_BIT
07280         case SQL_C_BIT:
07281             *((char *) val) = getbool(*data);
07282             *lenp = sizeof (char);
07283             break;
07284 #endif
07285         case SQL_C_USHORT:
07286         case SQL_C_SHORT:
07287         case SQL_C_SSHORT:
07288             *((short *) val) = strtol(*data, &endp, 0);
07289             if (endp && endp == *data) {
07290                 *lenp = SQL_NULL_DATA;
07291             } else {
07292                 *lenp = sizeof (short);
07293             }
07294             break;
07295         case SQL_C_ULONG:
07296         case SQL_C_LONG:
07297         case SQL_C_SLONG:
07298             *((int *) val) = strtol(*data, &endp, 0);
07299             if (endp && endp == *data) {
07300                 *lenp = SQL_NULL_DATA;
07301             } else {
07302                 *lenp = sizeof (int);
07303             }
07304             break;
07305 #ifdef SQL_BIGINT
07306         case SQL_C_UBIGINT:
07307 #ifdef _WIN32
07308             if (sscanf(*data, "%I64u%c", (SQLUBIGINT *) val, &endc) != 1) {
07309                 *lenp = SQL_NULL_DATA;
07310             } else {
07311                 *lenp = sizeof (SQLUBIGINT);
07312             }
07313 #else
07314             *((SQLUBIGINT *) val) = strtoull(*data, &endp, 0);
07315             if (endp && endp == *data) {
07316                 *lenp = SQL_NULL_DATA;
07317             } else {
07318                 *lenp = sizeof (SQLUBIGINT);
07319             }
07320 #endif
07321             break;
07322         case SQL_C_SBIGINT:
07323 #ifdef _WIN32
07324             if (sscanf(*data, "%I64d%c", (SQLBIGINT *) val, &endc) != 1) {
07325                 *lenp = SQL_NULL_DATA;
07326             } else {
07327                 *lenp = sizeof (SQLBIGINT);
07328             }
07329 #else
07330             *((SQLBIGINT *) val) = strtoll(*data, &endp, 0);
07331             if (endp && endp == *data) {
07332                 *lenp = SQL_NULL_DATA;
07333             } else {
07334                 *lenp = sizeof (int);
07335             }
07336 #endif
07337             break;
07338 #endif
07339         case SQL_C_FLOAT:
07340             *((float *) val) = ln_strtod(*data, &endp);
07341             if (endp && endp == *data) {
07342                 *lenp = SQL_NULL_DATA;
07343             } else {
07344                 *lenp = sizeof (float);
07345             }
07346             break;
07347         case SQL_C_DOUBLE:
07348             *((double *) val) = ln_strtod(*data, &endp);
07349             if (endp && endp == *data) {
07350                 *lenp = SQL_NULL_DATA;
07351             } else {
07352                 *lenp = sizeof (double);
07353             }
07354             break;
07355         case SQL_C_BINARY: {
07356             int dlen, offs = 0;
07357             char *bin;
07358 
07359             if (valnull) {
07360                 freep(&s->bincache);
07361                 s->binlen = 0;
07362                 goto doCHAR;
07363             }
07364             if (*data == s->bincell) {
07365                 if (s->bincache) {
07366                     bin = s->bincache;
07367                     dlen = s->binlen;
07368                 } else {
07369                     goto doCHAR;
07370                 }
07371             } else {
07372                 char *dp;
07373                 int i;
07374 
07375                 freep(&s->bincache);
07376                 dp = *data;
07377                 dlen = strlen(dp);
07378                 s->bincell = dp;
07379                 s->binlen = 0;
07380                 if (!(dp[0] == 'x' || dp[0] == 'X') || dp[1] != '\'' ||
07381                     dp[dlen - 1] != '\'') {
07382                     goto doCHAR;
07383                 }
07384                 dlen -= 2;
07385                 dp += 2;
07386                 dlen = dlen / 2;
07387                 s->bincache = bin = xmalloc(dlen);
07388                 if (!bin) {
07389                     return nomem(s);
07390                 }
07391                 s->binlen = dlen;
07392                 memset(s->bincache, 0, dlen);
07393                 for (i = 0; i < dlen; i++) {
07394                     char *x;
07395                     int v;
07396 
07397                     if (!*dp || !(x = strchr(xdigits, *dp))) {
07398                         goto converr;
07399                     }
07400                     v = x - xdigits;
07401                     bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
07402                     ++dp;
07403                     if (!*dp || !(x = strchr(xdigits, *dp))) {
07404 converr:
07405                         freep(&s->bincache);
07406                         s->binlen = 0;
07407                         setstat(s, -1, "conversion error",
07408                                 (*s->ov3) ? "HY000" : "S1000");
07409                         return SQL_ERROR;
07410                     }
07411                     v = x - xdigits;
07412                     bin[i] |= (v >= 16) ? (v - 6) : v;
07413                     ++dp;
07414                 }
07415                 bin = s->bincache;
07416             }
07417             if (partial && len && s->bindcols) {
07418                 if (dlen && s->bindcols[col].offs >= dlen) {
07419                     s->bindcols[col].offs = 0;
07420                     return SQL_NO_DATA;
07421                 }
07422                 offs = s->bindcols[col].offs;
07423                 dlen -= offs;
07424             }
07425             if (val && len) {
07426                 memcpy(val, bin + offs, len);
07427             }
07428             if (len < 1) {
07429                 *lenp = dlen;
07430             } else {
07431                 *lenp = min(len, dlen);
07432                 if (*lenp == len && *lenp != dlen) {
07433                     *lenp = SQL_NO_TOTAL;
07434                 }
07435             }
07436             if (partial && len && s->bindcols) {
07437                 if (*lenp == SQL_NO_TOTAL) {
07438                     s->bindcols[col].offs += len;
07439                     setstat(s, -1, "data right truncated", "01004");
07440                     if (s->bindcols[col].lenp) {
07441                         *s->bindcols[col].lenp = dlen;
07442                     }
07443                     return SQL_SUCCESS_WITH_INFO;
07444                 }
07445                 s->bindcols[col].offs += *lenp;
07446             }
07447             break;
07448         }
07449         doCHAR:
07450         case SQL_C_CHAR: {
07451             int doz;
07452             int dlen = strlen(*data);
07453             int offs = 0;
07454 
07455             doz = type == SQL_C_CHAR ? 1 : 0;
07456             if (partial && len && s->bindcols) {
07457                 if (dlen && s->bindcols[col].offs >= dlen) {
07458                     s->bindcols[col].offs = 0;
07459                     return SQL_NO_DATA;
07460                 }
07461                 offs = s->bindcols[col].offs;
07462                 dlen -= offs;
07463             }
07464             if (val && !valnull && len) {
07465                 strncpy(val, *data + offs, len - doz);
07466             }
07467             if (valnull || len < 1) {
07468                 *lenp = dlen;
07469             } else {
07470                 *lenp = min(len - doz, dlen);
07471                 if (*lenp == len - doz && *lenp != dlen) {
07472                     *lenp = SQL_NO_TOTAL;
07473                 }
07474             }
07475             if (len && !valnull && doz) {
07476                 ((char *) val)[len - 1] = '\0';
07477             }
07478             if (partial && len && s->bindcols) {
07479                 if (*lenp == SQL_NO_TOTAL) {
07480                     s->bindcols[col].offs += len - doz;
07481                     setstat(s, -1, "data right truncated", "01004");
07482                     if (s->bindcols[col].lenp) {
07483                         *s->bindcols[col].lenp = dlen;
07484                     }
07485                     return SQL_SUCCESS_WITH_INFO;
07486                 }
07487                 s->bindcols[col].offs += *lenp;
07488             }
07489             break;
07490         }
07491 #ifdef SQL_C_TYPE_DATE
07492         case SQL_C_TYPE_DATE:
07493 #endif
07494         case SQL_C_DATE:
07495             if (str2date(*data, (DATE_STRUCT *) val) < 0) {
07496                 *lenp = SQL_NULL_DATA;
07497             } else {
07498                 *lenp = sizeof (DATE_STRUCT);
07499             }
07500             break;
07501 #ifdef SQL_C_TYPE_TIME
07502         case SQL_C_TYPE_TIME:
07503 #endif
07504         case SQL_C_TIME:
07505             if (str2time(*data, (TIME_STRUCT *) val) < 0) {
07506                 *lenp = SQL_NULL_DATA;
07507             } else {
07508                 *lenp = sizeof (TIME_STRUCT);
07509             }
07510             break;
07511 #ifdef SQL_C_TYPE_TIMESTAMP
07512         case SQL_C_TYPE_TIMESTAMP:
07513 #endif
07514         case SQL_C_TIMESTAMP:
07515             if (str2timestamp(*data, (TIMESTAMP_STRUCT *) val) < 0) {
07516                 *lenp = SQL_NULL_DATA;
07517             } else {
07518                 *lenp = sizeof (TIMESTAMP_STRUCT);
07519             }
07520             break;
07521         default:
07522             return SQL_ERROR;
07523         }
07524     }
07525     return SQL_SUCCESS;
07526 }
07527 
07539 SQLRETURN SQL_API
07540 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
07541            SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
07542 {
07543     STMT *s;
07544 
07545     if (stmt == SQL_NULL_HSTMT) {
07546         return SQL_INVALID_HANDLE;
07547     }
07548     s = (STMT *) stmt;
07549     if (col < 1) {
07550         if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
07551             s->bkmrkcol.type = type;
07552             s->bkmrkcol.max = max;
07553             s->bkmrkcol.lenp = lenp;
07554             s->bkmrkcol.valp = val;
07555             s->bkmrkcol.offs = 0;
07556             if (lenp) {
07557                 *lenp = 0;
07558             }
07559             return SQL_SUCCESS;
07560         }
07561         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
07562         return SQL_ERROR;
07563     }
07564     if (mkbindcols(s, col) != SQL_SUCCESS) {
07565         return SQL_ERROR;
07566     }
07567     --col;
07568     if (type == SQL_C_DEFAULT) {
07569         type = mapdeftype(type, s->cols[col].type, 0);
07570     } else {
07571         switch (type) {
07572         case SQL_C_LONG:
07573         case SQL_C_ULONG:
07574         case SQL_C_SLONG:
07575         case SQL_C_TINYINT:
07576         case SQL_C_UTINYINT:
07577         case SQL_C_STINYINT:
07578         case SQL_C_SHORT:
07579         case SQL_C_USHORT:
07580         case SQL_C_SSHORT:
07581         case SQL_C_FLOAT:
07582         case SQL_C_DOUBLE:
07583         case SQL_C_TIMESTAMP:
07584         case SQL_C_TIME:
07585         case SQL_C_DATE:
07586         case SQL_C_CHAR:
07587 #ifdef SQL_C_TYPE_DATE
07588         case SQL_C_TYPE_DATE:
07589 #endif
07590 #ifdef SQL_C_TYPE_TIME
07591         case SQL_C_TYPE_TIME:
07592 #endif
07593 #ifdef SQL_C_TYPE_TIMESTAMP
07594         case SQL_C_TYPE_TIMESTAMP:
07595 #endif
07596 #ifdef SQL_BIT
07597         case SQL_C_BIT:
07598 #endif
07599             break;
07600         case SQL_C_BINARY:
07601             break;
07602 #ifdef SQL_BIGINT
07603         case SQL_C_SBIGINT:
07604         case SQL_C_UBIGINT:
07605             break;
07606 #endif
07607         default:
07608             setstat(s, -1, "invalid type %d", "HY003", type);
07609             return SQL_ERROR;
07610         }
07611     }
07612     if (max < 0) {
07613         setstat(s, -1, "invalid length", "HY090");
07614         return SQL_ERROR;
07615     }
07616     s->bindcols[col].type = type;
07617     s->bindcols[col].max = max;
07618     s->bindcols[col].lenp = lenp;
07619     s->bindcols[col].valp = val;
07620     s->bindcols[col].offs = 0;
07621     if (lenp) {
07622         *lenp = 0;
07623     }
07624     return SQL_SUCCESS; 
07625 }
07626 
07631 static COL tableSpec[] = {
07632     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
07633     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
07634     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
07635     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
07636     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
07637 };
07638 
07653 static SQLRETURN
07654 drvtables(SQLHSTMT stmt,
07655           SQLCHAR *cat, SQLSMALLINT catLen,
07656           SQLCHAR *schema, SQLSMALLINT schemaLen,
07657           SQLCHAR *table, SQLSMALLINT tableLen,
07658           SQLCHAR *type, SQLSMALLINT typeLen)
07659 {
07660     SQLRETURN ret;
07661     STMT *s;
07662     DBC *d;
07663     int ncols, rc;
07664     char *errp = NULL, *sql, tname[512];
07665     char *where = "(type = 'table' or type = 'view')";
07666 
07667     ret = mkresultset(stmt, tableSpec, array_size(tableSpec));
07668     if (ret != SQL_SUCCESS) {
07669         return ret;
07670     }
07671     s = (STMT *) stmt;
07672     d = (DBC *) s->dbc;
07673     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
07674         int size = 3 * array_size(tableSpec);
07675 
07676         s->rows = xmalloc(size * sizeof (char *));
07677         if (!s->rows) {
07678             s->nrows = 0;
07679             return nomem(s);
07680         }
07681         memset(s->rows, 0, sizeof (char *) * size);
07682         s->ncols = array_size(tableSpec);
07683         s->rows[s->ncols + 0] = "";
07684         s->rows[s->ncols + 1] = "";
07685         s->rows[s->ncols + 2] = "";
07686         s->rows[s->ncols + 3] = "TABLE";
07687         s->rows[s->ncols + 5] = "";
07688         s->rows[s->ncols + 6] = "";
07689         s->rows[s->ncols + 7] = "";
07690         s->rows[s->ncols + 8] = "VIEW";
07691 #ifdef MEMORY_DEBUG
07692         s->rowfree = xfree__;
07693 #else
07694         s->rowfree = free;
07695 #endif
07696         s->nrows = 2;
07697         s->rowp = -1;
07698         return SQL_SUCCESS;
07699     }
07700     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
07701         int size = 2 * array_size(tableSpec);
07702 
07703         s->rows = xmalloc(size * sizeof (char *));
07704         if (!s->rows) {
07705             s->nrows = 0;
07706             return nomem(s);
07707         }
07708         memset(s->rows, 0, sizeof (char *) * size);
07709         s->ncols = array_size(tableSpec);
07710         s->rows[s->ncols + 0] = "";
07711         s->rows[s->ncols + 1] = "";
07712         s->rows[s->ncols + 2] = d->dbname;
07713         s->rows[s->ncols + 3] = "CATALOG";
07714 #ifdef MEMORY_DEBUG
07715         s->rowfree = xfree__;
07716 #else
07717         s->rowfree = free;
07718 #endif
07719         s->nrows = 1;
07720         s->rowp = -1;
07721         return SQL_SUCCESS;
07722     }
07723     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
07724         schema[0] == '%') {
07725         if ((!cat || catLen == 0 || !cat[0]) &&
07726             (!table || tableLen == 0 || !table[0])) {
07727             int size = 2 * array_size(tableSpec);
07728 
07729             s->rows = xmalloc(size * sizeof (char *));
07730             if (!s->rows) {
07731                 s->nrows = 0;
07732                 return nomem(s);
07733             }
07734             memset(s->rows, 0, sizeof (char *) * size);
07735             s->ncols = array_size(tableSpec);
07736             s->rows[s->ncols + 1] = "";
07737 #ifdef MEMORY_DEBUG
07738             s->rowfree = xfree__;
07739 #else
07740             s->rowfree = free;
07741 #endif
07742             s->nrows = 1;
07743             s->rowp = -1;
07744             return SQL_SUCCESS;
07745         }
07746     }
07747     if (type) {
07748         char tmp[256], *t;
07749         int with_view = 0, with_table = 0;
07750 
07751         if (typeLen == SQL_NTS) {
07752             strncpy(tmp, (char *) type, sizeof (tmp));
07753             tmp[sizeof (tmp) - 1] = '\0';
07754         } else {
07755             int len = min(sizeof (tmp) - 1, typeLen);
07756 
07757             strncpy(tmp, (char *) type, len);
07758             tmp[len] = '\0';
07759         }
07760         t = tmp;
07761         while (*t) {
07762             *t = TOLOWER(*t);
07763             t++;
07764         }
07765         t = tmp;
07766         while (t) {
07767             if (t[0] == '\'') {
07768                 ++t;
07769             }
07770             if (strncmp(t, "table", 5) == 0) {
07771                 with_table++;
07772             } else if (strncmp(t, "view", 4) == 0) {
07773                 with_view++;
07774             }
07775             t = strchr(t, ',');
07776             if (t) {
07777                 ++t;
07778             }
07779         }
07780         if (with_view && with_table) {
07781             /* where is already preset */
07782         } else if (with_view && !with_table) {
07783             where = "type = 'view'";
07784         } else if (!with_view && with_table) {
07785             where = "type = 'table'";
07786         } else {
07787             s->rowp = -1;
07788             return SQL_SUCCESS;
07789         }
07790     }
07791     strcpy(tname, "%");
07792     if (table && (tableLen > 0 || tableLen == SQL_NTS) && table[0] != '%') {
07793         int size;
07794 
07795         if (tableLen == SQL_NTS) {
07796             size = sizeof (tname) - 1;
07797         } else {
07798             size = min(sizeof (tname) - 1, tableLen);
07799         }
07800         strncpy(tname, (char *) table, size);
07801         tname[size] = '\0';
07802     }
07803     sql = sqlite3_mprintf("select '' as 'TABLE_QUALIFIER', "
07804                           "'' as 'TABLE_OWNER', "
07805                           "tbl_name as 'TABLE_NAME', "
07806                           "upper(type) as 'TABLE_TYPE', "
07807                           "NULL as 'REMARKS' "
07808                           "from sqlite_master where %s "
07809                           "and tbl_name like '%q'", where, tname);
07810     if (!sql) {
07811         return nomem(s);
07812     }
07813     dbtraceapi(d, "sqlite3_get_table", sql);
07814     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
07815     sqlite3_free(sql);
07816     if (rc == SQLITE_OK) {
07817         if (ncols != s->ncols) {
07818             freeresult(s, 0);
07819             s->nrows = 0;
07820         } else {
07821             s->rowfree = sqlite3_free_table;
07822         }
07823     } else {
07824         s->nrows = 0;
07825         s->rows = NULL;
07826         s->rowfree = NULL;
07827     }
07828     if (errp) {
07829         sqlite3_free(errp);
07830         errp = NULL;
07831     }
07832     s->rowp = -1;
07833     return SQL_SUCCESS;
07834 }
07835 
07850 SQLRETURN SQL_API
07851 SQLTables(SQLHSTMT stmt,
07852           SQLCHAR *cat, SQLSMALLINT catLen,
07853           SQLCHAR *schema, SQLSMALLINT schemaLen,
07854           SQLCHAR *table, SQLSMALLINT tableLen,
07855           SQLCHAR *type, SQLSMALLINT typeLen)
07856 {
07857     return drvtables(stmt, cat, catLen, schema, schemaLen,
07858                      table, tableLen, type, typeLen);
07859 }
07860 
07865 static COL colSpec[] = {
07866     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
07867     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
07868     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
07869     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
07870     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
07871     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
07872     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
07873     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
07874     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
07875     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
07876     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
07877     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
07878     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
07879     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
07880     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
07881     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
07882     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
07883     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
07884 };
07885 
07900 static SQLRETURN
07901 drvcolumns(SQLHSTMT stmt,
07902            SQLCHAR *cat, SQLSMALLINT catLen,
07903            SQLCHAR *schema, SQLSMALLINT schemaLen,
07904            SQLCHAR *table, SQLSMALLINT tableLen,
07905            SQLCHAR *col, SQLSMALLINT colLen)
07906 {
07907     SQLRETURN sret;
07908     STMT *s;
07909     DBC *d;
07910     int ret, nrows, ncols, size, i, k;
07911     char *errp = NULL, *sql, tname[512], **rowp;
07912 
07913     sret = mkresultset(stmt, colSpec, array_size(colSpec));
07914     if (sret != SQL_SUCCESS) {
07915         return sret;
07916     }
07917     s = (STMT *) stmt;
07918     d = (DBC *) s->dbc;
07919     if (!table || table[0] == '\0' || table[0] == '%') {
07920         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
07921         return SQL_ERROR;
07922     }
07923     if (tableLen == SQL_NTS) {
07924         size = sizeof (tname) - 1;
07925     } else {
07926         size = min(sizeof (tname) - 1, tableLen);
07927     }
07928     strncpy(tname, (char *) table, size);
07929     tname[size] = '\0';
07930     sql = sqlite3_mprintf("PRAGMA table_info('%q')", tname);
07931     if (!sql) {
07932         return nomem(s);
07933     }
07934     dbtraceapi(d, "sqlite3_get_table", sql);
07935     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
07936     sqlite3_free(sql);
07937     if (ret != SQLITE_OK) {
07938         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
07939                 errp ? errp : "unknown error", ret);
07940         if (errp) {
07941             sqlite3_free(errp);
07942             errp = NULL;
07943         }
07944         return SQL_ERROR;       
07945     }
07946     if (errp) {
07947         sqlite3_free(errp);
07948         errp = NULL;
07949     }
07950     if (ncols * nrows <= 0) {
07951         sqlite3_free_table(rowp);
07952         return SQL_NO_DATA;
07953     }
07954     size = array_size(colSpec) * (nrows + 1);
07955     s->rows = xmalloc((size + 1) * sizeof (char *));
07956     if (!s->rows) {
07957         return nomem(s);
07958     }
07959     s->rows[0] = (char *) size;
07960     s->rows += 1;
07961     memset(s->rows, 0, sizeof (char *) * size);
07962     s->rowfree = freerows;
07963     s->nrows = nrows;
07964     for (i = 1; i <= s->nrows; i++) {
07965         s->rows[array_size(colSpec) * i + 0] = xstrdup("");
07966         s->rows[array_size(colSpec) * i + 1] = xstrdup("");
07967         s->rows[array_size(colSpec) * i + 2] = xstrdup(tname);
07968         s->rows[array_size(colSpec) * i + 8] = xstrdup("10");
07969         s->rows[array_size(colSpec) * i + 9] = xstrdup("0");
07970         s->rows[array_size(colSpec) * i + 15] = xstrdup("16384");
07971     }
07972     for (k = 0; k < ncols; k++) {
07973         if (strcmp(rowp[k], "cid") == 0) {
07974             for (i = 1; i <= s->nrows; i++) {
07975                 char buf[256];
07976                 int coln = i;
07977 
07978                 sscanf(rowp[i * ncols + k], "%d", &coln);
07979                 sprintf(buf, "%d", coln + 1);
07980                 s->rows[array_size(colSpec) * i + 16] = xstrdup(buf);
07981             }
07982         } else if (strcmp(rowp[k], "name") == 0) {
07983             for (i = 1; i <= s->nrows; i++) {
07984                 s->rows[array_size(colSpec) * i + 3] =
07985                     xstrdup(rowp[i * ncols + k]);
07986             }
07987         } else if (strcmp(rowp[k], "notnull") == 0) {
07988             for (i = 1; i <= s->nrows; i++) {
07989                 if (*rowp[i * ncols + k] != '0') {
07990                     s->rows[array_size(colSpec) * i + 10] =
07991                         xstrdup(stringify(SQL_FALSE));
07992                 } else {
07993                     s->rows[array_size(colSpec) * i + 10] =
07994                         xstrdup(stringify(SQL_TRUE));
07995                 }
07996                 s->rows[array_size(colSpec) * i + 17] =
07997                     xstrdup(*rowp[i * ncols + k] != '0' ? "NO" : "YES");
07998             }
07999         } else if (strcmp(rowp[k], "dflt_value") == 0) {
08000             for (i = 1; i <= s->nrows; i++) {
08001                 char *dflt = rowp[i * ncols + k];
08002 
08003                 s->rows[array_size(colSpec) * i + 12] =
08004                     xstrdup(dflt ? dflt : "NULL");
08005             }
08006         } else if (strcmp(rowp[k], "type") == 0) {
08007             for (i = 1; i <= s->nrows; i++) {
08008                 char *typename = rowp[i * ncols + k];
08009                 int sqltype, m, d;
08010                 char buf[256];
08011 
08012                 s->rows[array_size(colSpec) * i + 5] = xstrdup(typename);
08013                 sqltype = mapsqltype(typename, NULL, *s->ov3);
08014                 getmd(typename, sqltype, &m, &d);
08015 #ifdef SQL_LONGVARCHAR
08016                 if (sqltype == SQL_VARCHAR && m > 255) {
08017                     sqltype = SQL_LONGVARCHAR;
08018                 }
08019 #endif
08020                 if (sqltype == SQL_VARBINARY && m > 255) {
08021                     sqltype = SQL_LONGVARBINARY;
08022                 }
08023                 sprintf(buf, "%d", sqltype);
08024                 s->rows[array_size(colSpec) * i + 4] = xstrdup(buf);
08025                 s->rows[array_size(colSpec) * i + 13] = xstrdup(buf);
08026                 sprintf(buf, "%d", m);
08027                 s->rows[array_size(colSpec) * i + 7] = xstrdup(buf);
08028                 sprintf(buf, "%d", d);
08029                 s->rows[array_size(colSpec) * i + 6] = xstrdup(buf);
08030             }
08031         }
08032     }
08033     sqlite3_free_table(rowp);
08034     return SQL_SUCCESS;
08035 }
08036 
08051 SQLRETURN SQL_API
08052 SQLColumns(SQLHSTMT stmt,
08053            SQLCHAR *cat, SQLSMALLINT catLen,
08054            SQLCHAR *schema, SQLSMALLINT schemaLen,
08055            SQLCHAR *table, SQLSMALLINT tableLen,
08056            SQLCHAR *col, SQLSMALLINT colLen)
08057 {
08058     return drvcolumns(stmt, cat, catLen, schema, schemaLen,
08059                       table, tableLen, col, colLen);
08060 }
08061 
08066 static COL typeSpec[] = {
08067     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
08068     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
08069     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 4 },
08070     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
08071     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
08072     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
08073     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
08074     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
08075     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
08076     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
08077     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
08078     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
08079     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
08080     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
08081     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
08082 };
08083 
08093 static void
08094 mktypeinfo(STMT *s, int row, char *typename, int type, int tind)
08095 {
08096     int offs = row * array_size(typeSpec);
08097     char *tcode, *crpar = NULL, *quote = NULL, *sign = stringify(SQL_FALSE);
08098     static char tcodes[32 * 32];
08099 
08100     if (tind <= 0) {
08101         tind = row;
08102     }
08103     tcode = tcodes + tind * 32;
08104     sprintf(tcode, "%d", type);
08105     s->rows[offs + 0] = typename;
08106     s->rows[offs + 1] = tcode;
08107     switch (type) {
08108     default:
08109 #ifdef SQL_LONGVARCHAR
08110     case SQL_LONGVARCHAR:
08111         crpar = "length";
08112         quote = "'";
08113         sign = NULL;
08114         s->rows[offs + 2] = "65536";
08115         break;
08116 #endif
08117 #ifdef SQL_BIT
08118     case SQL_BIT:
08119         sign = NULL;
08120         s->rows[offs + 2] = "1";
08121         break;
08122 #endif
08123     case SQL_CHAR:
08124     case SQL_VARCHAR:
08125         s->rows[offs + 2] = "255";
08126         crpar = "length";
08127         quote = "'";
08128         sign = NULL;
08129         break;
08130     case SQL_TINYINT:
08131         s->rows[offs + 2] = "3";
08132         break;
08133     case SQL_SMALLINT:
08134         s->rows[offs + 2] = "5";
08135         break;
08136     case SQL_INTEGER:
08137         s->rows[offs + 2] = "7";
08138         break;
08139 #ifdef SQL_BIGINT
08140     case SQL_BIGINT:
08141         s->rows[offs + 2] = "19";
08142         break;
08143 #endif
08144     case SQL_FLOAT:
08145         s->rows[offs + 2] = "7";
08146         break;
08147     case SQL_DOUBLE:
08148         s->rows[offs + 2] = "15";
08149         break;
08150 #ifdef SQL_TYPE_DATE
08151     case SQL_TYPE_DATE:
08152 #endif
08153     case SQL_DATE:
08154         s->rows[offs + 2] = "10";
08155         quote = "'";
08156         sign = NULL;
08157         break;
08158 #ifdef SQL_TYPE_TIME
08159     case SQL_TYPE_TIME:
08160 #endif
08161     case SQL_TIME:
08162         s->rows[offs + 2] = "8";
08163         quote = "'";
08164         sign = NULL;
08165         break;
08166 #ifdef SQL_TYPE_TIMESTAMP
08167     case SQL_TYPE_TIMESTAMP:
08168 #endif
08169     case SQL_TIMESTAMP:
08170         s->rows[offs + 2] = "32";
08171         quote = "'";
08172         sign = NULL;
08173         break;
08174     case SQL_VARBINARY:
08175         sign = NULL;
08176         s->rows[offs + 2] = "255";
08177         break;
08178     case SQL_LONGVARBINARY:
08179         sign = NULL;
08180         s->rows[offs + 2] = "65536";
08181         break;
08182     }
08183     s->rows[offs + 3] = s->rows[offs + 4] = quote;
08184     s->rows[offs + 5] = crpar;
08185     s->rows[offs + 6] = stringify(SQL_NULLABLE);
08186     s->rows[offs + 7] = stringify(SQL_FALSE);
08187     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
08188     s->rows[offs + 9] = sign;
08189     s->rows[offs + 10] = stringify(SQL_FALSE);
08190     s->rows[offs + 11] = stringify(SQL_FALSE);
08191     s->rows[offs + 12] = typename;
08192     s->rows[offs + 13] = NULL;
08193     s->rows[offs + 14] = NULL;
08194 }
08195 
08204 static int
08205 typeinfosort(const void *a, const void *b)
08206 {
08207     char **pa = (char **) a;
08208     char **pb = (char **) b;
08209     int na, nb;
08210 
08211     na = strtol(pa[1], NULL, 0);
08212     nb = strtol(pb[1], NULL, 0);
08213     return na - nb;
08214 }
08215 
08223 static SQLRETURN
08224 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
08225 {
08226     SQLRETURN ret;
08227     STMT *s;
08228     DBC *d;
08229 
08230     ret = mkresultset(stmt, typeSpec, array_size(typeSpec));
08231     if (ret != SQL_SUCCESS) {
08232         return ret;
08233     }
08234     s = (STMT *) stmt;
08235     d = (DBC *) s->dbc;
08236 #ifdef SQL_LONGVARCHAR
08237     s->nrows = sqltype == SQL_ALL_TYPES ? 13 : 1;
08238 #else
08239     s->nrows = sqltype == SQL_ALL_TYPES ? 12 : 1;
08240 #endif
08241     if (sqltype == SQL_ALL_TYPES) {
08242         s->nrows += 2;
08243 #ifdef SQL_BIT
08244         s->nrows += 1;
08245 #endif
08246 #ifdef SQL_BIGINT
08247         s->nrows += 1;
08248 #endif
08249     }
08250     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1)
08251                                 * array_size(typeSpec));
08252     if (!s->rows) {
08253         s->nrows = 0;
08254         return nomem(s);
08255     }
08256 #ifdef MEMORY_DEBUG
08257     s->rowfree = xfree__;
08258 #else
08259     s->rowfree = free;
08260 #endif
08261     memset(s->rows, 0,
08262            sizeof (char *) * (s->nrows + 1) * array_size(typeSpec));
08263     if (sqltype == SQL_ALL_TYPES) {
08264         int cc = 1;
08265 
08266         mktypeinfo(s, cc++, "varchar", SQL_VARCHAR, 0);
08267         mktypeinfo(s, cc++, "tinyint", SQL_TINYINT, 0);
08268         mktypeinfo(s, cc++, "smallint", SQL_SMALLINT, 0);
08269         mktypeinfo(s, cc++, "integer", SQL_INTEGER, 0);
08270         mktypeinfo(s, cc++, "float", SQL_FLOAT, 0);
08271         mktypeinfo(s, cc++, "double", SQL_DOUBLE, 0);
08272 #ifdef SQL_TYPE_DATE
08273         mktypeinfo(s, cc++, "date", (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
08274 #else
08275         mktypeinfo(s, cc++, "date", SQL_DATE, 0);
08276 #endif
08277 #ifdef SQL_TYPE_TIME
08278         mktypeinfo(s, cc++, "time", (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
08279 #else
08280         mktypeinfo(s, cc++, "time", SQL_TIME, 0);
08281 #endif
08282 #ifdef SQL_TYPE_TIMESTAMP
08283         mktypeinfo(s, cc++, "timestamp",
08284                    (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
08285 #else
08286         mktypeinfo(s, cc++, "timestamp", SQL_TIMESTAMP, 0);
08287 #endif
08288         mktypeinfo(s, cc++, "char", SQL_CHAR, 0);
08289         mktypeinfo(s, cc++, "numeric", SQL_DOUBLE, 0);
08290 #ifdef SQL_LONGVARCHAR
08291         mktypeinfo(s, cc++, "text", SQL_LONGVARCHAR, 0);
08292         mktypeinfo(s, cc++, "longvarchar", SQL_LONGVARCHAR, 0);
08293 #else
08294         mktypeinfo(s, cc++, "text", SQL_VARCHAR, 0);
08295 #endif
08296         mktypeinfo(s, cc++, "varbinary", SQL_VARBINARY, 0);
08297         mktypeinfo(s, cc++, "longvarbinary", SQL_LONGVARBINARY, 0);
08298 #ifdef SQL_BIT
08299         mktypeinfo(s, cc++, "bit", SQL_BIT, 0);
08300 #endif
08301 #ifdef SQL_BIGINT
08302         mktypeinfo(s, cc++, "bigint", SQL_BIGINT, 0);
08303 #endif
08304         qsort(s->rows + array_size(typeSpec), s->nrows,
08305               sizeof (char *) * array_size(typeSpec), typeinfosort);
08306     } else {
08307         switch (sqltype) {
08308         case SQL_CHAR:
08309             mktypeinfo(s, 1, "char", SQL_CHAR, 10);
08310             break;
08311         case SQL_VARCHAR:
08312             mktypeinfo(s, 1, "varchar", SQL_VARCHAR, 1);
08313             break;
08314         case SQL_TINYINT:
08315             mktypeinfo(s, 1, "tinyint", SQL_TINYINT, 2);
08316             break;
08317         case SQL_SMALLINT:
08318             mktypeinfo(s, 1, "smallint", SQL_SMALLINT, 3);
08319             break;
08320         case SQL_INTEGER:
08321             mktypeinfo(s, 1, "integer", SQL_INTEGER, 4);
08322             break;
08323         case SQL_FLOAT:
08324             mktypeinfo(s, 1, "float", SQL_FLOAT, 5);
08325             break;
08326         case SQL_DOUBLE:
08327             mktypeinfo(s, 1, "double", SQL_DOUBLE, 6);
08328             break;
08329 #ifdef SQL_TYPE_DATE
08330         case SQL_TYPE_DATE:
08331             mktypeinfo(s, 1, "date", SQL_TYPE_DATE, 25);
08332             break;
08333 #endif
08334         case SQL_DATE:
08335             mktypeinfo(s, 1, "date", SQL_DATE, 7);
08336             break;
08337 #ifdef SQL_TYPE_TIME
08338         case SQL_TYPE_TIME:
08339             mktypeinfo(s, 1, "date", SQL_TYPE_TIME, 26);
08340             break;
08341 #endif
08342         case SQL_TIME:
08343             mktypeinfo(s, 1, "time", SQL_TIME, 8);
08344             break;
08345 #ifdef SQL_TYPE_TIMESTAMP
08346         case SQL_TYPE_TIMESTAMP:
08347             mktypeinfo(s, 1, "date", SQL_TYPE_TIMESTAMP, 27);
08348             break;
08349 #endif
08350         case SQL_TIMESTAMP:
08351             mktypeinfo(s, 1, "timestamp", SQL_TIMESTAMP, 9);
08352             break;
08353 #ifdef SQL_LONGVARCHAR
08354         case SQL_LONGVARCHAR:
08355             mktypeinfo(s, 1, "longvarchar", SQL_LONGVARCHAR, 12);
08356             break;
08357 #endif
08358         case SQL_VARBINARY:
08359             mktypeinfo(s, 1, "varbinary", SQL_VARBINARY, 30);
08360             break;
08361         case SQL_LONGVARBINARY:
08362             mktypeinfo(s, 1, "longvarbinary", SQL_LONGVARBINARY, 31);
08363             break;
08364 #ifdef SQL_BIT
08365         case SQL_BIT:
08366             mktypeinfo(s, 1, "bit", SQL_BIT, 29);
08367             break;
08368 #endif
08369 #ifdef SQL_BIGINT
08370         case SQL_BIGINT:
08371             mktypeinfo(s, 1, "bigint", SQL_BIGINT, 28);
08372             break;
08373 #endif
08374         default:
08375             s->nrows = 0;
08376             return SQL_NO_DATA;
08377         }
08378     }
08379     return SQL_SUCCESS;
08380 }
08381 
08389 SQLRETURN SQL_API
08390 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
08391 {
08392     return drvgettypeinfo(stmt, sqltype);
08393 }
08394 
08399 static COL statSpec[] = {
08400     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
08401     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
08402     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
08403     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
08404     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
08405     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
08406     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
08407     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
08408     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
08409     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
08410     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
08411     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
08412     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
08413 };
08414 
08429 static SQLRETURN
08430 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
08431               SQLCHAR *schema, SQLSMALLINT schemaLen,
08432               SQLCHAR *table, SQLSMALLINT tableLen,
08433               SQLUSMALLINT itype, SQLUSMALLINT resv)
08434 {
08435     SQLRETURN sret;
08436     STMT *s;
08437     DBC *d;
08438     int i, size, ret, nrows, ncols, offs, namec, uniquec;
08439     char **rowp, *errp = NULL, *sql, tname[512];
08440 
08441     sret = mkresultset(stmt, statSpec, array_size(statSpec));
08442     if (sret != SQL_SUCCESS) {
08443         return sret;
08444     }
08445     s = (STMT *) stmt;
08446     d = (DBC *) s->dbc;
08447     if (!table || table[0] == '\0' || table[0] == '%') {
08448         setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
08449         return SQL_ERROR;
08450     }
08451     if (tableLen == SQL_NTS) {
08452         size = sizeof (tname) - 1;
08453     } else {
08454         size = min(sizeof (tname) - 1, tableLen);
08455     }
08456     strncpy(tname, (char *) table, size);
08457     tname[size] = '\0';
08458     sql = sqlite3_mprintf("PRAGMA index_list('%q')", tname);
08459     if (!sql) {
08460         return nomem(s);
08461     }
08462     dbtraceapi(d, "sqlite3_get_table", sql);
08463     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
08464     sqlite3_free(sql);
08465     if (ret != SQLITE_OK) {
08466         setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
08467                 errp ? errp : "unknown error", ret);
08468         if (errp) {
08469             sqlite3_free(errp);
08470             errp = NULL;
08471         }
08472         return SQL_ERROR;
08473     }
08474     if (errp) {
08475         sqlite3_free(errp);
08476         errp = NULL;
08477     }
08478     if (ncols * nrows <= 0) {
08479 nodata:
08480         sqlite3_free_table(rowp);
08481         /* try table_info for integer primary keys */
08482         if (itype == SQL_INDEX_UNIQUE) {
08483             ret = SQLITE_ERROR;
08484 
08485             sql = sqlite3_mprintf("PRAGMA table_info('%q')", tname);
08486             if (sql) {
08487                 dbtraceapi(d, "sqlite3_get_table", sql);
08488                 ret = sqlite3_get_table(d->sqlite, sql, &rowp,
08489                                         &nrows, &ncols, NULL);
08490                 sqlite3_free(sql);
08491             }
08492             if (ret == SQLITE_OK) {
08493                 int colid, typec, roffs;
08494 
08495                 namec = findcol(rowp, ncols, "name");
08496                 uniquec = findcol(rowp, ncols, "pk");
08497                 typec = findcol(rowp, ncols, "type");
08498                 colid = findcol(rowp, ncols, "cid");
08499                 if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
08500                     goto nodata2;
08501                 }
08502                 for (i = 1; i <= nrows; i++) {
08503                     if (*rowp[i * ncols + uniquec] != '0' &&
08504                         strlen(rowp[i * ncols + typec]) == 7 &&
08505                         strncasecmp(rowp[i * ncols + typec], "integer", 7)
08506                         == 0) {
08507                         break;
08508                     }
08509                 }
08510                 if (i > nrows) {
08511                     goto nodata2;
08512                 }
08513                 size = (1 + 1) * array_size(statSpec);
08514                 s->rows = xmalloc((size + 1) * sizeof (char *));
08515                 if (!s->rows) {
08516                     s->nrows = 0;
08517                     return nomem(s);
08518                 }
08519                 s->rows[0] = (char *) size;
08520                 s->rows += 1;
08521                 memset(s->rows, 0, sizeof (char *) * size);
08522                 s->rowfree = freerows;
08523                 s->nrows = 1;
08524                 roffs = s->ncols;
08525                 s->rows[roffs + 0] = xstrdup("");
08526                 s->rows[roffs + 1] = xstrdup("");
08527                 s->rows[roffs + 2] = xstrdup(tname);
08528                 s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
08529                 s->rows[roffs + 4] = xstrdup("");
08530                 s->rows[roffs + 5] = xstrdup("");
08531                 s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
08532                 s->rows[roffs + 7] = xstrdup("1");
08533                 s->rows[roffs + 8] = xstrdup(rowp[i * ncols + namec]);
08534                 s->rows[roffs + 9] = xstrdup("A");
08535 nodata2:
08536                 sqlite3_free_table(rowp);
08537             }
08538         }
08539         return SQL_SUCCESS;
08540     }
08541     size = 0;
08542     namec = findcol(rowp, ncols, "name");
08543     uniquec = findcol(rowp, ncols, "unique");
08544     if (namec < 0 || uniquec < 0) {
08545         goto nodata;
08546     }
08547     for (i = 1; i <= nrows; i++) {
08548         int nnrows, nncols;
08549         char **rowpp;
08550         int isuniq;
08551 
08552         isuniq = *rowp[i * ncols + uniquec] != '0';
08553         if (isuniq || itype == SQL_INDEX_ALL) {
08554             ret = SQLITE_ERROR;
08555             sql = sqlite3_mprintf("PRAGMA index_info('%q')", 
08556                                   rowp[i * ncols + namec]);
08557             if (sql) {
08558                 dbtraceapi(d, "sqlite3_get_table", sql);
08559                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
08560                                         &nnrows, &nncols, NULL);
08561                 sqlite3_free(sql);
08562             }
08563             if (ret == SQLITE_OK) {
08564                 size += nnrows;
08565                 sqlite3_free_table(rowpp);
08566             }
08567         }
08568     }
08569     if (size == 0) {
08570         goto nodata;
08571     }
08572     s->nrows = size;
08573     size = (size + 1) * array_size(statSpec);
08574     s->rows = xmalloc((size + 1) * sizeof (char *));
08575     if (!s->rows) {
08576         s->nrows = 0;
08577         return nomem(s);
08578     }
08579     s->rows[0] = (char *) size;
08580     s->rows += 1;
08581     memset(s->rows, 0, sizeof (char *) * size);
08582     s->rowfree = freerows;
08583     offs = 0;
08584     for (i = 1; i <= nrows; i++) {
08585         int nnrows, nncols;
08586         char **rowpp;
08587 
08588         if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
08589             int k;
08590 
08591             ret = SQLITE_ERROR;
08592             sql = sqlite3_mprintf("PRAGMA index_info('%q')", 
08593                                   rowp[i * ncols + namec]);
08594             if (sql) {
08595                 dbtraceapi(d, "sqlite3_get_table", sql);
08596                 ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
08597                                         &nnrows, &nncols, NULL);
08598                 sqlite3_free(sql);
08599             }
08600             if (ret != SQLITE_OK) {
08601                 continue;
08602             }
08603             for (k = 0; nnrows && k < nncols; k++) {
08604                 if (strcmp(rowpp[k], "name") == 0) {
08605                     int m;
08606 
08607                     for (m = 1; m <= nnrows; m++) {
08608                         int roffs = (offs + m) * s->ncols;
08609                         int isuniq;
08610 
08611                         isuniq = *rowp[i * ncols + uniquec] != '0';
08612                         s->rows[roffs + 0] = xstrdup("");
08613                         s->rows[roffs + 1] = xstrdup("");
08614                         s->rows[roffs + 2] = xstrdup(tname);
08615                         if (isuniq) {
08616                             s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
08617                         } else {
08618                             s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
08619                         }
08620                         s->rows[roffs + 4] = xstrdup("");
08621                         s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
08622                         s->rows[roffs + 6] =
08623                             xstrdup(stringify(SQL_INDEX_OTHER));
08624                         s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
08625                         s->rows[roffs + 9] = xstrdup("A");
08626                     }
08627                 } else if (strcmp(rowpp[k], "seqno") == 0) {
08628                     int m;
08629 
08630                     for (m = 1; m <= nnrows; m++) {
08631                         int roffs = (offs + m) * s->ncols;
08632                         int pos = m - 1;
08633                         char buf[32];
08634 
08635                         sscanf(rowpp[m * nncols + k], "%d", &pos);
08636                         sprintf(buf, "%d", pos + 1);
08637                         s->rows[roffs + 7] = xstrdup(buf);
08638                     }
08639                 }
08640             }
08641             offs += nnrows;
08642             sqlite3_free_table(rowpp);
08643         }
08644     }
08645     sqlite3_free_table(rowp);
08646     return SQL_SUCCESS;
08647 }
08648 
08663 SQLRETURN SQL_API
08664 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
08665               SQLCHAR *schema, SQLSMALLINT schemaLen,
08666               SQLCHAR *table, SQLSMALLINT tableLen,
08667               SQLUSMALLINT itype, SQLUSMALLINT resv)
08668 {
08669     return drvstatistics(stmt, cat, catLen, schema, schemaLen,
08670                          table, tableLen, itype, resv);
08671 }
08672 
08684 SQLRETURN SQL_API
08685 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
08686            SQLPOINTER val, SQLLEN len, SQLLEN *lenp)
08687 {
08688     STMT *s;
08689 
08690     if (stmt == SQL_NULL_HSTMT) {
08691         return SQL_INVALID_HANDLE;
08692     }
08693     s = (STMT *) stmt;
08694     if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
08695         *((long *) val) = s->rowp;
08696         if (lenp) {
08697             *lenp = sizeof (long);
08698         }
08699         return SQL_SUCCESS;
08700     }
08701     if (col < 1 || col > s->ncols) {
08702         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
08703         return SQL_ERROR;
08704     }
08705     --col;
08706     return getrowdata(s, col, type, val, len, lenp, 1);
08707 }
08708 
08716 static SQLRETURN
08717 dofetchbind(STMT *s, int rsi)
08718 {
08719     int ret, i, withinfo = 0;
08720 
08721     s->row_status0[rsi] = SQL_ROW_SUCCESS;
08722     if (s->bkmrk && s->bkmrkcol.valp) {
08723         long *val;
08724 
08725         if (s->bind_type != SQL_BIND_BY_COLUMN) {
08726             val = (long *) ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
08727         } else {
08728             val = (long *) s->bkmrkcol.valp + rsi;
08729         }
08730         if (s->bind_offs) {
08731             val = (long *) ((char *) val + *s->bind_offs);
08732         }
08733         *val = s->rowp;
08734         if (s->bkmrkcol.lenp) {
08735             SQLLEN *ival;
08736 
08737             if (s->bind_type != SQL_BIND_BY_COLUMN) {
08738                 ival = (SQLLEN *)
08739                     ((char *) s->bkmrkcol.lenp + s->bind_type * rsi);
08740             } else {
08741                 ival = &s->bkmrkcol.lenp[rsi];
08742             }
08743             if (s->bind_offs) {
08744                 ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
08745             }
08746             *ival = sizeof (long);
08747         }
08748     }
08749     ret = SQL_SUCCESS;
08750     for (i = 0; s->bindcols && i < s->ncols; i++) {
08751         BINDCOL *b = &s->bindcols[i];
08752         SQLPOINTER dp = 0;
08753         SQLLEN *lp = 0;
08754 
08755         b->offs = 0;
08756         if (b->valp) {
08757             if (s->bind_type != SQL_BIND_BY_COLUMN) {
08758                 dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
08759             } else {
08760                 dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
08761             }
08762             if (s->bind_offs) {
08763                 dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
08764             }
08765         }
08766         if (b->lenp) {
08767             if (s->bind_type != SQL_BIND_BY_COLUMN) {
08768                 lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
08769             } else {
08770                 lp = b->lenp + rsi;
08771             }
08772             if (s->bind_offs) {
08773                 lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
08774             }
08775         }
08776         if (dp || lp) {
08777             ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
08778             if (!SQL_SUCCEEDED(ret)) {
08779                 s->row_status0[rsi] = SQL_ROW_ERROR;
08780                 break;
08781             }
08782             if (ret != SQL_SUCCESS) {
08783                 withinfo = 1;
08784 #ifdef SQL_ROW_SUCCESS_WITH_INFO
08785                 s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
08786 #endif
08787             }
08788         }
08789     }
08790     if (SQL_SUCCEEDED(ret)) {
08791         ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
08792     }
08793     return ret;
08794 }
08795 
08804 static SQLRETURN
08805 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
08806 {
08807     STMT *s;
08808     int i, withinfo = 0;
08809     SQLRETURN ret;
08810 
08811     if (stmt == SQL_NULL_HSTMT) {
08812         return SQL_INVALID_HANDLE;
08813     }
08814     s = (STMT *) stmt;
08815     for (i = 0; i < s->rowset_size; i++) {
08816         s->row_status0[i] = SQL_ROW_NOROW;
08817     }
08818     if (s->row_status) {
08819         memcpy(s->row_status, s->row_status0,
08820                sizeof (SQLUSMALLINT) * s->rowset_size);
08821     }
08822     s->row_count0 = 0;
08823     if (s->row_count) {
08824         *s->row_count = s->row_count0;
08825     }
08826     if (!s->bindcols) {
08827         for (i = 0; i < s->rowset_size; i++) {
08828             s->row_status0[i] = SQL_ROW_ERROR;
08829         }
08830         ret = SQL_ERROR;
08831         i = 0;
08832         goto done2;
08833     }
08834     if (!s->isselect) {
08835         setstat(s, -1, "no result set available", "24000");
08836         ret = SQL_ERROR;
08837         i = s->nrows;
08838         goto done2;
08839     }
08840     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
08841         setstat(s, -1, "wrong fetch direction", "01000");
08842         ret = SQL_ERROR;
08843         i = 0;
08844         goto done2;
08845     }
08846     ret = SQL_SUCCESS;
08847     i = 0;
08848     if (((DBC *) (s->dbc))->cur_s3stmt == s && s->s3stmt) {
08849         s->rowp = 0;
08850         for (; i < s->rowset_size; i++) {
08851             ret = s3stmt_step(s);
08852             if (ret != SQL_SUCCESS) {
08853                 s->row_status0[i] = SQL_ROW_ERROR;
08854                 break;
08855             }
08856             if (s->nrows < 1) {
08857                 break;
08858             }
08859             ret = dofetchbind(s, i);
08860             if (!SQL_SUCCEEDED(ret)) {
08861                 break;
08862             } else if (ret == SQL_SUCCESS_WITH_INFO) {
08863                 withinfo = 1;
08864             }
08865         }
08866     } else if (s->rows) {
08867         switch (orient) {
08868         case SQL_FETCH_NEXT:
08869             if (s->nrows < 1) {
08870                 return SQL_NO_DATA;
08871             }
08872             if (s->rowp < 0) {
08873                 s->rowp = -1;
08874             }
08875             if (s->rowp >= s->nrows) {
08876                 s->rowp = s->nrows;
08877                 return SQL_NO_DATA;
08878             }
08879             break;
08880         case SQL_FETCH_PRIOR:
08881             if (s->nrows < 1) {
08882                 s->rowp = -1;
08883                 return SQL_NO_DATA;
08884             }
08885             s->rowp -= s->rowset_size + 1;
08886             if (s->rowp < -1) {
08887                 s->rowp = -1;
08888                 return SQL_NO_DATA;
08889             }
08890             break;
08891         case SQL_FETCH_FIRST:
08892             if (s->nrows < 1) {
08893                 return SQL_NO_DATA;
08894             }
08895             s->rowp = -1;
08896             break;
08897         case SQL_FETCH_LAST:
08898             if (s->nrows < 1) {
08899                 return SQL_NO_DATA;
08900             }
08901             s->rowp = s->nrows - s->rowset_size;
08902             if (--s->rowp < -1) {
08903                 s->rowp = -1;
08904             }
08905             break;
08906         case SQL_FETCH_ABSOLUTE:
08907             if (offset == 0) {
08908                 s->rowp = -1;
08909                 return SQL_NO_DATA;
08910             } else if (offset < 0) {
08911                 if (0 - offset <= s->nrows) {
08912                     s->rowp = s->nrows + offset - 1;
08913                     break;
08914                 }
08915                 s->rowp = -1;
08916                 return SQL_NO_DATA;
08917             } else if (offset > s->nrows) {
08918                 s->rowp = s->nrows;
08919                 return SQL_NO_DATA;
08920             }
08921             s->rowp = offset - 1 - 1;
08922             break;
08923         case SQL_FETCH_RELATIVE:
08924             if (offset >= 0) {
08925                 s->rowp += offset * s->rowset_size - 1;
08926                 if (s->rowp >= s->nrows) {
08927                     s->rowp = s->nrows;
08928                     return SQL_NO_DATA;
08929                 }
08930             } else {
08931                 s->rowp += offset * s->rowset_size - 1;
08932                 if (s->rowp < -1) {
08933                     s->rowp = -1;
08934                     return SQL_NO_DATA;
08935                 }
08936             }
08937             break;
08938         case SQL_FETCH_BOOKMARK:
08939             if (s->bkmrk) {
08940                 if (offset < 0 || offset >= s->nrows) {
08941                     return SQL_NO_DATA;
08942                 }
08943                 s->rowp = offset - 1;
08944                 break;
08945             }
08946             /* fall through */
08947         default:
08948             s->row_status0[0] = SQL_ROW_ERROR;
08949             ret = SQL_ERROR;
08950             goto done;
08951         }
08952         for (; i < s->rowset_size; i++) {
08953             ++s->rowp;
08954             if (s->rowp < 0 || s->rowp >= s->nrows) {
08955                 break;
08956             }
08957             ret = dofetchbind(s, i);
08958             if (!SQL_SUCCEEDED(ret)) {
08959                 break;
08960             } else if (ret == SQL_SUCCESS_WITH_INFO) {
08961                 withinfo = 1;
08962             }
08963         }
08964     }
08965 done:
08966     if (i == 0) {
08967         if (SQL_SUCCEEDED(ret)) {
08968             return SQL_NO_DATA;
08969         }
08970         return ret;
08971     }
08972     if (SQL_SUCCEEDED(ret)) {
08973         ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
08974     }
08975 done2:
08976     if (s->row_status) {
08977         memcpy(s->row_status, s->row_status0,
08978                sizeof (SQLUSMALLINT) * s->rowset_size);
08979     }
08980     s->row_count0 = i;
08981     if (s->row_count) {
08982         *s->row_count = s->row_count0;
08983     }
08984     return ret;
08985 }
08986 
08993 SQLRETURN SQL_API
08994 SQLFetch(SQLHSTMT stmt)
08995 {
08996     return drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
08997 }
08998 
09007 SQLRETURN SQL_API
09008 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLLEN offset)
09009 {
09010     return drvfetchscroll(stmt, orient, offset);
09011 }
09012 
09023 SQLRETURN SQL_API
09024 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLLEN offset,
09025                  SQLULEN *rowcount, SQLUSMALLINT *rowstatus)
09026 {
09027     STMT *s;
09028     SQLRETURN ret;
09029     SQLUSMALLINT *rst;
09030 
09031     if (stmt == SQL_NULL_HSTMT) {
09032         return SQL_INVALID_HANDLE;
09033     }
09034     s = (STMT *) stmt;
09035     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
09036     rst = s->row_status;
09037     s->row_status = 0;
09038     ret = drvfetchscroll(stmt, orient, offset);
09039     s->row_status = rst;
09040     if (rowstatus) {
09041         memcpy(rowstatus, s->row_status0,
09042                sizeof (SQLUSMALLINT) * s->rowset_size);
09043     }
09044     if (rowcount) {
09045         *rowcount = s->row_count0;
09046     }
09047     return ret;
09048 }
09049 
09057 SQLRETURN SQL_API
09058 SQLRowCount(SQLHSTMT stmt, SQLLEN *nrows)
09059 {
09060     STMT *s;
09061 
09062     if (stmt == SQL_NULL_HSTMT) {
09063         return SQL_INVALID_HANDLE;
09064     }
09065     s = (STMT *) stmt;
09066     if (nrows) {
09067         *nrows = s->nrows;
09068     }
09069     return SQL_SUCCESS;
09070 }
09071 
09079 SQLRETURN SQL_API
09080 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
09081 {
09082     STMT *s;
09083 
09084     if (stmt == SQL_NULL_HSTMT) {
09085         return SQL_INVALID_HANDLE;
09086     }
09087     s = (STMT *) stmt;
09088     if (ncols) {
09089         *ncols = s->ncols;
09090     }
09091     return SQL_SUCCESS;
09092 }
09093 
09108 static SQLRETURN
09109 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
09110                SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
09111                SQLSMALLINT *type, SQLULEN *size,
09112                SQLSMALLINT *digits, SQLSMALLINT *nullable)
09113 {
09114     STMT *s;
09115     COL *c;
09116     int didname = 0;
09117 
09118     if (stmt == SQL_NULL_HSTMT) {
09119         return SQL_INVALID_HANDLE;
09120     }
09121     s = (STMT *) stmt;
09122     if (!s->cols) {
09123         setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
09124         return SQL_ERROR;
09125     }
09126     if (col < 1 || col > s->ncols) {
09127         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
09128         return SQL_ERROR;
09129     }
09130     c = s->cols + col - 1;
09131     if (name && nameMax > 0) {
09132         strncpy((char *) name, c->column, nameMax);
09133         name[nameMax - 1] = '\0';
09134         didname = 1;
09135     }
09136     if (nameLen) {
09137         if (didname) {
09138             *nameLen = strlen((char *) name);
09139         } else {
09140             *nameLen = strlen(c->column);
09141         }
09142     }
09143     if (type) {
09144         *type = c->type;
09145     }
09146     if (size) {
09147         *size = c->size;
09148     }
09149     if (digits) {
09150         *digits = 0;
09151     }
09152     if (nullable) {
09153         *nullable = 1;
09154     }
09155     return SQL_SUCCESS;
09156 }
09157 
09172 SQLRETURN SQL_API
09173 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
09174                SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
09175                SQLSMALLINT *type, SQLULEN *size,
09176                SQLSMALLINT *digits, SQLSMALLINT *nullable)
09177 {
09178     return drvdescribecol(stmt, col, name, nameMax, nameLen,
09179                           type, size, digits, nullable);
09180 }
09181 
09194 static SQLRETURN
09195 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
09196                  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
09197                  SQLLEN *val2)
09198 {
09199     STMT *s;
09200     COL *c;
09201     SQLSMALLINT dummy;
09202     char *valc = (char *) val;
09203 
09204     if (stmt == SQL_NULL_HSTMT) {
09205         return SQL_INVALID_HANDLE;
09206     }
09207     s = (STMT *) stmt;
09208     if (!s->cols) {
09209         return SQL_ERROR;
09210     }
09211     if (!valLen) {
09212         valLen = &dummy;
09213     }
09214     if (id == SQL_COLUMN_COUNT) {
09215         if (val2) {
09216             *val2 = s->ncols;
09217         }
09218         *valLen = sizeof (int);
09219         return SQL_SUCCESS;
09220     }
09221     if (id == SQL_COLUMN_TYPE && col == 0) {
09222         if (val2) {
09223             *val2 = SQL_INTEGER;
09224         }
09225         *valLen = sizeof (int);
09226         return SQL_SUCCESS;
09227     }
09228 #ifdef SQL_DESC_OCTET_LENGTH
09229     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
09230         if (val2) {
09231             *val2 = 4;
09232         }
09233         *valLen = sizeof (int);
09234         return SQL_SUCCESS;
09235     }
09236 #endif
09237     if (col < 1 || col > s->ncols) {
09238         setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
09239         return SQL_ERROR;
09240     }
09241     c = s->cols + col - 1;
09242 
09243     switch (id) {
09244     case SQL_COLUMN_LABEL:
09245         if (c->label) {
09246             if (valc && valMax > 0) {
09247                 strncpy(valc, c->label, valMax);
09248                 valc[valMax - 1] = '\0';
09249             }
09250             *valLen = strlen(c->label);
09251             goto checkLen;
09252         }
09253         /* fall through */
09254     case SQL_COLUMN_NAME:
09255     case SQL_DESC_NAME:
09256         if (valc && valMax > 0) {
09257             strncpy(valc, c->column, valMax);
09258             valc[valMax - 1] = '\0';
09259         }
09260         *valLen = strlen(c->column);
09261 checkLen:
09262         if (*valLen >= valMax) {
09263             setstat(s, -1, "data right truncated", "01004");
09264             return SQL_SUCCESS_WITH_INFO;
09265         }
09266         return SQL_SUCCESS;
09267 #ifdef SQL_DESC_BASE_COLUMN_NAME
09268         if (strchr(c->column, '(') || strchr(c->column, ')')) {
09269             valc[0] = '\0';
09270             *valLen = 0;
09271         } else if (valc && valMax > 0) {
09272             strncpy(valc, c->column, valMax);
09273             valc[valMax - 1] = '\0';
09274             *valLen = strlen(c->column);
09275         }
09276         goto checkLen;
09277 #endif
09278     case SQL_COLUMN_TYPE:
09279     case SQL_DESC_TYPE:
09280         if (val2) {
09281             *val2 = c->type;
09282         }
09283         *valLen = sizeof (int);
09284         return SQL_SUCCESS;
09285     case SQL_COLUMN_DISPLAY_SIZE:
09286         if (val2) {
09287             *val2 = c->size;
09288         }
09289         *valLen = sizeof (int);
09290         return SQL_SUCCESS;
09291     case SQL_COLUMN_UNSIGNED:
09292         if (val2) {
09293             *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
09294         }
09295         *valLen = sizeof (int);
09296         return SQL_SUCCESS;
09297     case SQL_COLUMN_SCALE:
09298     case SQL_DESC_SCALE:
09299         if (val2) {
09300             *val2 = c->scale;
09301         }
09302         *valLen = sizeof (int);
09303         return SQL_SUCCESS;
09304     case SQL_COLUMN_PRECISION:
09305     case SQL_DESC_PRECISION:
09306         if (val2) {
09307             *val2 = c->prec;
09308         }
09309         *valLen = sizeof (int);
09310         return SQL_SUCCESS;
09311     case SQL_COLUMN_MONEY:
09312         if (val2) {
09313             *val2 = SQL_FALSE;
09314         }
09315         *valLen = sizeof (int);
09316         return SQL_SUCCESS;
09317     case SQL_COLUMN_AUTO_INCREMENT:
09318         if (val2) {
09319             *val2 = c->autoinc > 0 ? SQL_TRUE : SQL_FALSE;
09320         }
09321         *valLen = sizeof (int);
09322         return SQL_SUCCESS;
09323     case SQL_COLUMN_LENGTH:
09324     case SQL_DESC_LENGTH:
09325         if (val2) {
09326             *val2 = c->size;
09327         }
09328         *valLen = sizeof (int);
09329         return SQL_SUCCESS;
09330     case SQL_COLUMN_NULLABLE:
09331     case SQL_DESC_NULLABLE:
09332         if (val2) {
09333             *val2 = SQL_NULLABLE;
09334         }
09335         *valLen = sizeof (int);
09336         return SQL_SUCCESS;
09337     case SQL_COLUMN_SEARCHABLE:
09338         if (val2) {
09339             *val2 = SQL_SEARCHABLE;
09340         }
09341         *valLen = sizeof (int);
09342         return SQL_SUCCESS;
09343     case SQL_COLUMN_CASE_SENSITIVE:
09344         if (val2) {
09345             *val2 = SQL_TRUE;
09346         }
09347         *valLen = sizeof (int);
09348         return SQL_SUCCESS;
09349     case SQL_COLUMN_UPDATABLE:
09350         if (val2) {
09351             *val2 = SQL_TRUE;
09352         }
09353         *valLen = sizeof (int);
09354         return SQL_SUCCESS;
09355     case SQL_DESC_COUNT:
09356         if (val2) {
09357             *val2 = s->ncols;
09358         }
09359         *valLen = sizeof (int);
09360         return SQL_SUCCESS;
09361     case SQL_COLUMN_TYPE_NAME: {
09362         char *tn = c->typename ? c->typename : "varchar";
09363 
09364         if (valc && valMax > 0) {
09365             strncpy(valc, tn, valMax);
09366             valc[valMax - 1] = '\0';
09367         }
09368         *valLen = strlen(tn);
09369         goto checkLen;
09370     }
09371     case SQL_COLUMN_OWNER_NAME:
09372     case SQL_COLUMN_QUALIFIER_NAME: {
09373         char *z = "";
09374 
09375         if (valc && valMax > 0) {
09376             strncpy(valc, z, valMax);
09377             valc[valMax - 1] = '\0';
09378         }
09379         *valLen = strlen(z);
09380         goto checkLen;
09381     }
09382     case SQL_COLUMN_TABLE_NAME:
09383 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
09384     case SQL_DESC_TABLE_NAME:
09385 #endif
09386 #ifdef SQL_DESC_BASE_TABLE_NAME
09387     case SQL_DESC_BASE_TABLE_NAME:
09388 #endif
09389         if (valc && valMax > 0) {
09390             strncpy(valc, c->table, valMax);
09391             valc[valMax - 1] = '\0';
09392         }
09393         *valLen = strlen(c->table);
09394         goto checkLen;
09395     }
09396     setstat(s, -1, "unsupported column attributes %d", "HY091", id);
09397     return SQL_ERROR;
09398 }
09399 
09412 SQLRETURN SQL_API
09413 SQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
09414                  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
09415                  SQLLEN *val2)
09416 {
09417     return drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
09418 }
09419 
09432 static SQLRETURN
09433 drvcolattribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
09434                 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
09435                 SQLPOINTER val2)
09436 {
09437     STMT *s;
09438     COL *c;
09439     int v = 0;
09440     char *valc = (char *) val;
09441 
09442     if (stmt == SQL_NULL_HSTMT) {
09443         return SQL_INVALID_HANDLE;
09444     }
09445     s = (STMT *) stmt;
09446     if (!s->cols) {
09447         return SQL_ERROR;
09448     }
09449     if (col < 1 || col > s->ncols) {
09450         setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
09451         return SQL_ERROR;
09452     }
09453     c = s->cols + col - 1;
09454     switch (id) {
09455     case SQL_DESC_COUNT:
09456         v = s->ncols;
09457         break;
09458     case SQL_DESC_CATALOG_NAME:
09459         if (valc && valMax > 0) {
09460             strncpy(valc, c->db, valMax);
09461             valc[valMax - 1] = '\0';
09462         }
09463         if (valLen) {
09464             *valLen = strlen(c->db);
09465         }
09466 checkLen:
09467         if (valLen && *valLen >= valMax) {
09468             setstat(s, -1, "data right truncated", "01004");
09469             return SQL_SUCCESS_WITH_INFO;
09470         }
09471         break;
09472     case SQL_COLUMN_LENGTH:
09473     case SQL_DESC_LENGTH:
09474         v = c->size;
09475         break;
09476     case SQL_COLUMN_LABEL:
09477         if (c->label) {
09478             if (valc && valMax > 0) {
09479                 strncpy(valc, c->label, valMax);
09480                 valc[valMax - 1] = '\0';
09481             }
09482             if (valLen) {
09483                 *valLen = strlen(c->label);
09484             }
09485             goto checkLen;
09486         }
09487         /* fall through */
09488     case SQL_COLUMN_NAME:
09489     case SQL_DESC_NAME:
09490         if (valc && valMax > 0) {
09491             strncpy(valc, c->column, valMax);
09492             valc[valMax - 1] = '\0';
09493         }
09494         if (valLen) {
09495             *valLen = strlen(c->column);
09496             goto checkLen;
09497         }
09498         break;
09499 #ifdef SQL_DESC_BASE_COLUMN_NAME
09500     case SQL_DESC_BASE_COLUMN_NAME:
09501         if (strchr(c->column, '(') || strchr(c->column, ')')) {
09502             valc[0] = '\0';
09503             if (valLen) {
09504                 *valLen = 0;
09505                 goto checkLen;
09506             }
09507         } else if (valc && valMax > 0) {
09508             strncpy(valc, c->column, valMax);
09509             valc[valMax - 1] = '\0';
09510             if (valLen) {
09511                 *valLen = strlen(c->column);
09512                 goto checkLen;
09513             }
09514         }
09515         break;
09516 #endif
09517     case SQL_DESC_TYPE_NAME: {
09518         char *tn = c->typename ? c->typename : "varchar";
09519 
09520         if (valc && valMax > 0) {
09521             strncpy(valc, tn, valMax);
09522             valc[valMax - 1] = '\0';
09523         }
09524         if (valLen) {
09525             *valLen = strlen(tn);
09526             goto checkLen;
09527         }
09528         break;
09529     }
09530     case SQL_DESC_OCTET_LENGTH:
09531         v = c->size;
09532         break;
09533 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
09534     case SQL_COLUMN_TABLE_NAME:
09535 #endif
09536 #ifdef SQL_DESC_BASE_TABLE_NAME
09537     case SQL_DESC_BASE_TABLE_NAME:
09538 #endif
09539     case SQL_DESC_TABLE_NAME:
09540         if (valc && valMax > 0) {
09541             strncpy(valc, c->table, valMax);
09542             valc[valMax - 1] = '\0';
09543         }
09544         if (valLen) {
09545             *valLen = strlen(c->table);
09546             goto checkLen;
09547         }
09548         break;
09549     case SQL_DESC_TYPE:
09550         v = c->type;
09551         break;
09552     case SQL_DESC_CONCISE_TYPE:
09553         switch (c->type) {
09554         case SQL_INTEGER:
09555             v = SQL_C_LONG;
09556             break;
09557         case SQL_TINYINT:
09558             v = SQL_C_TINYINT;
09559             break;
09560         case SQL_SMALLINT:
09561             v = SQL_C_SHORT;
09562             break;
09563         case SQL_FLOAT:
09564             v = SQL_C_FLOAT;
09565             break;
09566         case SQL_DOUBLE:
09567             v = SQL_C_DOUBLE;
09568             break;
09569         case SQL_TIMESTAMP:
09570             v = SQL_C_TIMESTAMP;
09571             break;
09572         case SQL_TIME:
09573             v = SQL_C_TIME;
09574             break;
09575         case SQL_DATE:
09576             v = SQL_C_DATE;
09577             break;
09578 #ifdef SQL_C_TYPE_TIMESTAMP
09579         case SQL_TYPE_TIMESTAMP:
09580             v = SQL_C_TYPE_TIMESTAMP;
09581             break;
09582 #endif
09583 #ifdef SQL_C_TYPE_TIME
09584         case SQL_TYPE_TIME:
09585             v = SQL_C_TYPE_TIME;
09586             break;
09587 #endif
09588 #ifdef SQL_C_TYPE_DATE
09589         case SQL_TYPE_DATE:
09590             v = SQL_C_TYPE_DATE;
09591             break;
09592 #endif
09593 #ifdef SQL_BIT
09594         case SQL_BIT:
09595             v = SQL_C_BIT;
09596             break;
09597 #endif
09598 #ifdef SQL_BIGINT
09599         case SQL_BIGINT:
09600             v = SQL_C_SBIGINT;
09601             break;
09602 #endif
09603         default:
09604             v = SQL_C_CHAR;
09605             break;
09606         }
09607         break;
09608     case SQL_DESC_UPDATABLE:
09609         v = SQL_TRUE;
09610         break;
09611     case SQL_COLUMN_DISPLAY_SIZE:
09612         v = c->size;
09613         break;
09614     case SQL_COLUMN_UNSIGNED:
09615         v = c->nosign ? SQL_TRUE : SQL_FALSE;
09616         break;
09617     case SQL_COLUMN_SEARCHABLE:
09618         v = SQL_SEARCHABLE;
09619         break;
09620     case SQL_COLUMN_SCALE:
09621     case SQL_DESC_SCALE:
09622         v = c->scale;
09623         break;
09624     case SQL_COLUMN_PRECISION:
09625     case SQL_DESC_PRECISION:
09626         v = c->prec;
09627         break;
09628     case SQL_COLUMN_MONEY:
09629         v = SQL_FALSE;
09630         break;
09631     case SQL_COLUMN_AUTO_INCREMENT:
09632         v = c->autoinc > 0 ? SQL_TRUE : SQL_FALSE;
09633         break;
09634     case SQL_DESC_NULLABLE:
09635         v = SQL_NULLABLE;
09636         break;
09637     default:
09638         setstat(s, -1, "unsupported column attribute %d", "HY091", id);
09639         return SQL_ERROR;
09640     }
09641     if (val2) {
09642         *(int *) val2 = v;
09643     }
09644     return SQL_SUCCESS;
09645 }
09646 
09659 SQLRETURN SQL_API
09660 SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
09661                 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
09662                 COLATTRIBUTE_LAST_ARG_TYPE val2)
09663 {
09664     return drvcolattribute(stmt, col, id, val, valMax, valLen,
09665                            (SQLPOINTER) val2);
09666 }
09667 
09681 static SQLRETURN
09682 drverror(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
09683          SQLCHAR *sqlState, SQLINTEGER *nativeErr,
09684          SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
09685 {
09686     SQLCHAR dummy0[6];
09687     SQLINTEGER dummy1;
09688     SQLSMALLINT dummy2;
09689 
09690     if (env == SQL_NULL_HENV &&
09691         dbc == SQL_NULL_HDBC &&
09692         stmt == SQL_NULL_HSTMT) {
09693         return SQL_INVALID_HANDLE;
09694     }
09695     if (sqlState) {
09696         sqlState[0] = '\0';
09697     } else {
09698         sqlState = dummy0;
09699     }
09700     if (!nativeErr) {
09701         nativeErr = &dummy1;
09702     }
09703     *nativeErr = 0;
09704     if (!errlen) {
09705         errlen = &dummy2;
09706     }
09707     *errlen = 0;
09708     if (errmsg) {
09709         if (errmax > 0) {
09710             errmsg[0] = '\0';
09711         }
09712     } else {
09713         errmsg = dummy0;
09714         errmax = 0;
09715     }
09716     if (stmt) {
09717         STMT *s = (STMT *) stmt;
09718 
09719         if (s->logmsg[0] == '\0') {
09720             goto noerr;
09721         }
09722         *nativeErr = s->naterr;
09723         strcpy((char *) sqlState, s->sqlstate);
09724         if (errmax == SQL_NTS) {
09725             strcpy((char *) errmsg, "[SQLite]");
09726             strcat((char *) errmsg, (char *) s->logmsg);
09727             *errlen = strlen((char *) errmsg);
09728         } else {
09729             strncpy((char *) errmsg, "[SQLite]", errmax);
09730             if (errmax - 8 > 0) {
09731                 strncpy((char *) errmsg + 8, (char *) s->logmsg, errmax - 8);
09732             }
09733             *errlen = min(strlen((char *) s->logmsg) + 8, errmax);
09734         }
09735         s->logmsg[0] = '\0';
09736         return SQL_SUCCESS;
09737     }
09738     if (dbc) {
09739         DBC *d = (DBC *) dbc;
09740 
09741         if (d->magic != DBC_MAGIC || d->logmsg[0] == '\0') {
09742             goto noerr;
09743         }
09744         *nativeErr = d->naterr;
09745         strcpy((char *) sqlState, d->sqlstate);
09746         if (errmax == SQL_NTS) {
09747             strcpy((char *) errmsg, "[SQLite]");
09748             strcat((char *) errmsg, (char *) d->logmsg);
09749             *errlen = strlen((char *) errmsg);
09750         } else {
09751             strncpy((char *) errmsg, "[SQLite]", errmax);
09752             if (errmax - 8 > 0) {
09753                 strncpy((char *) errmsg + 8, (char *) d->logmsg, errmax - 8);
09754             }
09755             *errlen = min(strlen((char *) d->logmsg) + 8, errmax);
09756         }
09757         d->logmsg[0] = '\0';
09758         return SQL_SUCCESS;
09759     }
09760 noerr:
09761     sqlState[0] = '\0';
09762     errmsg[0] = '\0';
09763     *nativeErr = 0;
09764     *errlen = 0;
09765     return SQL_NO_DATA_FOUND;
09766 }
09767 
09781 SQLRETURN SQL_API
09782 SQLError(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
09783          SQLCHAR *sqlState, SQLINTEGER *nativeErr,
09784          SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
09785 {
09786     return drverror(env, dbc, stmt, sqlState, nativeErr,
09787                     errmsg, errmax, errlen);
09788 }
09789 
09796 SQLRETURN SQL_API
09797 SQLMoreResults(SQLHSTMT stmt)
09798 {
09799     if (stmt == SQL_NULL_HSTMT) {
09800         return SQL_INVALID_HANDLE;
09801     }
09802     return SQL_NO_DATA;
09803 }
09804 
09813 static SQLRETURN
09814 drvprepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
09815 {
09816     STMT *s;
09817     DBC *d;
09818     char *errp = NULL;
09819 
09820     if (stmt == SQL_NULL_HSTMT) {
09821         return SQL_INVALID_HANDLE;
09822     }
09823     s = (STMT *) stmt;
09824     if (s->dbc == SQL_NULL_HDBC) {
09825 noconn:
09826         return noconn(s);
09827     }
09828     d = s->dbc;
09829     if (!d->sqlite) {
09830         goto noconn;
09831     }
09832     s3stmt_end(s);
09833     freep(&s->query);
09834     s->query = (SQLCHAR *) fixupsql((char *) query, queryLen,
09835                                     &s->nparams, &s->isselect, &errp);
09836     if (!s->query) {
09837         if (errp) {
09838             setstat(s, -1, errp, (*s->ov3) ? "HY000" : "S1000");
09839             return SQL_ERROR;
09840         }
09841         return nomem(s);
09842     }
09843 #ifdef CANT_PASS_VALIST_AS_CHARPTR
09844     if (s->nparams > MAX_PARAMS_FOR_MPRINTF) {
09845         freep(&s->query);
09846         setstat(s, -1, "too much parameters in query",
09847                 (*s->ov3) ? "HY000" : "S1000");
09848         return SQL_ERROR;
09849     }
09850 #endif
09851     errp = NULL;
09852     freeresult(s, -1);
09853     if (s->isselect > 0) {
09854         int ret, ncols;
09855         const char *rest;
09856         char *sql, *sqltofree = NULL, **params = NULL;
09857         sqlite3_stmt *s3stmt = NULL;
09858 
09859         if (s->nparams) {
09860             int i, maxp;
09861 
09862 #ifdef CANT_PASS_VALIST_AS_CHARPTR
09863             maxp = MAX_PARAMS_FOR_MPRINTF;
09864 #else
09865             maxp = s->nparams;
09866 #endif
09867             params = xmalloc(maxp * sizeof (char *));
09868             if (!params) {
09869                 return nomem(s);
09870             }
09871             for (i = 0; i < maxp; i++) {
09872                 params[i] = NULL;
09873             }
09874 #ifdef CANT_PASS_VALIST_AS_CHARPTR
09875             sql = sqlite3_mprintf(s->query,
09876                                   params[0], params[1],
09877                                   params[2], params[3],
09878                                   params[4], params[5],
09879                                   params[6], params[7],
09880                                   params[8], params[9],
09881                                   params[10], params[11],
09882                                   params[12], params[13],
09883                                   params[14], params[15],
09884                                   params[16], params[17],
09885                                   params[18], params[19],
09886                                   params[20], params[21],
09887                                   params[22], params[23],
09888                                   params[24], params[25],
09889                                   params[26], params[27],
09890                                   params[28], params[29],
09891                                   params[30], params[31]);
09892 #else
09893             sql = sqlite3_vmprintf((char *) s->query, (char *) params);
09894 #endif
09895             sqltofree = sql;
09896         } else {
09897             sql = s->query;
09898         }
09899         freep(&params);
09900         if (!sql && s->nparams) {
09901             return nomem(s);
09902         }
09903         dbtraceapi(d, "sqlite3_prepare", sql);
09904         ret = sqlite3_prepare(d->sqlite, sql, -1, &s3stmt, &rest);
09905         dbtracerc(d, ret, NULL);
09906         if (sqltofree) {
09907             sqlite3_free(sql);
09908         }
09909         if (ret != SQLITE_OK) {
09910             if (s3stmt) {
09911                 dbtraceapi(d, "sqlite3_finalize", 0);
09912                 sqlite3_finalize(s3stmt);
09913             }
09914             setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
09915                     sqlite3_errmsg(d->sqlite), ret);
09916             return SQL_ERROR;
09917         }
09918         ncols = sqlite3_column_count(s3stmt);
09919         if (ncols > 0) {
09920             int i, size;
09921             char *p;
09922             COL *dyncols;
09923             DBC *d = (DBC *) s->dbc;
09924             const char *colname, *typename;
09925 
09926             for (i = size = 0; i < ncols; i++) {
09927                 colname = sqlite3_column_name(s3stmt, i);
09928                 size += 3 + 3 * strlen(colname);
09929             }
09930             dyncols = xmalloc(ncols * sizeof (COL) + size);
09931             if (!dyncols) {
09932                 freedyncols(s);
09933                 ncols = 0;
09934             } else {
09935                 p = (char *) (dyncols + ncols);
09936                 for (i = 0; i < ncols; i++) {
09937                     char *q;
09938 
09939                     colname = sqlite3_column_name(s3stmt, i);
09940                     if (d->trace) {
09941                         fprintf(d->trace, "-- column %d name: '%s'\n",
09942                                 i + 1, colname);
09943                         fflush(d->trace);
09944                     }
09945                     typename = s3stmt_coltype(s3stmt, i, d);
09946                     dyncols[i].db = ((DBC *) (s->dbc))->dbname;
09947                     strcpy(p, colname);
09948                     dyncols[i].label = p;
09949                     p += strlen(p) + 1;
09950                     q = strchr(colname, '.');
09951                     if (q) {
09952                         char *q2 = strchr(q + 1, '.');
09953 
09954                         /* SQLite 3.3.4 produces view.table.column sometimes */
09955                         if (q2) {
09956                             q = q2;
09957                         }
09958                     }
09959                     if (q) {
09960                         dyncols[i].table = p;
09961                         strncpy(p, colname, q - colname);
09962                         p[q - colname] = '\0';
09963                         p += strlen(p) + 1;
09964                         strcpy(p, q + 1);
09965                         dyncols[i].column = p;
09966                         p += strlen(p) + 1;
09967                     } else {
09968                         dyncols[i].table = "";
09969                         strcpy(p, colname);
09970                         dyncols[i].column = p;
09971                         p += strlen(p) + 1;
09972                     }
09973                     if (s->longnames) {
09974                         dyncols[i].column = dyncols[i].label;
09975                     }
09976 #ifdef SQL_LONGVARCHAR
09977                     dyncols[i].type = SQL_LONGVARCHAR;
09978                     dyncols[i].size = 65536;
09979 #else
09980                     dyncols[i].type = SQL_VARCHAR;
09981                     dyncols[i].size = 256;
09982 #endif
09983                     dyncols[i].index = i;
09984                     dyncols[i].scale = 0;
09985                     dyncols[i].prec = 0;
09986                     dyncols[i].nosign = 1;
09987                     dyncols[i].autoinc = -1;
09988                     dyncols[i].typename = xstrdup(typename);
09989                 }
09990                 freedyncols(s);
09991                 s->dyncols = s->cols = dyncols;
09992                 s->dcols = ncols;
09993                 fixupdyncols(s, d);
09994             }
09995         }
09996         s->ncols = ncols;
09997         dbtraceapi(d, "sqlite3_finalize", 0);
09998         sqlite3_finalize(s3stmt);
09999     }
10000     mkbindcols(s, s->ncols);
10001     if (s->nparams) {
10002         s->paramset_count = 0;
10003     }
10004     return SQL_SUCCESS;
10005 }
10006 
10007 /* see doc on top */
10008 
10009 static SQLRETURN
10010 drvexecute(SQLHSTMT stmt, int initial)
10011 {
10012     STMT *s;
10013     DBC *d;
10014     char *errp = NULL, **params = NULL, *sql, *sqltofree = NULL;
10015     int rc, i, ncols, busy_count, start_trans;
10016     SQLRETURN ret;
10017 
10018     if (stmt == SQL_NULL_HSTMT) {
10019         return SQL_INVALID_HANDLE;
10020     }
10021     s = (STMT *) stmt;
10022     if (s->dbc == SQL_NULL_HDBC) {
10023 noconn:
10024         return noconn(s);
10025     }
10026     d = (DBC *) s->dbc;
10027     if (!d->sqlite) {
10028         goto noconn;
10029     }
10030     if (!s->query) {
10031         setstat(s, -1, "no query prepared", (*s->ov3) ? "HY000" : "S1000");
10032         return SQL_ERROR;
10033     }
10034     if (s->nbindparms < s->nparams) {
10035         setstat(s, -1, "unbound parameters in query",
10036                 (*s->ov3) ? "HY000" : "S1000");
10037         return SQL_ERROR;
10038     }
10039     busy_count = 0;
10040     start_trans = !d->autocommit && !d->intrans && !d->trans_disable;
10041 again:
10042     s3stmt_end(s);
10043     if (initial) {
10044         /* fixup data-at-execution parameters and alloc'ed blobs */
10045         for (i = 0; i < s->nparams; i++) {
10046             BINDPARM *p = &s->bindparms[i];
10047 
10048             if (p->param == p->parbuf) {
10049                 p->param = NULL;
10050             }
10051             freep(&p->parbuf);
10052             if (p->need <= 0 &&
10053                 p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
10054                 p->need = 1;
10055                 p->offs = 0;
10056                 p->len = 0;
10057             }
10058         }
10059     }
10060     if (s->nparams) {
10061         char *p;
10062         int maxp;
10063 
10064 #ifdef CANT_PASS_VALIST_AS_CHARPTR
10065         maxp = MAX_PARAMS_FOR_MPRINTF;
10066 #else
10067         maxp = s->nparams;
10068 #endif
10069         params = xmalloc(maxp * sizeof (char *));
10070         if (!params) {
10071             ret = nomem(s);
10072             goto cleanup;
10073         }
10074         for (i = 0; i < maxp; i++) {
10075             params[i] = NULL;
10076         }
10077         sql = s->query;
10078         for (i = 0; i < s->nparams; i++) {
10079             params[i] = p;
10080             ret = substparam(s, &sql, i, &params[i]);
10081             if (ret != SQL_SUCCESS) {
10082                 freep(&params);
10083                 goto cleanup;
10084             }
10085         }
10086     }
10087     freeresult(s, 0);
10088     if (!d->autocommit && !d->intrans && !d->trans_disable) {
10089 begin_again:
10090         rc = sqlite3_exec(d->sqlite, (d->version < verinfo(3, 0, 8)) ?
10091                           "BEGIN TRANSACTION" : "BEGIN EXCLUSIVE TRANSACTION",
10092                           NULL, NULL, &errp);
10093         if (rc == SQLITE_BUSY) {
10094             if (busy_handler((void *) d, ++busy_count)) {
10095                 if (errp) {
10096                     sqlite3_free(errp);
10097                     errp = NULL;
10098                 }
10099                 goto begin_again;
10100             }
10101         }
10102         dbtracerc(d, rc, errp);
10103         if (rc != SQLITE_OK) {
10104             freep(&params);
10105             setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10106                     errp ? errp : "unknown error", rc);
10107             if (errp) {
10108                 sqlite3_free(errp);
10109                 errp = NULL;
10110             }
10111             ret = SQL_ERROR;
10112             goto cleanup;
10113         }
10114         d->intrans = 1;
10115         if (errp) {
10116             sqlite3_free(errp);
10117             errp = NULL;
10118         }
10119     }
10120     if (s->isselect > 0 && !d->intrans &&
10121         s->curtype == SQL_CURSOR_FORWARD_ONLY &&
10122         d->step_enable && s->nparams == 0 && d->cur_s3stmt == NULL) {
10123         s->nrows = -1;
10124         ret = s3stmt_start(s, params);
10125         if (ret == SQL_SUCCESS) {
10126             freep(&params);
10127             goto done2;
10128         }
10129     }
10130     if (s->nparams) {
10131 #ifdef CANT_PASS_VALIST_AS_CHARPTR
10132         /* adjust with MAX_PARAMS_FOR_MPRINTF */
10133         sql = sqlite3_mprintf(s->query,
10134                               params[0], params[1],
10135                               params[2], params[3],
10136                               params[4], params[5],
10137                               params[6], params[7],
10138                               params[8], params[9],
10139                               params[10], params[11],
10140                               params[12], params[13],
10141                               params[14], params[15],
10142                               params[16], params[17],
10143                               params[18], params[19],
10144                               params[20], params[21],
10145                               params[22], params[23],
10146                               params[24], params[25],
10147                               params[26], params[27],
10148                               params[28], params[29],
10149                               params[30], params[31]);
10150 #else
10151         sql = sqlite3_vmprintf((char *) s->query, (char *) params);
10152 #endif
10153         if (!sql) {
10154             freep(&params);
10155             ret = nomem(s);
10156             goto cleanup;
10157         }
10158         sqltofree = sql;
10159     } else {
10160         sql = s->query;
10161     }
10162     rc = drvgettable(d, sql, &s->rows, &s->nrows, &ncols, &errp);
10163     dbtracerc(d, rc, errp);
10164     if (sqltofree) {
10165         sqlite3_free(sql);
10166     }
10167     if (rc == SQLITE_BUSY) {
10168         if (busy_handler((void *) d, ++busy_count)) {
10169             freep(&params);
10170             if (errp) {
10171                 sqlite3_free(errp);
10172                 errp = NULL;
10173             }
10174             if (start_trans) {
10175                 sqlite3_exec(d->sqlite, "ROLLBACK TRANSACTION;",
10176                              NULL, NULL, NULL);
10177                 d->intrans = 0;
10178             }
10179             if (s->nparams) {
10180                 for (i = 0; i < s->nparams; i++) {
10181                     BINDPARM *p = &s->bindparms[i];
10182 
10183                     if (p->param == p->parbuf) {
10184                         p->param = NULL;
10185                     }
10186                     freep(&p->parbuf);
10187                     if (!p->lenp || *p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET) {
10188                         p->param = p->param0;
10189                     }
10190                 }
10191                 s->paramset_count = 0;
10192                 s->paramset_nrows = 0;
10193             }
10194             s->nrows = 0;
10195             goto again;
10196         }
10197     }
10198     if (rc != SQLITE_OK) {
10199         freep(&params);
10200         setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10201                 errp ? errp : "unknown error", rc);
10202         if (errp) {
10203             sqlite3_free(errp);
10204             errp = NULL;
10205         }
10206         ret = SQL_ERROR;
10207         goto cleanup;
10208     }
10209     freep(&params);
10210     if (errp) {
10211         sqlite3_free(errp);
10212         errp = NULL;
10213     }
10214     s->rowfree = freerows;
10215     if (!s->isselect) {
10216         /*
10217          * INSERT/UPDATE/DELETE results are immediately released.
10218          */
10219         freeresult(s, -1);
10220         s->nrows = sqlite3_changes(d->sqlite);
10221         goto done;
10222     }
10223     if (s->ncols != ncols) {
10224         /*
10225          * Weird result.
10226          */
10227         setstat(s, -1, "broken result set %d/%d",
10228                 (*s->ov3) ? "HY000" : "S1000", s->ncols, ncols);
10229         ret = SQL_ERROR;
10230         goto cleanup;
10231     }
10232 done:
10233     mkbindcols(s, s->ncols);
10234 done2:
10235     ret = SQL_SUCCESS;
10236     s->rowp = -1;
10237     if (s->nparams) {
10238         s->paramset_count++;
10239         s->paramset_nrows += s->nrows;
10240         if (s->paramset_count < s->paramset_size) {
10241             for (i = 0; i < s->nparams; i++) {
10242                 BINDPARM *p = &s->bindparms[i];
10243 
10244                 if (p->param == p->parbuf) {
10245                     p->param = NULL;
10246                 }
10247                 freep(&p->parbuf);
10248                 if (!p->lenp || *p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET) {
10249                     if (p->param0 && p->inc > 0) {
10250                         p->param = (char *) p->param0 + 
10251                             s->paramset_count * p->inc;
10252                     }
10253                 }
10254             }
10255             goto again;
10256         }
10257     }
10258 cleanup:
10259     if (ret != SQL_NEED_DATA && s->nparams) {
10260         for (i = 0; i < s->nparams; i++) {
10261             BINDPARM *p = &s->bindparms[i];
10262 
10263             if (p->param == p->parbuf) {
10264                 p->param = NULL;
10265             }
10266             freep(&p->parbuf);
10267             if (!p->lenp || *p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET) {
10268                 p->param = p->param0;
10269             }
10270         }
10271         s->nrows = s->paramset_nrows;
10272         s->paramset_count = 0;
10273         s->paramset_nrows = 0;
10274     }
10275     return ret;
10276 }
10277 
10286 SQLRETURN SQL_API
10287 SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
10288 {
10289     return drvprepare(stmt, query, queryLen);
10290 }
10291 
10298 SQLRETURN SQL_API
10299 SQLExecute(SQLHSTMT stmt)
10300 {
10301     return drvexecute(stmt, 1);
10302 }
10303 
10312 SQLRETURN SQL_API
10313 SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
10314 {
10315     if (drvprepare(stmt, query, queryLen) != SQL_SUCCESS) {
10316         return SQL_ERROR;
10317     }
10318     return drvexecute(stmt, 1);
10319 }
10320 
10321 #ifdef _WIN32
10322 #ifndef WITHOUT_DRIVERMGR
10323 
10324 /*
10325  * Windows configuration dialog stuff.
10326  */
10327 
10328 #include <windowsx.h>
10329 #include <winuser.h>
10330 
10331 #define stricmp _stricmp
10332 
10333 static HINSTANCE NEAR hModule;  /* Saved module handle for resources */
10334 
10335 #define MAXPATHLEN      (255+1)           /* Max path length */
10336 #define MAXKEYLEN       (15+1)            /* Max keyword length */
10337 #define MAXDESC         (255+1)           /* Max description length */
10338 #define MAXDSNAME       (32+1)            /* Max data source name length */
10339 #define MAXTONAME       (32+1)            /* Max timeout length */
10340 #define MAXDBNAME       (255+1)
10341 
10342 /* Attribute key indexes into an array of Attr structs, see below */
10343 
10344 #define KEY_DSN                 0
10345 #define KEY_DESC                1
10346 #define KEY_DBNAME              2
10347 #define KEY_BUSY                3
10348 #define KEY_DRIVER              4
10349 #define KEY_STEPAPI             5
10350 #define KEY_SYNCP               6
10351 #define KEY_NOTXN               7
10352 #define KEY_LONGNAM             8
10353 #define NUMOFKEYS               9
10354 
10355 typedef struct {
10356     BOOL supplied;
10357     char attr[MAXPATHLEN];
10358 } ATTR;
10359 
10360 typedef struct {
10361     SQLHWND parent;
10362     LPCSTR  driver;
10363     ATTR    attr[NUMOFKEYS];
10364     char    DSN[MAXDSNAME];
10365     BOOL    newDSN;
10366     BOOL    defDSN;
10367 } SETUPDLG;
10368 
10369 static struct {
10370     char *key;
10371     int ikey;
10372 } attrLookup[] = {
10373     { "DSN", KEY_DSN },
10374     { "DESC", KEY_DESC },
10375     { "Description", KEY_DESC},
10376     { "Database", KEY_DBNAME },
10377     { "Timeout", KEY_BUSY },
10378     { "Driver", KEY_DRIVER },
10379     { "StepAPI", KEY_STEPAPI },
10380     { "SyncPragma", KEY_SYNCP },
10381     { "NoTXN", KEY_NOTXN },
10382     { "LongNames", KEY_LONGNAM },
10383     { NULL, 0 }
10384 };
10385 
10392 static void
10393 ParseAttributes(LPCSTR attribs, SETUPDLG *setupdlg)
10394 {
10395     char *str = (char *) attribs, *start, key[MAXKEYLEN];
10396     int elem, nkey;
10397 
10398     while (*str) {
10399         start = str;
10400         if ((str = strchr(str, '=')) == NULL) {
10401             return;
10402         }
10403         elem = -1;
10404         nkey = str - start;
10405         if (nkey < sizeof (key)) {
10406             int i;
10407 
10408             memcpy(key, start, nkey);
10409             key[nkey] = '\0';
10410             for (i = 0; attrLookup[i].key; i++) {
10411                 if (stricmp(attrLookup[i].key, key) == 0) {
10412                     elem = attrLookup[i].ikey;
10413                     break;
10414                 }
10415             }
10416         }
10417         start = ++str;
10418         while (*str && *str != ';') {
10419             ++str;
10420         }
10421         if (elem >= 0) {
10422             int end = min(str - start, sizeof (setupdlg->attr[elem].attr) - 1);
10423 
10424             setupdlg->attr[elem].supplied = TRUE;
10425             memcpy(setupdlg->attr[elem].attr, start, end);
10426             setupdlg->attr[elem].attr[end] = '\0';
10427         }
10428         ++str;
10429     }
10430 }
10431 
10439 static BOOL
10440 SetDSNAttributes(HWND parent, SETUPDLG *setupdlg)
10441 {
10442     char *dsn = setupdlg->attr[KEY_DSN].attr;
10443 
10444     if (setupdlg->newDSN && strlen(dsn) == 0) {
10445         return FALSE;
10446     }
10447     if (!SQLWriteDSNToIni(dsn, setupdlg->driver)) {
10448         if (parent) {
10449             char buf[MAXPATHLEN], msg[MAXPATHLEN];
10450 
10451             LoadString(hModule, IDS_BADDSN, buf, sizeof (buf));
10452             wsprintf(msg, buf, dsn);
10453             LoadString(hModule, IDS_MSGTITLE, buf, sizeof (buf));
10454             MessageBox(parent, msg, buf,
10455                        MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
10456                        MB_SETFOREGROUND);
10457         }
10458         return FALSE;
10459     }
10460     if (parent || setupdlg->attr[KEY_DESC].supplied) {
10461         SQLWritePrivateProfileString(dsn, "Description",
10462                                      setupdlg->attr[KEY_DESC].attr,
10463                                      ODBC_INI);
10464     }
10465     if (parent || setupdlg->attr[KEY_DBNAME].supplied) {
10466         SQLWritePrivateProfileString(dsn, "Database",
10467                                      setupdlg->attr[KEY_DBNAME].attr,
10468                                      ODBC_INI);
10469     }
10470     if (parent || setupdlg->attr[KEY_BUSY].supplied) {
10471         SQLWritePrivateProfileString(dsn, "Timeout",
10472                                      setupdlg->attr[KEY_BUSY].attr,
10473                                      ODBC_INI);
10474     }
10475     if (parent || setupdlg->attr[KEY_STEPAPI].supplied) {
10476         SQLWritePrivateProfileString(dsn, "StepAPI",
10477                                      setupdlg->attr[KEY_STEPAPI].attr,
10478                                      ODBC_INI);
10479     }
10480     if (parent || setupdlg->attr[KEY_SYNCP].supplied) {
10481         SQLWritePrivateProfileString(dsn, "SyncPragma",
10482                                      setupdlg->attr[KEY_SYNCP].attr,
10483                                      ODBC_INI);
10484     }
10485     if (parent || setupdlg->attr[KEY_NOTXN].supplied) {
10486         SQLWritePrivateProfileString(dsn, "NoTXN",
10487                                      setupdlg->attr[KEY_NOTXN].attr,
10488                                      ODBC_INI);
10489     }
10490     if (parent || setupdlg->attr[KEY_LONGNAM].supplied) {
10491         SQLWritePrivateProfileString(dsn, "LongNames",
10492                                      setupdlg->attr[KEY_LONGNAM].attr,
10493                                      ODBC_INI);
10494     }
10495     if (setupdlg->attr[KEY_DSN].supplied &&
10496         stricmp(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr)) {
10497         SQLRemoveDSNFromIni(setupdlg->DSN);
10498     }
10499     return TRUE;
10500 }
10501 
10507 static void
10508 GetAttributes(SETUPDLG *setupdlg)
10509 {
10510     char *dsn = setupdlg->attr[KEY_DSN].attr;
10511 
10512     if (!setupdlg->attr[KEY_DESC].supplied) {
10513         SQLGetPrivateProfileString(dsn, "Description", "",
10514                                    setupdlg->attr[KEY_DESC].attr,
10515                                    sizeof (setupdlg->attr[KEY_DESC].attr),
10516                                    ODBC_INI);
10517     }
10518     if (!setupdlg->attr[KEY_DBNAME].supplied) {
10519         SQLGetPrivateProfileString(dsn, "Database", "",
10520                                    setupdlg->attr[KEY_DBNAME].attr,
10521                                    sizeof (setupdlg->attr[KEY_DBNAME].attr),
10522                                    ODBC_INI);
10523     }
10524     if (!setupdlg->attr[KEY_BUSY].supplied) {
10525         SQLGetPrivateProfileString(dsn, "Timeout", "1000",
10526                                    setupdlg->attr[KEY_BUSY].attr,
10527                                    sizeof (setupdlg->attr[KEY_BUSY].attr),
10528                                    ODBC_INI);
10529     }
10530     if (!setupdlg->attr[KEY_STEPAPI].supplied) {
10531         SQLGetPrivateProfileString(dsn, "StepAPI", "0",
10532                                    setupdlg->attr[KEY_STEPAPI].attr,
10533                                    sizeof (setupdlg->attr[KEY_STEPAPI].attr),
10534                                    ODBC_INI);
10535     }
10536     if (!setupdlg->attr[KEY_SYNCP].supplied) {
10537         SQLGetPrivateProfileString(dsn, "SyncPragma", "NORMAL",
10538                                    setupdlg->attr[KEY_SYNCP].attr,
10539                                    sizeof (setupdlg->attr[KEY_SYNCP].attr),
10540                                    ODBC_INI);
10541     }
10542     if (!setupdlg->attr[KEY_NOTXN].supplied) {
10543         SQLGetPrivateProfileString(dsn, "NoTXN", "",
10544                                    setupdlg->attr[KEY_NOTXN].attr,
10545                                    sizeof (setupdlg->attr[KEY_NOTXN].attr),
10546                                    ODBC_INI);
10547     }
10548     if (!setupdlg->attr[KEY_LONGNAM].supplied) {
10549         SQLGetPrivateProfileString(dsn, "LongNames", "",
10550                                    setupdlg->attr[KEY_LONGNAM].attr,
10551                                    sizeof (setupdlg->attr[KEY_LONGNAM].attr),
10552                                    ODBC_INI);
10553     }
10554 }
10555 
10561 static void
10562 GetDBFile(HWND hdlg)
10563 {
10564     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
10565     OPENFILENAME ofn;
10566 
10567     memset(&ofn, 0, sizeof (ofn));
10568     ofn.lStructSize = sizeof (ofn);
10569     ofn.hwndOwner = hdlg;
10570     ofn.hInstance = (HINSTANCE) GetWindowLong(hdlg, GWL_HINSTANCE);
10571     ofn.lpstrFile = (LPTSTR) setupdlg->attr[KEY_DBNAME].attr;
10572     ofn.nMaxFile = MAXPATHLEN;
10573     ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
10574                 OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_FILEMUSTEXIST;
10575     if (GetOpenFileName(&ofn)) {
10576         SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
10577         setupdlg->attr[KEY_DBNAME].supplied = TRUE;
10578     }
10579 }
10580 
10590 static BOOL CALLBACK
10591 ConfigDlgProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
10592 {
10593     SETUPDLG *setupdlg = NULL;
10594     WORD index;
10595 
10596     switch (wmsg) {
10597     case WM_INITDIALOG:
10598         SetWindowLong(hdlg, DWL_USER, lparam);
10599         setupdlg = (SETUPDLG *) lparam;
10600         GetAttributes(setupdlg);
10601         SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
10602         SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
10603         SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
10604         SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
10605         CheckDlgButton(hdlg, IDC_STEPAPI,
10606                        getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
10607                        BST_CHECKED : BST_UNCHECKED);
10608         CheckDlgButton(hdlg, IDC_NOTXN,
10609                        getbool(setupdlg->attr[KEY_NOTXN].attr) ?
10610                        BST_CHECKED : BST_UNCHECKED);
10611         CheckDlgButton(hdlg, IDC_LONGNAM,
10612                        getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
10613                        BST_CHECKED : BST_UNCHECKED);
10614         SendDlgItemMessage(hdlg, IDC_SYNCP,
10615                            CB_LIMITTEXT, (WPARAM) 10, 0);
10616         SendDlgItemMessage(hdlg, IDC_SYNCP,
10617                            CB_ADDSTRING, 0, (LONG) "NORMAL");
10618         SendDlgItemMessage(hdlg, IDC_SYNCP,
10619                            CB_ADDSTRING, 0, (LONG) "OFF");
10620         SendDlgItemMessage(hdlg, IDC_SYNCP,
10621                            CB_ADDSTRING, 0, (LONG) "FULL");
10622         SendDlgItemMessage(hdlg, IDC_SYNCP,
10623                            CB_SELECTSTRING, (WORD) -1,
10624                            (LONG) setupdlg->attr[KEY_SYNCP].attr);
10625         if (setupdlg->defDSN) {
10626             EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
10627             EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
10628         } else {
10629             SendDlgItemMessage(hdlg, IDC_DSNAME,
10630                                EM_LIMITTEXT, (WPARAM) (MAXDSNAME - 1), 0L);
10631             SendDlgItemMessage(hdlg, IDC_DESC,
10632                                EM_LIMITTEXT, (WPARAM) (MAXDESC - 1), 0L);
10633             SendDlgItemMessage(hdlg, IDC_DBNAME,
10634                                EM_LIMITTEXT, (WPARAM) (MAXDBNAME - 1), 0L);
10635             SendDlgItemMessage(hdlg, IDC_TONAME,
10636                                EM_LIMITTEXT, (WPARAM) (MAXTONAME - 1), 0L);
10637         }
10638         return TRUE;
10639     case WM_COMMAND:
10640         switch (GET_WM_COMMAND_ID(wparam, lparam)) {
10641         case IDC_DSNAME:
10642             if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) {
10643                 char item[MAXDSNAME];
10644 
10645                 EnableWindow(GetDlgItem(hdlg, IDOK),
10646                              GetDlgItemText(hdlg, IDC_DSNAME,
10647                                             item, sizeof (item)));
10648                 return TRUE;
10649             }
10650             break;
10651         case IDC_BROWSE:
10652             GetDBFile(hdlg);
10653             break;
10654         case IDOK:
10655             setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
10656             if (!setupdlg->defDSN) {
10657                 GetDlgItemText(hdlg, IDC_DSNAME,
10658                                setupdlg->attr[KEY_DSN].attr,
10659                                sizeof (setupdlg->attr[KEY_DSN].attr));
10660             }
10661             GetDlgItemText(hdlg, IDC_DESC,
10662                            setupdlg->attr[KEY_DESC].attr,
10663                            sizeof (setupdlg->attr[KEY_DESC].attr));
10664             GetDlgItemText(hdlg, IDC_DBNAME,
10665                            setupdlg->attr[KEY_DBNAME].attr,
10666                            sizeof (setupdlg->attr[KEY_DBNAME].attr));
10667             GetDlgItemText(hdlg, IDC_TONAME,
10668                            setupdlg->attr[KEY_BUSY].attr,
10669                            sizeof (setupdlg->attr[KEY_BUSY].attr));
10670             index = SendDlgItemMessage(hdlg, IDC_SYNCP,
10671                                        CB_GETCURSEL, (WORD) 0, (LONG) 0);
10672             if (index != (WORD) CB_ERR) {
10673                 SendDlgItemMessage(hdlg, IDC_SYNCP,
10674                                    CB_GETLBTEXT, index,
10675                                    (LONG) setupdlg->attr[KEY_SYNCP].attr);
10676             }
10677             strcpy(setupdlg->attr[KEY_STEPAPI].attr,
10678                    IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED ?
10679                    "1" : "0");
10680             strcpy(setupdlg->attr[KEY_NOTXN].attr,
10681                    IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED ?
10682                    "1" : "0");
10683             strcpy(setupdlg->attr[KEY_LONGNAM].attr,
10684                    IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED ?
10685                    "1" : "0");
10686             SetDSNAttributes(hdlg, setupdlg);
10687             /* FALL THROUGH */
10688         case IDCANCEL:
10689             EndDialog(hdlg, wparam);
10690             return TRUE;
10691         }
10692         break;
10693     }
10694     return FALSE;
10695 }
10696 
10706 BOOL INSTAPI
10707 ConfigDSN(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attribs)
10708 {
10709     BOOL success;
10710     SETUPDLG *setupdlg;
10711 
10712     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
10713     if (setupdlg == NULL) {
10714         return FALSE;
10715     }
10716     memset(setupdlg, 0, sizeof (SETUPDLG));
10717     if (attribs) {
10718         ParseAttributes(attribs, setupdlg);
10719     }
10720     if (setupdlg->attr[KEY_DSN].supplied) {
10721         strcpy(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr);
10722     } else {
10723         setupdlg->DSN[0] = '\0';
10724     }
10725     if (request == ODBC_REMOVE_DSN) {
10726         if (!setupdlg->attr[KEY_DSN].supplied) {
10727             success = FALSE;
10728         } else {
10729             success = SQLRemoveDSNFromIni(setupdlg->attr[KEY_DSN].attr);
10730         }
10731     } else {
10732         setupdlg->parent = hwnd;
10733         setupdlg->driver = driver;
10734         setupdlg->newDSN = request == ODBC_ADD_DSN;
10735         setupdlg->defDSN = stricmp(setupdlg->attr[KEY_DSN].attr,
10736                                    "Default") == 0;
10737         if (hwnd) {
10738             success = DialogBoxParam(hModule, MAKEINTRESOURCE(CONFIGDSN),
10739                                      hwnd, (DLGPROC) ConfigDlgProc,
10740                                      (LONG) setupdlg) == IDOK;
10741         } else if (setupdlg->attr[KEY_DSN].supplied) {
10742             success = SetDSNAttributes(hwnd, setupdlg);
10743         } else {
10744             success = FALSE;
10745         }
10746     }
10747     xfree(setupdlg);
10748     return success;
10749 }
10750 
10760 static BOOL CALLBACK
10761 DriverConnectProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
10762 {
10763     SETUPDLG *setupdlg;
10764     WORD index;
10765 
10766     switch (wmsg) {
10767     case WM_INITDIALOG:
10768         SetWindowLong(hdlg, DWL_USER, lparam);
10769         setupdlg = (SETUPDLG *) lparam;
10770         SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
10771         SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
10772         SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
10773         SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
10774         SendDlgItemMessage(hdlg, IDC_DSNAME,
10775                            EM_LIMITTEXT, (WPARAM) (MAXDSNAME - 1), 0L);
10776         SendDlgItemMessage(hdlg, IDC_DESC,
10777                            EM_LIMITTEXT, (WPARAM) (MAXDESC - 1), 0L);
10778         SendDlgItemMessage(hdlg, IDC_DBNAME,
10779                            EM_LIMITTEXT, (WORD)(MAXDBNAME - 1), 0L);
10780         SendDlgItemMessage(hdlg, IDC_TONAME,
10781                            EM_LIMITTEXT, (WORD)(MAXTONAME - 1), 0L);
10782         CheckDlgButton(hdlg, IDC_STEPAPI,
10783                        getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
10784                        BST_CHECKED : BST_UNCHECKED);
10785         CheckDlgButton(hdlg, IDC_NOTXN,
10786                        getbool(setupdlg->attr[KEY_NOTXN].attr) ?
10787                        BST_CHECKED : BST_UNCHECKED);
10788         CheckDlgButton(hdlg, IDC_LONGNAM,
10789                        getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
10790                        BST_CHECKED : BST_UNCHECKED);
10791         SendDlgItemMessage(hdlg, IDC_SYNCP,
10792                            CB_LIMITTEXT, (WPARAM) 10, 0);
10793         SendDlgItemMessage(hdlg, IDC_SYNCP,
10794                            CB_ADDSTRING, 0, (LONG) "NORMAL");
10795         SendDlgItemMessage(hdlg, IDC_SYNCP,
10796                            CB_ADDSTRING, 0, (LONG) "OFF");
10797         SendDlgItemMessage(hdlg, IDC_SYNCP,
10798                            CB_ADDSTRING, 0, (LONG) "FULL");
10799         SendDlgItemMessage(hdlg, IDC_SYNCP,
10800                            CB_SELECTSTRING, (WORD) -1,
10801                            (LONG) setupdlg->attr[KEY_SYNCP].attr);
10802         return TRUE;
10803     case WM_COMMAND:
10804         switch (GET_WM_COMMAND_ID(wparam, lparam)) {
10805         case IDC_BROWSE:
10806             GetDBFile(hdlg);
10807             break;
10808         case IDOK:
10809             setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
10810             GetDlgItemText(hdlg, IDC_DSNAME,
10811                            setupdlg->attr[KEY_DSN].attr,
10812                            sizeof (setupdlg->attr[KEY_DSN].attr));
10813             GetDlgItemText(hdlg, IDC_DBNAME,
10814                            setupdlg->attr[KEY_DBNAME].attr,
10815                            sizeof (setupdlg->attr[KEY_DBNAME].attr));
10816             GetDlgItemText(hdlg, IDC_TONAME,
10817                            setupdlg->attr[KEY_BUSY].attr,
10818                            sizeof (setupdlg->attr[KEY_BUSY].attr));
10819             index = SendDlgItemMessage(hdlg, IDC_SYNCP,
10820                                        CB_GETCURSEL, (WORD) 0, (LONG) 0);
10821             if (index != (WORD) CB_ERR) {
10822                 SendDlgItemMessage(hdlg, IDC_SYNCP,
10823                                    CB_GETLBTEXT, index,
10824                                    (LONG) setupdlg->attr[KEY_SYNCP].attr);
10825             }
10826             strcpy(setupdlg->attr[KEY_STEPAPI].attr,
10827                    IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED ?
10828                    "1" : "0");
10829             strcpy(setupdlg->attr[KEY_NOTXN].attr,
10830                    IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED ?
10831                    "1" : "0");
10832             strcpy(setupdlg->attr[KEY_LONGNAM].attr,
10833                    IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED ?
10834                    "1" : "0");
10835             /* FALL THROUGH */
10836         case IDCANCEL:
10837             EndDialog(hdlg, GET_WM_COMMAND_ID(wparam, lparam) == IDOK);
10838             return TRUE;
10839         }
10840     }
10841     return FALSE;
10842 }
10843 
10857 static SQLRETURN
10858 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
10859                  SQLCHAR *connIn, SQLSMALLINT connInLen,
10860                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
10861                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
10862 {
10863     BOOL maybeprompt, prompt = FALSE;
10864     DBC *d;
10865     SETUPDLG *setupdlg;
10866     short ret;
10867     SQLRETURN rc;
10868 
10869     if (dbc == SQL_NULL_HDBC) {
10870         return SQL_INVALID_HANDLE;
10871     }
10872     d = (DBC *) dbc;
10873     if (d->sqlite) {
10874         setstatd(d, -1, "connection already established", "08002");
10875         return SQL_ERROR;
10876     }
10877     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
10878     if (setupdlg == NULL) {
10879         return SQL_ERROR;
10880     }
10881     memset(setupdlg, 0, sizeof (SETUPDLG));
10882     maybeprompt = drvcompl == SQL_DRIVER_COMPLETE ||
10883         drvcompl == SQL_DRIVER_COMPLETE_REQUIRED;
10884     if (connIn == NULL || !connInLen ||
10885         (connInLen == SQL_NTS && !connIn[0])) {
10886         prompt = TRUE;
10887     } else {
10888         ParseAttributes(connIn, setupdlg);
10889         if (!setupdlg->attr[KEY_DSN].attr[0] &&
10890             drvcompl == SQL_DRIVER_COMPLETE_REQUIRED) {
10891             strcpy(setupdlg->attr[KEY_DSN].attr, "DEFAULT");
10892         }
10893         GetAttributes(setupdlg);
10894         if (drvcompl == SQL_DRIVER_PROMPT ||
10895             (maybeprompt &&
10896              (!setupdlg->attr[KEY_DSN].attr[0] ||
10897               !setupdlg->attr[KEY_DBNAME].attr[0]))) {
10898             prompt = TRUE;
10899         }
10900     }
10901 retry:
10902     if (prompt) {
10903         ret = DialogBoxParam(hModule, MAKEINTRESOURCE(DRIVERCONNECT),
10904                              hwnd, (DLGPROC) DriverConnectProc,
10905                              (LONG) setupdlg);
10906         if (!ret || ret == -1) {
10907             xfree(setupdlg);
10908             return SQL_NO_DATA_FOUND;
10909         }
10910     }
10911     if (connOut || connOutLen) {
10912         char buf[1024];
10913         int len, count;
10914         char dsn_0 = setupdlg->attr[KEY_DSN].attr[0];
10915         char drv_0 = setupdlg->attr[KEY_DRIVER].attr[0];
10916 
10917         buf[0] = '\0';
10918         count = snprintf(buf, sizeof (buf),
10919                          "%s%s%s%s%s%sDatabase=%s;StepAPI=%s;"
10920                          "SyncPragma=%s;NoTXN=%s;Timeout=%s;LongNames=%s",
10921                          dsn_0 ? "DSN=" : "",
10922                          dsn_0 ? setupdlg->attr[KEY_DSN].attr : "",
10923                          dsn_0 ? ";" : "",
10924                          drv_0 ? "Driver=" : "",
10925                          drv_0 ? setupdlg->attr[KEY_DRIVER].attr : "",
10926                          drv_0 ? ";" : "",
10927                          setupdlg->attr[KEY_DBNAME].attr,
10928                          setupdlg->attr[KEY_STEPAPI].attr,
10929                          setupdlg->attr[KEY_SYNCP].attr,
10930                          setupdlg->attr[KEY_NOTXN].attr,
10931                          setupdlg->attr[KEY_BUSY].attr,
10932                          setupdlg->attr[KEY_LONGNAM].attr);
10933         if (count < 0) {
10934             buf[sizeof (buf) - 1] = '\0';
10935         }
10936         len = min(connOutMax - 1, strlen(buf));
10937         if (connOut) {
10938             strncpy(connOut, buf, len);
10939             connOut[len] = '\0';
10940         }
10941         if (connOutLen) {
10942             *connOutLen = len;
10943         }
10944     }
10945     d->longnames = getbool(setupdlg->attr[KEY_LONGNAM].attr);
10946     rc = dbopen(d, setupdlg->attr[KEY_DBNAME].attr,
10947                 setupdlg->attr[KEY_DSN].attr,
10948                 setupdlg->attr[KEY_STEPAPI].attr,
10949                 setupdlg->attr[KEY_SYNCP].attr,
10950                 setupdlg->attr[KEY_NOTXN].attr,
10951                 setupdlg->attr[KEY_BUSY].attr);
10952     if (rc != SQL_SUCCESS) {
10953         if (maybeprompt && !prompt) {
10954             prompt = TRUE;
10955             goto retry;
10956         }
10957         xfree(setupdlg);
10958         return rc;
10959     }
10960     xfree(setupdlg);
10961     return SQL_SUCCESS;
10962 }
10963 
10964 #endif /* WITHOUT_DRIVERMGR */
10965 #endif /* _WIN32 */
10966 
10967 #ifndef WITHOUT_DRIVERMGR
10968 
10982 SQLRETURN SQL_API
10983 SQLDriverConnect(SQLHDBC dbc, SQLHWND hwnd,
10984                  SQLCHAR *connIn, SQLSMALLINT connInLen,
10985                  SQLCHAR *connOut, SQLSMALLINT connOutMax,
10986                  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
10987 {
10988     return drvdriverconnect(dbc, hwnd, connIn, connInLen,
10989                             connOut, connOutMax, connOutLen, drvcompl);
10990 }
10991 
10992 #endif /* WITHOUT_DRIVERMGR */
10993 
10994 #ifdef _WIN32
10995 
11004 BOOL APIENTRY
11005 LibMain(HANDLE hinst, DWORD reason, LPVOID reserved)
11006 {
11007     static int initialized = 0;
11008 
11009     switch (reason) {
11010     case DLL_PROCESS_ATTACH:
11011         if (!initialized++) {
11012 #ifndef _MSC_VER
11013             /* this allows to link sqlite3.exe against this DLL */
11014             sqlite3_complete("");
11015 #endif
11016             hModule = hinst;
11017         }
11018         break;
11019     case DLL_THREAD_ATTACH:
11020         break;
11021     case DLL_PROCESS_DETACH:
11022         --initialized;
11023         break;
11024     case DLL_THREAD_DETACH:
11025         break;
11026     default:
11027         break;
11028     }
11029     return TRUE;
11030 }
11031 
11040 int __stdcall
11041 DllMain(HANDLE hinst, DWORD reason, LPVOID reserved)
11042 {
11043     return LibMain(hinst, reason, reserved);
11044 }
11045 
11046 #endif /* _WIN32 */
11047 
11048 #if defined(HAVE_ODBCINSTEXT_H) && HAVE_ODBCINSTEXT_H
11049 
11050 /*
11051  * unixODBC property page for this driver,
11052  * may or may not work depending on unixODBC version.
11053  */
11054 
11055 #include <odbcinstext.h>
11056 
11057 int
11058 ODBCINSTGetProperties(HODBCINSTPROPERTY prop)
11059 {
11060     static const char *instYN[] = { "No", "Yes", NULL };
11061     static const char *syncPragma[] = { "NORMAL", "OFF", "FULL", NULL };
11062 
11063     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
11064     prop = prop->pNext;
11065     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
11066     prop->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
11067     strncpy(prop->szName, "Database", INI_MAX_PROPERTY_NAME);
11068     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
11069     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
11070     prop = prop->pNext;
11071     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
11072     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
11073     strncpy(prop->szName, "Timeout", INI_MAX_PROPERTY_NAME);
11074     strncpy(prop->szValue, "1000", INI_MAX_PROPERTY_VALUE);
11075     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
11076     prop = prop->pNext;
11077     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
11078     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
11079     prop->aPromptData = malloc(sizeof (instYN));
11080     memcpy(prop->aPromptData, instYN, sizeof (instYN));
11081     strncpy(prop->szName, "StepAPI", INI_MAX_PROPERTY_NAME);
11082     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
11083     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
11084     prop = prop->pNext;
11085     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
11086     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
11087     prop->aPromptData = malloc(sizeof (instYN));
11088     memcpy(prop->aPromptData, instYN, sizeof (instYN));
11089     strncpy(prop->szName, "LongNames", INI_MAX_PROPERTY_NAME);
11090     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
11091     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
11092     prop = prop->pNext;
11093     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
11094     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
11095     prop->aPromptData = malloc(sizeof (syncPragma));
11096     memcpy(prop->aPromptData, syncPragma, sizeof (syncPragma));
11097     strncpy(prop->szName, "SyncPragma", INI_MAX_PROPERTY_NAME);
11098     strncpy(prop->szValue, "NORMAL", INI_MAX_PROPERTY_VALUE);
11099     return 1;
11100 }
11101 
11102 #endif /* HAVE_ODBCINSTEXT_H */

Generated on 24 Apr 2006 by doxygen.
Contact: chw@ch-werner.de