1 /**
2  * @file sqlite3odbc.c
3  * SQLite3 ODBC Driver main module.
4  *
5  * $Id: sqlite3odbc.c,v 1.179 2020/06/20 11:56:09 chw Exp chw $
6  *
7  * Copyright (c) 2004-2020 Christian Werner <chw@ch-werner.de>
8  *
9  * See the file "license.terms" for information on usage
10  * and redistribution of this file and for a
11  * DISCLAIMER OF ALL WARRANTIES.
12  */
13 
14 #if defined(SQLITE_HAS_CODEC) && defined(SQLITE_API)
15 #undef WITH_SQLITE_DLLS
16 #undef SQLITE_DYNLOAD
17 #include "sqlite3.c"
18 #endif
19 
20 #if defined(WITH_SQLITE_DLLS) && (WITH_SQLITE_DLLS > 1)
21 #define SQLITE_DYNLOAD 1
22 #undef  HAVE_SQLITE3CLOSEV2
23 #endif
24 
25 #include "sqlite3odbc.h"
26 
27 #ifdef SQLITE_DYNLOAD
28 
29 #undef MEMORY_DEBUG
30 
31 #if defined(_WIN32) || defined(_WIN64)
32 static void dls_init(void);
33 static void dls_fini(void);
34 #else
35 void dls_init(void);
36 void dls_fini(void);
37 #endif
38 
39 static struct dl_sqlite3_funcs {
40     void (*activate_see)(const char *p0);
41     int (*bind_blob)(sqlite3_stmt *p0, int p1, const void *p2, int p3,
42 		     void (*p4)(void *));
43     int (*bind_double)(sqlite3_stmt *p0, int p1, double p2);
44     int (*bind_int)(sqlite3_stmt *p0, int p1, int p2);
45     int (*bind_int64)(sqlite3_stmt *p0, int p1, sqlite_int64 p2);
46     int (*bind_null)(sqlite3_stmt *p0, int p1);
47     int (*bind_parameter_count)(sqlite3_stmt *p0);
48     int (*bind_text)(sqlite3_stmt *p0, int p1, const char *p2, int p3,
49 		     void (*p4)(void *));
50     int (*busy_handler)(sqlite3 *p0, int (*p2)(void *, int), void *p3);
51     int (*changes)(sqlite3 *p0);
52     int (*close)(sqlite3 *p0);
53     const void * (*column_blob)(sqlite3_stmt *p0, int p1);
54     int (*column_bytes)(sqlite3_stmt *p0, int p1);
55     int (*column_count)(sqlite3_stmt *p0);
56     const char * (*column_database_name)(sqlite3_stmt *p0, int p1);
57     const char * (*column_decltype)(sqlite3_stmt *p0, int p1);
58     double (*column_double)(sqlite3_stmt *p0, int p1);
59     const char * (*column_name)(sqlite3_stmt *p0, int p1);
60     const char * (*column_origin_name)(sqlite3_stmt *p0, int p1);
61     const char * (*column_table_name)(sqlite3_stmt *p0, int p1);
62     const unsigned char * (*column_text)(sqlite3_stmt *p0, int p1);
63     int (*column_type)(sqlite3_stmt *p0, int p1);
64     int (*create_function)(sqlite3 *p0, const char *p1, int p2, int p3,
65 			   void *p4,
66 			   void (*p5)(sqlite3_context *, int, sqlite3_value **),
67 			   void (*p6)(sqlite3_context *, int, sqlite3_value **),
68 			   void (*p7)(sqlite3_context *));
69     int (*enable_load_extension)(sqlite3 *p0, int p1);
70     int (*errcode)(sqlite3 *p0);
71     const char * (*errmsg)(sqlite3 *p0);
72     int (*exec)(sqlite3 *p0, const char *p1,
73 		int (*p2)(void *, int, char **, char **),
74 		void *p3, char **p4);
75     int (*finalize)(sqlite3_stmt *p0);
76     void (*free)(void *p0);
77     void (*free_table)(char **p0);
78     int (*get_table)(sqlite3 *p0, const char *p1, char ***p2,
79 		     int *p3, int *p4, char **p5);
80     void (*interrupt)(sqlite3 *p0);
81     int (*key)(sqlite3 *p0, const void *p1, int p2);
82     sqlite_int64 (*last_insert_rowid)(sqlite3 *p0);
83     const char * (*libversion)(void);
84     int (*load_extension)(sqlite3 *p0, const char *p1, const char *p2,
85 			  char **p3);
86     void * (*malloc)(int p0);
87     char * (*mprintf)(const char *p0, ...);
88     int (*open)(const char *p0, sqlite3 **p1);
89     int (*open16)(const void *p0, sqlite3 **p1);
90     int (*open_v2)(const char *p0, sqlite3 **p1, int p2, const char *p3);
91     int (*prepare)(sqlite3 *p0, const char *p1, int p2, sqlite3_stmt **p3,
92 		   const char **p4);
93     int (*prepare_v2)(sqlite3 *p0, const char *p1, int p2, sqlite3_stmt **p3,
94 		      const char **p4);
95     void * (*profile)(sqlite3 *p0,
96 		      void (*p1)(void *, const char *, sqlite3_uint64),
97 		      void *p2);
98     void * (*realloc)(void *p0, int p1);
99     int (*rekey)(sqlite3 *p0, const void *p1, int p2);
100     int (*reset)(sqlite3_stmt *p0);
101     void (*result_blob)(sqlite3_context *p0, const void *p1,
102 			int p2, void (*p3)(void *));
103     void (*result_error)(sqlite3_context *p0, const char *p1, int p2);
104     void (*result_int)(sqlite3_context *p0, int p1);
105     void (*result_null)(sqlite3_context *p0);
106     int (*step)(sqlite3_stmt *p0);
107     int (*xstrnicmp)(const char *p0, const char *p1, int p2);
108     int (*table_column_metadata)(sqlite3 *p0, const char *p1,
109 				 const char *p2, const char *p3,
110 				 char const **p4, char const **p5,
111 				 int *p6, int *p7, int *p8);
112     void * (*trace)(sqlite3 *p0, void (*p1)(void *, const char *), void *p2);
113     void * (*user_data)(sqlite3_context *p0);
114     const void * (*value_blob)(sqlite3_value *p0);
115     int (*value_bytes)(sqlite3_value *p0);
116     const unsigned char * (*value_text)(sqlite3_value *p0);
117     int (*value_type)(sqlite3_value *p0);
118 } dls_funcs;
119 
120 #define sqlite3_activate_see          dls_funcs.activate_see
121 #define sqlite3_bind_blob             dls_funcs.bind_blob
122 #define sqlite3_bind_double           dls_funcs.bind_double
123 #define sqlite3_bind_int              dls_funcs.bind_int
124 #define sqlite3_bind_int64            dls_funcs.bind_int64
125 #define sqlite3_bind_null             dls_funcs.bind_null
126 #define sqlite3_bind_parameter_count  dls_funcs.bind_parameter_count
127 #define sqlite3_bind_text             dls_funcs.bind_text
128 #define sqlite3_busy_handler          dls_funcs.busy_handler
129 #define sqlite3_changes               dls_funcs.changes
130 #define sqlite3_close                 dls_funcs.close
131 #define sqlite3_column_blob           dls_funcs.column_blob
132 #define sqlite3_column_bytes          dls_funcs.column_bytes
133 #define sqlite3_column_count          dls_funcs.column_count
134 #define sqlite3_column_database_name  dls_funcs.column_database_name
135 #define sqlite3_column_decltype       dls_funcs.column_decltype
136 #define sqlite3_column_double         dls_funcs.column_double
137 #define sqlite3_column_name           dls_funcs.column_name
138 #define sqlite3_column_origin_name    dls_funcs.column_origin_name
139 #define sqlite3_column_table_name     dls_funcs.column_table_name
140 #define sqlite3_column_text           dls_funcs.column_text
141 #define sqlite3_column_type           dls_funcs.column_type
142 #define sqlite3_create_function       dls_funcs.create_function
143 #define sqlite3_enable_load_extension dls_funcs.enable_load_extension
144 #define sqlite3_errcode               dls_funcs.errcode
145 #define sqlite3_errmsg                dls_funcs.errmsg
146 #define sqlite3_exec                  dls_funcs.exec
147 #define sqlite3_finalize              dls_funcs.finalize
148 #define sqlite3_free                  dls_funcs.free
149 #define sqlite3_free_table            dls_funcs.free_table
150 #define sqlite3_get_table             dls_funcs.get_table
151 #define sqlite3_interrupt             dls_funcs.interrupt
152 #define sqlite3_key                   dls_funcs.key
153 #define sqlite3_last_insert_rowid     dls_funcs.last_insert_rowid
154 #define sqlite3_libversion            dls_funcs.libversion
155 #define sqlite3_load_extension        dls_funcs.load_extension
156 #define sqlite3_malloc                dls_funcs.malloc
157 #define sqlite3_mprintf               dls_funcs.mprintf
158 #define sqlite3_open                  dls_funcs.open
159 #define sqlite3_open16                dls_funcs.open16
160 #define sqlite3_open_v2               dls_funcs.open_v2
161 #define sqlite3_prepare               dls_funcs.prepare
162 #define sqlite3_prepare_v2            dls_funcs.prepare_v2
163 #define sqlite3_profile               dls_funcs.profile
164 #define sqlite3_realloc               dls_funcs.realloc
165 #define sqlite3_rekey                 dls_funcs.rekey
166 #define sqlite3_reset                 dls_funcs.reset
167 #define sqlite3_result_blob           dls_funcs.result_blob
168 #define sqlite3_result_error          dls_funcs.result_error
169 #define sqlite3_result_int            dls_funcs.result_int
170 #define sqlite3_result_null           dls_funcs.result_null
171 #define sqlite3_step                  dls_funcs.step
172 #define sqlite3_strnicmp              dls_funcs.xstrnicmp
173 #define sqlite3_table_column_metadata dls_funcs.table_column_metadata
174 #define sqlite3_trace                 dls_funcs.trace
175 #define sqlite3_user_data             dls_funcs.user_data
176 #define sqlite3_value_blob            dls_funcs.value_blob
177 #define sqlite3_value_bytes           dls_funcs.value_bytes
178 #define sqlite3_value_text            dls_funcs.value_text
179 #define sqlite3_value_type            dls_funcs.value_type
180 
181 #endif
182 
183 #ifndef WITHOUT_WINTERFACE
184 #define WINTERFACE
185 #define WCHARSUPPORT
186 #endif
187 
188 #if !defined(_WIN32) && !defined(_WIN64)
189 #if !defined(WCHARSUPPORT) && defined(HAVE_SQLWCHAR) && (HAVE_SQLWCHAR)
190 #define WCHARSUPPORT
191 #endif
192 #endif
193 
194 #if defined(WINTERFACE)
195 #include <sqlucode.h>
196 #endif
197 
198 #if defined(_WIN32) || defined(_WIN64)
199 #include "resource3.h"
200 #define ODBC_INI "ODBC.INI"
201 #ifndef DRIVER_VER_INFO
202 #define DRIVER_VER_INFO VERSION
203 #endif
204 #else
205 #define ODBC_INI ".odbc.ini"
206 #endif
207 
208 #ifndef DRIVER_VER_INFO
209 #define DRIVER_VER_INFO "0.0"
210 #endif
211 
212 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
213 #ifdef _WIN64
214 #define COLATTRIBUTE_LAST_ARG_TYPE SQLLEN *
215 #else
216 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
217 #endif
218 #endif
219 
220 #ifndef SETSTMTOPTION_LAST_ARG_TYPE
221 #define SETSTMTOPTION_LAST_ARG_TYPE SQLROWCOUNT
222 #endif
223 
224 #undef min
225 #define min(a, b) ((a) < (b) ? (a) : (b))
226 #undef max
227 #define max(a, b) ((a) < (b) ? (b) : (a))
228 
229 #ifndef PTRDIFF_T
230 #define PTRDIFF_T int
231 #endif
232 
233 #define array_size(x) (sizeof (x) / sizeof (x[0]))
234 
235 #define stringify1(s) #s
236 #define stringify(s) stringify1(s)
237 
238 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
239 
240 /* Column meta data from SQLite support */
241 #undef FULL_METADATA
242 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && (HAVE_SQLITE3TABLECOLUMNMETADATA)
243 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
244 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
245 #if defined(HAVE_SQLITE3COLUMNORIGINNAME) && (HAVE_SQLITE3COLUMNORIGINNAME)
246 #define FULL_METADATA 1
247 #endif
248 #endif
249 #endif
250 #endif
251 
252 /* Column types for static string column descriptions (SQLTables etc.) */
253 
254 #if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
255 #define SCOL_VARCHAR SQL_WVARCHAR
256 #define SCOL_CHAR SQL_WCHAR
257 #else
258 #define SCOL_VARCHAR SQL_VARCHAR
259 #define SCOL_CHAR SQL_CHAR
260 #endif
261 
262 #define ENV_MAGIC  0x53544145
263 #define DBC_MAGIC  0x53544144
264 #define DEAD_MAGIC 0xdeadbeef
265 
266 /**
267  * @typedef dstr
268  * @struct dstr
269  * Internal structure representing dynamic strings.
270  */
271 
272 typedef struct dstr {
273     int len;		/**< Current length. */
274     int max;		/**< Maximum length of buffer. */
275     int oom;		/**< True when out of memory. */
276     char buffer[1];	/**< String buffer. */
277 } dstr;
278 
279 static const char *xdigits = "0123456789ABCDEFabcdef";
280 
281 #ifdef MEMORY_DEBUG
282 
283 static void *
xmalloc_(int n,char * file,int line)284 xmalloc_(int n, char *file, int line)
285 {
286     int nn = n + 4 * sizeof (long);
287     long *p;
288 
289     p = malloc(nn);
290     if (!p) {
291 #if (MEMORY_DEBUG > 1)
292 	fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
293 #endif
294 	return NULL;
295     }
296     p[0] = 0xdead1234;
297     nn = nn / sizeof (long) - 1;
298     p[1] = n;
299     p[nn] = 0xdead5678;
300 #if (MEMORY_DEBUG > 1)
301     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
302 #endif
303     return (void *) &p[2];
304 }
305 
306 static void *
xrealloc_(void * old,int n,char * file,int line)307 xrealloc_(void *old, int n, char *file, int line)
308 {
309     int nn = n + 4 * sizeof (long), nnn;
310     long *p, *pp;
311 
312     if (n == 0 || !old) {
313 	return xmalloc_(n, file, line);
314     }
315     p = &((long *) old)[-2];
316     if (p[0] != 0xdead1234) {
317 	fprintf(stderr, "*** low end corruption @ %p\n", old);
318 	abort();
319     }
320     nnn = p[1] + 4 * sizeof (long);
321     nnn = nnn / sizeof (long) - 1;
322     if (p[nnn] != 0xdead5678) {
323 	fprintf(stderr, "*** high end corruption @ %p\n", old);
324 	abort();
325     }
326     pp = realloc(p, nn);
327     if (!pp) {
328 #if (MEMORY_DEBUG > 1)
329 	fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
330 #endif
331 	return NULL;
332     }
333 #if (MEMORY_DEBUG > 1)
334     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
335 #endif
336     p = pp;
337     p[1] = n;
338     nn = nn / sizeof (long) - 1;
339     p[nn] = 0xdead5678;
340     return (void *) &p[2];
341 }
342 
343 static void
xfree_(void * x,char * file,int line)344 xfree_(void *x, char *file, int line)
345 {
346     long *p;
347     int n;
348 
349     if (!x) {
350 	return;
351     }
352     p = &((long *) x)[-2];
353     if (p[0] != 0xdead1234) {
354 	fprintf(stderr, "*** low end corruption @ %p\n", x);
355 	abort();
356     }
357     n = p[1] + 4 * sizeof (long);
358     n = n / sizeof (long) - 1;
359     if (p[n] != 0xdead5678) {
360 	fprintf(stderr, "*** high end corruption @ %p\n", x);
361 	abort();
362     }
363 #if (MEMORY_DEBUG > 1)
364     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
365 #endif
366     free(p);
367 }
368 
369 static void
xfree__(void * x)370 xfree__(void *x)
371 {
372     xfree_(x, "unknown location", 0);
373 }
374 
375 static char *
xstrdup_(const char * str,char * file,int line)376 xstrdup_(const char *str, char *file, int line)
377 {
378     char *p;
379 
380     if (!str) {
381 #if (MEMORY_DEBUG > 1)
382 	fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
383 #endif
384 	return NULL;
385     }
386     p = xmalloc_(strlen(str) + 1, file, line);
387     if (p) {
388 	strcpy(p, str);
389     }
390 #if (MEMORY_DEBUG > 1)
391     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
392 #endif
393     return p;
394 }
395 
396 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
397 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
398 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
399 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
400 
401 #else
402 
403 #define xmalloc(x)    sqlite3_malloc(x)
404 #define xrealloc(x,y) sqlite3_realloc(x, y)
405 #define xfree(x)      sqlite3_free(x)
406 #define xstrdup(x)    strdup_(x)
407 
408 #endif
409 
410 #if defined(_WIN32) || defined(_WIN64)
411 
412 #define vsnprintf   _vsnprintf
413 #define snprintf    _snprintf
414 #define strcasecmp  _stricmp
415 #define strncasecmp _strnicmp
416 
417 #ifdef _MSC_VER
418 #define strtoll     _strtoi64
419 #define strtoull    _strtoui64
420 #endif
421 
422 static HINSTANCE NEAR hModule;	/* Saved module handle for resources */
423 
424 #endif
425 
426 #ifdef HAVE_SQLITE3STRNICMP
427 #undef  strncasecmp
428 #define strncasecmp(A,B,C) sqlite3_strnicmp(A,B,C)
429 #undef  strcasecmp
430 #define strcasecmp(A,B) strcasecmp_(A,B)
431 
432 #if defined(__GNUC__) && (__GNUC__ >= 2)
433 static int strcasecmp_(const char *a, const char *b)
434     __attribute__((__unused__));
435 #endif
436 
strcasecmp_(const char * a,const char * b)437 static int strcasecmp_(const char *a, const char *b)
438 {
439     int c = strlen(a), d = strlen(b);
440 
441     if (c > d) {
442 	return strncasecmp(a, b, c);
443     }
444     return strncasecmp(a, b, d);
445 }
446 #endif
447 
448 #if defined(_WIN32) || defined(_WIN64)
449 
450 /*
451  * SQLHENV, SQLHDBC, and SQLHSTMT synchronization
452  * is done using a critical section in ENV and DBC
453  * structures.
454  */
455 
456 #define HDBC_LOCK(hdbc)				\
457 {						\
458     DBC *d;					\
459 						\
460     if ((hdbc) == SQL_NULL_HDBC) {		\
461 	return SQL_INVALID_HANDLE;		\
462     }						\
463     d = (DBC *) (hdbc);				\
464     if (d->magic != DBC_MAGIC) {		\
465 	return SQL_INVALID_HANDLE;		\
466     }						\
467     EnterCriticalSection(&d->cs);		\
468     d->owner = GetCurrentThreadId();		\
469 }
470 
471 #define HDBC_UNLOCK(hdbc)			\
472     if ((hdbc) != SQL_NULL_HDBC) {		\
473 	DBC *d;					\
474 						\
475 	d = (DBC *) (hdbc);			\
476 	if (d->magic == DBC_MAGIC) {		\
477 	    d->owner = 0;			\
478 	    LeaveCriticalSection(&d->cs);	\
479 	}					\
480     }
481 
482 #define HSTMT_LOCK(hstmt)			\
483 {						\
484     DBC *d;					\
485 						\
486     if ((hstmt) == SQL_NULL_HSTMT) {		\
487 	return SQL_INVALID_HANDLE;		\
488     }						\
489     d = (DBC *) ((STMT *) (hstmt))->dbc;	\
490     if (d->magic != DBC_MAGIC) {		\
491 	return SQL_INVALID_HANDLE;		\
492     }						\
493     EnterCriticalSection(&d->cs);		\
494     d->owner = GetCurrentThreadId();		\
495 }
496 
497 #define HSTMT_UNLOCK(hstmt)			\
498     if ((hstmt) != SQL_NULL_HSTMT) {		\
499 	DBC *d;					\
500 						\
501 	d = (DBC *) ((STMT *) (hstmt))->dbc;	\
502 	if (d->magic == DBC_MAGIC) {		\
503 	    d->owner = 0;			\
504 	    LeaveCriticalSection(&d->cs);	\
505 	}					\
506     }
507 
508 #else
509 
510 /*
511  * On UN*X assume that we are single-threaded or
512  * the driver manager provides serialization for us.
513  *
514  * In iODBC (3.52.x) serialization can be turned
515  * on using the DSN property "ThreadManager=yes".
516  *
517  * In unixODBC that property is named
518  * "Threading=0-3" and takes one of these values:
519  *
520  *   0 - no protection
521  *   1 - statement level protection
522  *   2 - connection level protection
523  *   3 - environment level protection
524  *
525  * unixODBC 2.2.11 uses environment level protection
526  * by default when it has been built with pthread
527  * support.
528  */
529 
530 #define HDBC_LOCK(hdbc)
531 #define HDBC_UNLOCK(hdbc)
532 #define HSTMT_LOCK(hdbc)
533 #define HSTMT_UNLOCK(hdbc)
534 
535 #endif
536 
537 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
538 extern void nvfs_init(void);
539 extern const char *nvfs_makevfs(const char *);
540 #endif
541 
542 /*
543  * tolower() replacement w/o locale
544  */
545 
546 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
547 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
548 
549 static int
TOLOWER(int c)550 TOLOWER(int c)
551 {
552     if (c) {
553 	char *p = strchr(upper_chars, c);
554 
555 	if (p) {
556 	    c = lower_chars[p - upper_chars];
557 	}
558     }
559     return c;
560 }
561 
562 /*
563  * isdigit() replacement w/o ctype.h
564  */
565 
566 static const char digit_chars[] = "0123456789";
567 
568 #define ISDIGIT(c) \
569     ((c) && strchr(digit_chars, (c)) != NULL)
570 
571 /*
572  * isspace() replacement w/o ctype.h
573  */
574 
575 static const char space_chars[] = " \f\n\r\t\v";
576 
577 #define ISSPACE(c) \
578     ((c) && strchr(space_chars, (c)) != NULL)
579 
580 
581 /*
582  * Forward declarations of static functions.
583  */
584 
585 static void dbtraceapi(DBC *d, char *fn, const char *sql);
586 static void freedyncols(STMT *s);
587 static void freeresult(STMT *s, int clrcols);
588 static void freerows(char **rowp);
589 static void unbindcols(STMT *s);
590 static void s3stmt_drop(STMT *s);
591 
592 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
593 static SQLRETURN freestmt(HSTMT stmt);
594 static SQLRETURN mkbindcols(STMT *s, int ncols);
595 static SQLRETURN setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp);
596 static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
597 static SQLRETURN starttran(STMT *s);
598 static SQLRETURN setupparam(STMT *s, char *sql, int pnum);
599 static SQLRETURN getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
600 			    SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp,
601 			    int partial);
602 
603 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
604 /* MS Access hack part 1 (reserved error -7748) */
605 static COL *statSpec2P, *statSpec3P;
606 #endif
607 
608 #if (MEMORY_DEBUG < 1)
609 /**
610  * Duplicate string using xmalloc().
611  * @param str string to be duplicated
612  * @result pointer to new string or NULL
613  */
614 
615 static char *
strdup_(const char * str)616 strdup_(const char *str)
617 {
618     char *p = NULL;
619 
620     if (str) {
621 	p = xmalloc(strlen(str) + 1);
622 	if (p) {
623 	    strcpy(p, str);
624 	}
625     }
626     return p;
627 }
628 #endif
629 
630 /**
631  * Append string to dynamic string.
632  * @param dsp dstr pointer
633  * @param str string to append
634  * @result dsp result dstr pointer or NULL.
635  */
636 
637 static dstr *
dsappend(dstr * dsp,const char * str)638 dsappend(dstr *dsp, const char *str)
639 {
640     int len;
641 
642     if (!str) {
643 	return dsp;
644     }
645     len = strlen(str);
646     if (!dsp) {
647 	int max = 256;
648 
649 	if (max < len) {
650 	    max += len;
651 	}
652 	dsp = xmalloc(max);
653 	if (dsp) {
654 	    dsp->max = max;
655 	    dsp->len = dsp->oom = 0;
656 	    goto copy;
657 	}
658 	return dsp;
659     }
660     if (dsp->oom) {
661 	return dsp;
662     }
663     if (dsp->len + len > dsp->max) {
664 	int max = dsp->max + len + 256;
665 	dstr *ndsp = xrealloc(dsp, max);
666 
667 	if (!ndsp) {
668 	    strcpy(dsp->buffer, "OUT OF MEMORY");
669 	    dsp->max = dsp->len = 13;
670 	    dsp->oom = 1;
671 	    return dsp;
672 	}
673 	dsp = ndsp;
674 	dsp->max = max;
675     }
676 copy:
677     strcpy(dsp->buffer + dsp->len, str);
678     dsp->len += len;
679     return dsp;
680 }
681 
682 /**
683  * Append a string double quoted to dynamic string.
684  * @param dsp dstr pointer
685  * @param str string to append
686  * @result dsp result dstr pointer or NULL.
687  */
688 
689 static dstr *
dsappendq(dstr * dsp,const char * str)690 dsappendq(dstr *dsp, const char *str)
691 {
692     int len;
693     const char *p;
694     char *q;
695 
696     if (!str) {
697 	return dsp;
698     }
699     len = strlen(str);
700     for (p = str; *p; ++p) {
701 	if (p[0] == '"') {
702 	    ++len;
703 	}
704     }
705     len += 2;
706     if (!dsp) {
707 	int max = 256;
708 
709 	if (max < len) {
710 	    max += len;
711 	}
712 	dsp = xmalloc(max);
713 	if (dsp) {
714 	    dsp->max = max;
715 	    dsp->len = dsp->oom = 0;
716 	    goto copy;
717 	}
718 	return dsp;
719     }
720     if (dsp->oom) {
721 	return dsp;
722     }
723     if (dsp->len + len > dsp->max) {
724 	int max = dsp->max + len + 256;
725 	dstr *ndsp = xrealloc(dsp, max);
726 
727 	if (!ndsp) {
728 	    strcpy(dsp->buffer, "OUT OF MEMORY");
729 	    dsp->max = dsp->len = 13;
730 	    dsp->oom = 1;
731 	    return dsp;
732 	}
733 	dsp = ndsp;
734 	dsp->max = max;
735     }
736 copy:
737     q = dsp->buffer + dsp->len;
738     *q++ = '"';
739     for (p = str; *p; ++p) {
740 	*q++ = *p;
741 	if (p[0] == '"') {
742 	    *q++ = '"';
743 	}
744     }
745     *q++ = '"';
746     *q = '\0';
747     dsp->len += len;
748     return dsp;
749 }
750 
751 /**
752  * Return dynamic string's value.
753  * @param dsp dstr pointer
754  * @result string value
755  */
756 
757 static const char *
dsval(dstr * dsp)758 dsval(dstr *dsp)
759 {
760     if (dsp) {
761 	return (const char *) dsp->buffer;
762     }
763     return "ERROR";
764 }
765 
766 /**
767  * Check error on dynamic string.
768  * @param dsp dstr pointer
769  * @result true when error pending
770  */
771 
772 static int
dserr(dstr * dsp)773 dserr(dstr *dsp)
774 {
775     return !dsp || dsp->oom;
776 }
777 
778 /**
779  * Free dynamic string.
780  * @param dsp dstr pointer
781  */
782 
783 static void
dsfree(dstr * dsp)784 dsfree(dstr *dsp)
785 {
786     if (dsp) {
787 	xfree(dsp);
788     }
789 }
790 
791 #ifdef WCHARSUPPORT
792 
793 /**
794  * Return length of UNICODE string.
795  * @param str UNICODE string
796  * @result length of string in characters
797  */
798 
799 static int
uc_strlen(SQLWCHAR * str)800 uc_strlen(SQLWCHAR *str)
801 {
802     int len = 0;
803 
804     if (str) {
805 	while (*str) {
806 	    ++len;
807 	    ++str;
808 	}
809     }
810     return len;
811 }
812 
813 /**
814  * Copy UNICODE string like strncpy().
815  * @param dest destination area
816  * @param src source area
817  * @param len length of source area in characters
818  * @return pointer to destination area
819  */
820 
821 static SQLWCHAR *
uc_strncpy(SQLWCHAR * dest,SQLWCHAR * src,int len)822 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
823 {
824     int i = 0;
825 
826     while (i < len) {
827 	if (!src[i]) {
828 	    break;
829 	}
830 	dest[i] = src[i];
831 	++i;
832     }
833     if (i < len) {
834 	dest[i] = 0;
835     }
836     return dest;
837 }
838 
839 /**
840  * Make UNICODE string from UTF8 string into buffer.
841  * @param str UTF8 string to be converted
842  * @param len length in characters of str or -1
843  * @param uc destination area to receive UNICODE string
844  * @param ucLen byte length of destination area
845  */
846 
847 static void
uc_from_utf_buf(unsigned char * str,int len,SQLWCHAR * uc,int ucLen)848 uc_from_utf_buf(unsigned char *str, int len, SQLWCHAR *uc, int ucLen)
849 {
850     ucLen = ucLen / sizeof (SQLWCHAR);
851     if (!uc || ucLen < 0) {
852 	return;
853     }
854     if (len < 0) {
855 	len = ucLen * 5;
856     }
857     uc[0] = 0;
858     if (str) {
859 	int i = 0;
860 
861 	while (i < len && *str && i < ucLen) {
862 	    unsigned char c = str[0];
863 
864 	    if (c < 0x80) {
865 		uc[i++] = c;
866 		++str;
867 	    } else if (c <= 0xc1 || c >= 0xf5) {
868 		/* illegal, ignored */
869 		++str;
870 	    } else if (c < 0xe0) {
871 		if ((str[1] & 0xc0) == 0x80) {
872 		    unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
873 
874 		    uc[i++] = t;
875 		    str += 2;
876 		} else {
877 		    uc[i++] = c;
878 		    ++str;
879 		}
880 	    } else if (c < 0xf0) {
881 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
882 		    unsigned long t = ((c & 0x0f) << 12) |
883 			((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
884 
885 		    uc[i++] = t;
886 		    str += 3;
887 		} else {
888 		    uc[i++] = c;
889 		    ++str;
890 		}
891 	    } else if (c < 0xf8) {
892 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
893 		    (str[3] & 0xc0) == 0x80) {
894 		    unsigned long t = ((c & 0x03) << 18) |
895 			((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
896 			(str[3] & 0x3f);
897 
898 		    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
899 			t >= 0x10000) {
900 			t -= 0x10000;
901 			uc[i++] = 0xd800 | ((t >> 10) & 0x3ff);
902 			if (i >= ucLen) {
903 			    break;
904 			}
905 			t = 0xdc00 | (t & 0x3ff);
906 		    }
907 		    uc[i++] = t;
908 		    str += 4;
909 		} else {
910 		    uc[i++] = c;
911 		    ++str;
912 		}
913 	    } else {
914 		/* ignore */
915 		++str;
916 	    }
917 	}
918 	if (i < ucLen) {
919 	    uc[i] = 0;
920 	}
921     }
922 }
923 
924 /**
925  * Make UNICODE string from UTF8 string.
926  * @param str UTF8 string to be converted
927  * @param len length of UTF8 string
928  * @return alloc'ed UNICODE string to be free'd by uc_free()
929  */
930 
931 static SQLWCHAR *
uc_from_utf(unsigned char * str,int len)932 uc_from_utf(unsigned char *str, int len)
933 {
934     SQLWCHAR *uc = NULL;
935     int ucLen;
936 
937     if (str) {
938 	if (len == SQL_NTS) {
939 	    len = strlen((char *) str);
940 	}
941 	ucLen = sizeof (SQLWCHAR) * (len + 1);
942 	uc = xmalloc(ucLen);
943 	if (uc) {
944 	    uc_from_utf_buf(str, len, uc, ucLen);
945 	}
946     }
947     return uc;
948 }
949 
950 /**
951  * Make UTF8 string from UNICODE string.
952  * @param str UNICODE string to be converted
953  * @param len length of UNICODE string in bytes
954  * @return alloc'ed UTF8 string to be free'd by uc_free()
955  */
956 
957 static char *
uc_to_utf(SQLWCHAR * str,int len)958 uc_to_utf(SQLWCHAR *str, int len)
959 {
960     int i;
961     char *cp, *ret = NULL;
962 
963     if (!str) {
964 	return ret;
965     }
966     if (len == SQL_NTS) {
967 	len = uc_strlen(str);
968     } else {
969 	len = len / sizeof (SQLWCHAR);
970     }
971     cp = xmalloc(len * 6 + 1);
972     if (!cp) {
973 	return ret;
974     }
975     ret = cp;
976     for (i = 0; i < len; i++) {
977 	unsigned long c = str[i];
978 
979 	if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
980 	    c &= 0xffff;
981 	}
982 	if (c < 0x80) {
983 	    *cp++ = c;
984 	} else if (c < 0x800) {
985 	    *cp++ = 0xc0 | ((c >> 6) & 0x1f);
986 	    *cp++ = 0x80 | (c & 0x3f);
987 	} else if (c < 0x10000) {
988 	    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
989 		c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
990 		unsigned long c2 = str[i + 1] & 0xffff;
991 
992 		if (c2 >= 0xdc00 && c2 <= 0xdfff) {
993 		    c = (((c & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10000;
994 		    *cp++ = 0xf0 | ((c >> 18) & 0x07);
995 		    *cp++ = 0x80 | ((c >> 12) & 0x3f);
996 		    *cp++ = 0x80 | ((c >> 6) & 0x3f);
997 		    *cp++ = 0x80 | (c & 0x3f);
998 		    ++i;
999 		    continue;
1000 		}
1001 	    }
1002 	    *cp++ = 0xe0 | ((c >> 12) & 0x0f);
1003 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
1004 	    *cp++ = 0x80 | (c & 0x3f);
1005 	} else if (c <= 0x10ffff) {
1006 	    *cp++ = 0xf0 | ((c >> 18) & 0x07);
1007 	    *cp++ = 0x80 | ((c >> 12) & 0x3f);
1008 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
1009 	    *cp++ = 0x80 | (c & 0x3f);
1010 	}
1011     }
1012     *cp = '\0';
1013     return ret;
1014 }
1015 
1016 #endif
1017 
1018 #ifdef WINTERFACE
1019 
1020 /**
1021  * Make UTF8 string from UNICODE string.
1022  * @param str UNICODE string to be converted
1023  * @param len length of UNICODE string in characters
1024  * @return alloc'ed UTF8 string to be free'd by uc_free()
1025  */
1026 
1027 static char *
uc_to_utf_c(SQLWCHAR * str,int len)1028 uc_to_utf_c(SQLWCHAR *str, int len)
1029 {
1030     if (len != SQL_NTS) {
1031 	len = len * sizeof (SQLWCHAR);
1032     }
1033     return uc_to_utf(str, len);
1034 }
1035 
1036 #endif
1037 
1038 #if defined(WCHARSUPPORT) || defined(_WIN32) || defined(_WIN64)
1039 
1040 /**
1041  * Free converted UTF8 or UNICODE string.
1042  * @param str string to be free'd
1043  */
1044 
1045 static void
uc_free(void * str)1046 uc_free(void *str)
1047 {
1048     if (str) {
1049 	xfree(str);
1050     }
1051 }
1052 
1053 #endif
1054 
1055 #if defined(_WIN32) || defined(_WIN64)
1056 
1057 /**
1058  * Convert multibyte, current code page string to UTF8 string,
1059  * @param str multibyte string to be converted
1060  * @param len length of multibyte string
1061  * @return alloc'ed UTF8 string to be free'd by uc_free()
1062  */
1063 
1064 static char *
wmb_to_utf(char * str,int len)1065 wmb_to_utf(char *str, int len)
1066 {
1067     WCHAR *wstr;
1068     OSVERSIONINFO ovi;
1069     int nchar, is2k, cp = CP_OEMCP;
1070 
1071     ovi.dwOSVersionInfoSize = sizeof (ovi);
1072     GetVersionEx(&ovi);
1073     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1074     if (AreFileApisANSI()) {
1075 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1076     }
1077     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
1078     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1079     if (!wstr) {
1080 	return NULL;
1081     }
1082     wstr[0] = 0;
1083     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
1084     wstr[nchar] = 0;
1085     str = xmalloc((nchar + 1) * 7);
1086     if (!str) {
1087 	xfree(wstr);
1088 	return NULL;
1089     }
1090     str[0] = '\0';
1091     nchar = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, nchar * 7, 0, 0);
1092     str[nchar] = '\0';
1093     xfree(wstr);
1094     return str;
1095 }
1096 
1097 #ifndef WINTERFACE
1098 
1099 /**
1100  * Convert multibyte, current code page string to UTF8 string,
1101  * @param str multibyte string to be converted
1102  * @param len length of multibyte string
1103  * @return alloc'ed UTF8 string to be free'd by uc_free()
1104  */
1105 
1106 static char *
wmb_to_utf_c(char * str,int len)1107 wmb_to_utf_c(char *str, int len)
1108 {
1109     if (len == SQL_NTS) {
1110 	len = strlen(str);
1111     }
1112     return wmb_to_utf(str, len);
1113 }
1114 
1115 #endif
1116 
1117 /**
1118  * Convert UTF8 string to multibyte, current code page string,
1119  * @param str UTF8 string to be converted
1120  * @param len length of UTF8 string
1121  * @return alloc'ed multibyte string to be free'd by uc_free()
1122  */
1123 
1124 static char *
utf_to_wmb(char * str,int len)1125 utf_to_wmb(char *str, int len)
1126 {
1127     WCHAR *wstr;
1128     OSVERSIONINFO ovi;
1129     int nchar, is2k, cp = CP_OEMCP;
1130 
1131     ovi.dwOSVersionInfoSize = sizeof (ovi);
1132     GetVersionEx(&ovi);
1133     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1134     if (AreFileApisANSI()) {
1135 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1136     }
1137     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
1138     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1139     if (!wstr) {
1140 	return NULL;
1141     }
1142     wstr[0] = 0;
1143     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, nchar);
1144     wstr[nchar] = 0;
1145     str = xmalloc((nchar + 1) * 7);
1146     if (!str) {
1147 	xfree(wstr);
1148 	return NULL;
1149     }
1150     str[0] = '\0';
1151     nchar = WideCharToMultiByte(cp, 0, wstr, -1, str, nchar * 7, 0, 0);
1152     str[nchar] = '\0';
1153     xfree(wstr);
1154     return str;
1155 }
1156 
1157 #ifdef WINTERFACE
1158 
1159 /**
1160  * Convert multibyte, current code page string to UNICODE string,
1161  * @param str multibyte string to be converted
1162  * @param len length of multibyte string
1163  * @return alloc'ed UNICODE string to be free'd by uc_free()
1164  */
1165 
1166 static WCHAR *
wmb_to_uc(char * str,int len)1167 wmb_to_uc(char *str, int len)
1168 {
1169     WCHAR *wstr;
1170     OSVERSIONINFO ovi;
1171     int nchar, is2k, cp = CP_OEMCP;
1172 
1173     ovi.dwOSVersionInfoSize = sizeof (ovi);
1174     GetVersionEx(&ovi);
1175     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1176     if (AreFileApisANSI()) {
1177 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1178     }
1179     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
1180     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1181     if (!wstr) {
1182 	return NULL;
1183     }
1184     wstr[0] = 0;
1185     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
1186     wstr[nchar] = 0;
1187     return wstr;
1188 }
1189 
1190 /**
1191  * Convert UNICODE string to multibyte, current code page string,
1192  * @param str UNICODE string to be converted
1193  * @param len length of UNICODE string
1194  * @return alloc'ed multibyte string to be free'd by uc_free()
1195  */
1196 
1197 static char *
uc_to_wmb(WCHAR * wstr,int len)1198 uc_to_wmb(WCHAR *wstr, int len)
1199 {
1200     char *str;
1201     OSVERSIONINFO ovi;
1202     int nchar, is2k, cp = CP_OEMCP;
1203 
1204     ovi.dwOSVersionInfoSize = sizeof (ovi);
1205     GetVersionEx(&ovi);
1206     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1207     if (AreFileApisANSI()) {
1208 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1209     }
1210     nchar = WideCharToMultiByte(cp, 0, wstr, len, NULL, 0, 0, 0);
1211     str = xmalloc((nchar + 1) * 2);
1212     if (!str) {
1213 	return NULL;
1214     }
1215     str[0] = '\0';
1216     nchar = WideCharToMultiByte(cp, 0, wstr, len, str, nchar * 2, 0, 0);
1217     str[nchar] = '\0';
1218     return str;
1219 }
1220 
1221 #endif /* WINTERFACE */
1222 
1223 #endif /* _WIN32 || _WIN64 */
1224 
1225 
1226 #ifdef USE_DLOPEN_FOR_GPPS
1227 
1228 #include <dlfcn.h>
1229 
1230 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
1231 
1232 /*
1233  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
1234  * dlopen(), in theory this makes the driver independent from the
1235  * driver manager, i.e. the same driver binary can run with iODBC
1236  * and unixODBC.
1237  */
1238 
1239 static void
drvgetgpps(DBC * d)1240 drvgetgpps(DBC *d)
1241 {
1242     void *lib;
1243     int (*gpps)();
1244 
1245     lib = dlopen("libodbcinst.so.2", RTLD_LAZY);
1246     if (!lib) {
1247 	lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
1248     }
1249     if (!lib) {
1250 	lib = dlopen("libodbcinst.so", RTLD_LAZY);
1251     }
1252     if (!lib) {
1253 	lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
1254     }
1255     if (!lib) {
1256 	lib = dlopen("libiodbcinst.so", RTLD_LAZY);
1257     }
1258     if (lib) {
1259 	gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
1260 	if (!gpps) {
1261 	    dlclose(lib);
1262 	    return;
1263 	}
1264 	d->instlib = lib;
1265 	d->gpps = gpps;
1266     }
1267 }
1268 
1269 static void
drvrelgpps(DBC * d)1270 drvrelgpps(DBC *d)
1271 {
1272     if (d->instlib) {
1273 	dlclose(d->instlib);
1274 	d->instlib = 0;
1275     }
1276 }
1277 
1278 static int
drvgpps(DBC * d,char * sect,char * ent,char * def,char * buf,int bufsiz,char * fname)1279 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
1280 	int bufsiz, char *fname)
1281 {
1282     if (d->gpps) {
1283 	return d->gpps(sect, ent, def, buf, bufsiz, fname);
1284     }
1285     strncpy(buf, def, bufsiz);
1286     buf[bufsiz - 1] = '\0';
1287     return 1;
1288 }
1289 #else
1290 #include <odbcinst.h>
1291 #define drvgetgpps(d)
1292 #define drvrelgpps(d)
1293 #endif
1294 
1295 /*
1296  * Internal function to bind SQLite3 parameters.
1297  */
1298 
1299 static void
s3bind(DBC * d,sqlite3_stmt * stmt,int nparams,BINDPARM * p)1300 s3bind(DBC *d, sqlite3_stmt *stmt, int nparams, BINDPARM *p)
1301 {
1302     int i;
1303 
1304     if (stmt && p && nparams > 0) {
1305 	for (i = 0; i < nparams; i++, p++) {
1306 	    switch (p->s3type) {
1307 	    default:
1308 	    case SQLITE_NULL:
1309 		sqlite3_bind_null(stmt, i + 1);
1310 		if (d->trace) {
1311 		    fprintf(d->trace, "-- parameter %d: NULL\n", i + 1);
1312 		    fflush(d->trace);
1313 		}
1314 		break;
1315 	    case SQLITE_TEXT:
1316 		sqlite3_bind_text(stmt, i + 1, p->s3val, p->s3size,
1317 				  SQLITE_STATIC);
1318 		if (d->trace) {
1319 		    fprintf(d->trace, "-- parameter %d: '%*s'\n", i + 1,
1320 			    p->s3size, (char *) p->s3val);
1321 		    fflush(d->trace);
1322 		}
1323 		break;
1324 	    case SQLITE_BLOB:
1325 		sqlite3_bind_blob(stmt, i + 1, p->s3val, p->s3size,
1326 				  SQLITE_STATIC);
1327 		if (d->trace) {
1328 		    fprintf(d->trace, "-- parameter %d: [BLOB]'\n", i + 1);
1329 		    fflush(d->trace);
1330 		}
1331 		break;
1332 	    case SQLITE_FLOAT:
1333 		sqlite3_bind_double(stmt, i + 1, p->s3dval);
1334 		if (d->trace) {
1335 		    fprintf(d->trace, "-- parameter %d: %g\n",
1336 			    i + 1, p->s3dval);
1337 		    fflush(d->trace);
1338 		}
1339 		break;
1340 	    case SQLITE_INTEGER:
1341 		if (p->s3size > sizeof (int)) {
1342 		    sqlite3_bind_int64(stmt, i + 1, p->s3lival);
1343 		    if (d->trace) {
1344 			fprintf(d->trace,
1345 #ifdef _WIN32
1346 				"-- parameter %d: %I64d\n",
1347 #else
1348 				"-- parameter %d: %lld\n",
1349 #endif
1350 				i + 1, p->s3lival);
1351 			fflush(d->trace);
1352 		    }
1353 		} else {
1354 		    sqlite3_bind_int(stmt, i + 1, p->s3ival);
1355 		    if (d->trace) {
1356 			fprintf(d->trace, "-- parameter %d: %d\n",
1357 				i + 1, p->s3ival);
1358 			fflush(d->trace);
1359 		    }
1360 		}
1361 		break;
1362 	    }
1363 	}
1364     }
1365 }
1366 
1367 /**
1368  * @typedef TBLRES
1369  * @struct tblres
1370  * Internal structure for managing driver's
1371  * sqlite3_get_table() implementation.
1372  */
1373 
1374 typedef struct tblres {
1375     char **resarr;	/**< result array */
1376     char *errmsg;	/**< error message or NULL */
1377     sqlite3_stmt *stmt;	/**< SQLite3 statement pointer */
1378     STMT *s;		/**< Driver statement pointer */
1379     int nalloc;		/**< alloc'ed size of result array */
1380     int nrow;		/**< number of rows in result array */
1381     int ncol;		/**< number of columns in result array */
1382     PTRDIFF_T ndata;	/**< index into result array */
1383     int rc;		/**< SQLite return code */
1384 } TBLRES;
1385 
1386 /*
1387  * Driver's version of sqlite3_get_table() and friends which are
1388  * capable of dealing with blobs.
1389  */
1390 
1391 static int
drvgettable_row(TBLRES * t,int ncol,int rc)1392 drvgettable_row(TBLRES *t, int ncol, int rc)
1393 {
1394     int need;
1395     int i;
1396     char *p;
1397 
1398     if (t->nrow == 0 && rc == SQLITE_ROW) {
1399 	need = ncol * 2;
1400     } else {
1401 	need = ncol;
1402     }
1403     if (t->ndata + need >= t->nalloc) {
1404 	char **resnew;
1405 	int nalloc = t->nalloc * 2 + need + 1;
1406 
1407 	resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
1408 	if (!resnew) {
1409 nomem:
1410 	    t->rc = SQLITE_NOMEM;
1411 	    return 1;
1412 	}
1413 	t->nalloc = nalloc;
1414 	t->resarr = resnew;
1415     }
1416     /* column names when first row */
1417     if (t->nrow == 0) {
1418 	t->ncol = ncol;
1419 	for (i = 0; i < ncol; i++) {
1420 	    p = (char *) sqlite3_column_name(t->stmt, i);
1421 	    if (p) {
1422 		char *q = xmalloc(strlen(p) + 1);
1423 
1424 		if (!q) {
1425 		    goto nomem;
1426 		}
1427 		strcpy(q, p);
1428 		p = q;
1429 	    }
1430 	    t->resarr[t->ndata++] = p;
1431 	}
1432 	if (t->s && t->s->guessed_types) {
1433 	    int ncol2 = ncol;
1434 
1435 	    setupdyncols(t->s, t->stmt, &ncol2);
1436 	    t->s->guessed_types = 0;
1437 	    t->s->ncols = ncol;
1438 	}
1439     } else if (t->ncol != ncol) {
1440 	t->errmsg = sqlite3_mprintf("drvgettable() called with two or"
1441 				    " more incompatible queries");
1442 	t->rc = SQLITE_ERROR;
1443 	return 1;
1444     }
1445     /* copy row data */
1446     if (rc == SQLITE_ROW) {
1447 	for (i = 0; i < ncol; i++) {
1448 	    int coltype = sqlite3_column_type(t->stmt, i);
1449 
1450 	    p = NULL;
1451 	    if (coltype == SQLITE_BLOB) {
1452 		int k, nbytes = sqlite3_column_bytes(t->stmt, i);
1453 		char *qp;
1454 		unsigned const char *bp;
1455 
1456 		bp = sqlite3_column_blob(t->stmt, i);
1457 		qp = xmalloc(nbytes * 2 + 4);
1458 		if (!qp) {
1459 		    goto nomem;
1460 		}
1461 		p = qp;
1462 		*qp++ = 'X';
1463 		*qp++ = '\'';
1464 		for (k = 0; k < nbytes; k++) {
1465 		    *qp++ = xdigits[(bp[k] >> 4)];
1466 		    *qp++ = xdigits[(bp[k] & 0xF)];
1467 		}
1468 		*qp++ = '\'';
1469 		*qp = '\0';
1470 #ifdef _MSC_VER
1471 	    } else if (coltype == SQLITE_FLOAT) {
1472 		struct lconv *lc = 0;
1473 		double val = sqlite3_column_double(t->stmt, i);
1474 		char buffer[128];
1475 
1476 		/*
1477 		 * This avoids floating point rounding
1478 		 * and formatting problems of some SQLite
1479 		 * versions in conjunction with MSVC 2010.
1480 		 */
1481 		snprintf(buffer, sizeof (buffer), "%.15g", val);
1482 		lc = localeconv();
1483 		if (lc && lc->decimal_point && lc->decimal_point[0] &&
1484 		    lc->decimal_point[0] != '.') {
1485 		    p = strchr(buffer, lc->decimal_point[0]);
1486 		    if (p) {
1487 			*p = '.';
1488 		    }
1489 		}
1490 		p = xstrdup(buffer);
1491 		if (!p) {
1492 		    goto nomem;
1493 		}
1494 #endif
1495 	    } else if (coltype != SQLITE_NULL) {
1496 		p = xstrdup((char *) sqlite3_column_text(t->stmt, i));
1497 		if (!p) {
1498 		    goto nomem;
1499 		}
1500 	    }
1501 	    t->resarr[t->ndata++] = p;
1502 	}
1503 	t->nrow++;
1504     }
1505     return 0;
1506 }
1507 
1508 static int
drvgettable(STMT * s,const char * sql,char *** resp,int * nrowp,int * ncolp,char ** errp,int nparam,BINDPARM * p)1509 drvgettable(STMT *s, const char *sql, char ***resp, int *nrowp,
1510 	    int *ncolp, char **errp, int nparam, BINDPARM *p)
1511 {
1512     DBC *d = (DBC *) s->dbc;
1513     int rc = SQLITE_OK, keep = sql == NULL;
1514     TBLRES tres;
1515     const char *sqlleft = 0;
1516     int nretry = 0, haveerr = 0;
1517 
1518     if (!resp) {
1519 	return SQLITE_ERROR;
1520     }
1521     *resp = NULL;
1522     if (nrowp) {
1523 	*nrowp = 0;
1524     }
1525     if (ncolp) {
1526 	*ncolp = 0;
1527     }
1528     tres.errmsg = NULL;
1529     tres.nrow = 0;
1530     tres.ncol = 0;
1531     tres.ndata = 1;
1532     tres.nalloc = 20;
1533     tres.rc = SQLITE_OK;
1534     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
1535     tres.stmt = NULL;
1536     tres.s = s;
1537     if (!tres.resarr) {
1538 	return SQLITE_NOMEM;
1539     }
1540     tres.resarr[0] = 0;
1541     if (sql == NULL) {
1542 	tres.stmt = s->s3stmt;
1543 	if (tres.stmt == NULL) {
1544 	    return SQLITE_NOMEM;
1545 	}
1546 	goto retrieve;
1547     }
1548     while (sql && *sql && (rc == SQLITE_OK ||
1549 			   (rc == SQLITE_SCHEMA && (++nretry) < 2))) {
1550 	int ncol;
1551 
1552 	tres.stmt = NULL;
1553 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
1554 	dbtraceapi(d, "sqlite3_prepare_v2", sql);
1555 	rc = sqlite3_prepare_v2(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
1556 #else
1557 	dbtraceapi(d, "sqlite3_prepare", sql);
1558 	rc = sqlite3_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
1559 #endif
1560 	if (rc != SQLITE_OK) {
1561 	    if (tres.stmt) {
1562 		dbtraceapi(d, "sqlite3_finalize", 0);
1563 		sqlite3_finalize(tres.stmt);
1564 		tres.stmt = NULL;
1565 	    }
1566 	    continue;
1567 	}
1568 	if (!tres.stmt) {
1569 	    /* this happens for a comment or white-space */
1570 	    sql = sqlleft;
1571 	    continue;
1572 	}
1573 retrieve:
1574 	if (sqlite3_bind_parameter_count(tres.stmt) != nparam) {
1575 	    if (errp) {
1576 		*errp =
1577 		    sqlite3_mprintf("%s", "parameter marker count incorrect");
1578 	    }
1579 	    haveerr = 1;
1580 	    rc = SQLITE_ERROR;
1581 	    goto tbldone;
1582 	}
1583 	s3bind(d, tres.stmt, nparam, p);
1584 	ncol = sqlite3_column_count(tres.stmt);
1585 	while (1) {
1586 	    if (s->max_rows && tres.nrow >= s->max_rows) {
1587 		rc = SQLITE_OK;
1588 		break;
1589 	    }
1590 	    rc = sqlite3_step(tres.stmt);
1591 	    if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
1592 		if (drvgettable_row(&tres, ncol, rc)) {
1593 		    rc = SQLITE_ABORT;
1594 		    goto tbldone;
1595 		}
1596 	    }
1597 	    if (rc != SQLITE_ROW) {
1598 		if (keep) {
1599 		    dbtraceapi(d, "sqlite3_reset", 0);
1600 		    rc = sqlite3_reset(tres.stmt);
1601 		    s->s3stmt_noreset = 1;
1602 		} else {
1603 		    dbtraceapi(d, "sqlite3_finalize", 0);
1604 		    rc = sqlite3_finalize(tres.stmt);
1605 		}
1606 		tres.stmt = 0;
1607 		if (rc != SQLITE_SCHEMA) {
1608 		    nretry = 0;
1609 		    sql = sqlleft;
1610 		    while (sql && ISSPACE(*sql)) {
1611 			sql++;
1612 		    }
1613 		}
1614 		if (rc == SQLITE_DONE) {
1615 		    rc = SQLITE_OK;
1616 		}
1617 		break;
1618 	    }
1619 	}
1620     }
1621 tbldone:
1622     if (tres.stmt) {
1623 	if (keep) {
1624 	    if (!s->s3stmt_noreset) {
1625 		dbtraceapi(d, "sqlite3_reset", 0);
1626 		sqlite3_reset(tres.stmt);
1627 		s->s3stmt_noreset = 1;
1628 	    }
1629 	} else {
1630 	    dbtraceapi(d, "sqlite3_finalize", 0);
1631 	    sqlite3_finalize(tres.stmt);
1632 	}
1633     }
1634     if (haveerr) {
1635 	/* message already in *errp if any */
1636     } else if (rc != SQLITE_OK && rc == sqlite3_errcode(d->sqlite) && errp) {
1637 	*errp = sqlite3_mprintf("%s", sqlite3_errmsg(d->sqlite));
1638     } else if (errp) {
1639 	*errp = NULL;
1640     }
1641     if (tres.resarr) {
1642 	tres.resarr[0] = (char *) (tres.ndata - 1);
1643     }
1644     if (rc == SQLITE_ABORT) {
1645 	freerows(&tres.resarr[1]);
1646 	if (tres.errmsg) {
1647 	    if (errp) {
1648 		if (*errp) {
1649 		    sqlite3_free(*errp);
1650 		}
1651 		*errp = tres.errmsg;
1652 	    } else {
1653 		sqlite3_free(tres.errmsg);
1654 	    }
1655 	}
1656 	return tres.rc;
1657     }
1658     sqlite3_free(tres.errmsg);
1659     if (rc != SQLITE_OK) {
1660 	freerows(&tres.resarr[1]);
1661 	return rc;
1662     }
1663     *resp = &tres.resarr[1];
1664     if (ncolp) {
1665 	*ncolp = tres.ncol;
1666     }
1667     if (nrowp) {
1668 	*nrowp = tres.nrow;
1669     }
1670     return rc;
1671 }
1672 
1673 /**
1674  * Set error message and SQL state on DBC
1675  * @param d database connection pointer
1676  * @param naterr native error code
1677  * @param msg error message
1678  * @param st SQL state
1679  */
1680 
1681 #if defined(__GNUC__) && (__GNUC__ >= 2)
1682 static void setstatd(DBC *, int, char *, char *, ...)
1683     __attribute__((format (printf, 3, 5)));
1684 #endif
1685 
1686 static void
setstatd(DBC * d,int naterr,char * msg,char * st,...)1687 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
1688 {
1689     va_list ap;
1690 
1691     if (!d) {
1692 	return;
1693     }
1694     d->naterr = naterr;
1695     d->logmsg[0] = '\0';
1696     if (msg) {
1697 	int count;
1698 
1699 	va_start(ap, st);
1700 	count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
1701 	va_end(ap);
1702 	if (count < 0) {
1703 	    d->logmsg[sizeof (d->logmsg) - 1] = '\0';
1704 	}
1705     }
1706     if (!st) {
1707 	st = "?????";
1708     }
1709     strncpy(d->sqlstate, st, 5);
1710     d->sqlstate[5] = '\0';
1711 }
1712 
1713 /**
1714  * Set error message and SQL state on statement
1715  * @param s statement pointer
1716  * @param naterr native error code
1717  * @param msg error message
1718  * @param st SQL state
1719  */
1720 
1721 #if defined(__GNUC__) && (__GNUC__ >= 2)
1722 static void setstat(STMT *, int, char *, char *, ...)
1723     __attribute__((format (printf, 3, 5)));
1724 #endif
1725 
1726 static void
setstat(STMT * s,int naterr,char * msg,char * st,...)1727 setstat(STMT *s, int naterr, char *msg, char *st, ...)
1728 {
1729     va_list ap;
1730 
1731     if (!s) {
1732 	return;
1733     }
1734     s->naterr = naterr;
1735     s->logmsg[0] = '\0';
1736     if (msg) {
1737 	int count;
1738 
1739 	va_start(ap, st);
1740 	count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
1741 	va_end(ap);
1742 	if (count < 0) {
1743 	    s->logmsg[sizeof (s->logmsg) - 1] = '\0';
1744 	}
1745     }
1746     if (!st) {
1747 	st = "?????";
1748     }
1749     strncpy(s->sqlstate, st, 5);
1750     s->sqlstate[5] = '\0';
1751 }
1752 
1753 /**
1754  * Report IM001 (not implemented) SQL error code for HDBC.
1755  * @param dbc database connection handle
1756  * @result ODBC error code
1757  */
1758 
1759 static SQLRETURN
drvunimpldbc(HDBC dbc)1760 drvunimpldbc(HDBC dbc)
1761 {
1762     DBC *d;
1763 
1764     if (dbc == SQL_NULL_HDBC) {
1765 	return SQL_INVALID_HANDLE;
1766     }
1767     d = (DBC *) dbc;
1768     setstatd(d, -1, "not supported", "IM001");
1769     return SQL_ERROR;
1770 }
1771 
1772 /**
1773  * Report IM001 (not implemented) SQL error code for HSTMT.
1774  * @param stmt statement handle
1775  * @result ODBC error code
1776  */
1777 
1778 static SQLRETURN
drvunimplstmt(HSTMT stmt)1779 drvunimplstmt(HSTMT stmt)
1780 {
1781     STMT *s;
1782 
1783     if (stmt == SQL_NULL_HSTMT) {
1784 	return SQL_INVALID_HANDLE;
1785     }
1786     s = (STMT *) stmt;
1787     setstat(s, -1, "not supported", "IM001");
1788     return SQL_ERROR;
1789 }
1790 
1791 /**
1792  * Free memory given pointer to memory pointer.
1793  * @param x pointer to pointer to memory to be free'd
1794  */
1795 
1796 static void
freep(void * x)1797 freep(void *x)
1798 {
1799     if (x && ((char **) x)[0]) {
1800 	xfree(((char **) x)[0]);
1801 	((char **) x)[0] = NULL;
1802     }
1803 }
1804 
1805 /**
1806  * Report S1000 (out of memory) SQL error given STMT.
1807  * @param s statement pointer
1808  * @result ODBC error code
1809  */
1810 
1811 static SQLRETURN
nomem(STMT * s)1812 nomem(STMT *s)
1813 {
1814     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
1815     return SQL_ERROR;
1816 }
1817 
1818 /**
1819  * Report S1000 (not connected) SQL error given STMT.
1820  * @param s statement pointer
1821  * @result ODBC error code
1822  */
1823 
1824 static SQLRETURN
noconn(STMT * s)1825 noconn(STMT *s)
1826 {
1827     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
1828     return SQL_ERROR;
1829 }
1830 
1831 /**
1832  * Internal locale neutral strtod function.
1833  * @param data pointer to string
1834  * @param endp pointer for ending character
1835  * @result double value
1836  */
1837 
1838 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
1839 
1840 static double
ln_strtod(const char * data,char ** endp)1841 ln_strtod(const char *data, char **endp)
1842 {
1843     struct lconv *lc = 0;
1844     char buf[128], *p, *end;
1845     double value;
1846 
1847     lc = localeconv();
1848     if (lc && lc->decimal_point && lc->decimal_point[0] &&
1849 	lc->decimal_point[0] != '.') {
1850 	strncpy(buf, data, sizeof (buf) - 1);
1851 	buf[sizeof (buf) - 1] = '\0';
1852 	p = strchr(buf, '.');
1853 	if (p) {
1854 	    *p = lc->decimal_point[0];
1855 	}
1856 	p = buf;
1857     } else {
1858 	p = (char *) data;
1859     }
1860     value = strtod(p, &end);
1861     end = (char *) data + (end - p);
1862     if (endp) {
1863 	*endp = end;
1864     }
1865     return value;
1866 }
1867 
1868 #else
1869 
1870 #define ln_strtod(A,B) strtod(A,B)
1871 
1872 #endif
1873 
1874 /**
1875  * Strip quotes from quoted string in-place.
1876  * @param str string
1877  */
1878 
1879 static char *
unquote(char * str)1880 unquote(char *str)
1881 {
1882     if (str) {
1883 	int len = strlen(str);
1884 
1885 	if (len > 1) {
1886 	    int end = len - 1;
1887 
1888 	    if ((str[0] == '\'' && str[end] == '\'') ||
1889 		(str[0] == '"' && str[end] == '"') ||
1890 		(str[0] == '[' && str[end] == ']')) {
1891 		memmove(str, str + 1, end - 1);
1892 		str[end - 1] = '\0';
1893 	    }
1894 	}
1895     }
1896     return str;
1897 }
1898 
1899 /**
1900  * Unescape search pattern for e.g. table name in
1901  * catalog functions. Replacements in string are done in-place.
1902  * @param str string
1903  * @result number of pattern characters in string or 0
1904  */
1905 
1906 static int
unescpat(char * str)1907 unescpat(char *str)
1908 {
1909     char *p, *q;
1910     int count = 0;
1911 
1912     p = str;
1913     while ((q = strchr(p, '_')) != NULL) {
1914 	if (q == str || q[-1] != '\\') {
1915 	    count++;
1916 	}
1917 	p = q + 1;
1918     }
1919     p = str;
1920     while ((q = strchr(p, '%')) != NULL) {
1921 	if (q == str || q[-1] != '\\') {
1922 	    count++;
1923 	}
1924 	p = q + 1;
1925     }
1926     p = str;
1927     while ((q = strchr(p, '\\')) != NULL) {
1928 	if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
1929 	    memmove(q, q + 1, strlen(q));
1930 	}
1931 	p = q + 1;
1932     }
1933     return count;
1934 }
1935 
1936 /**
1937  * SQL LIKE string match with optional backslash escape handling.
1938  * @param str string
1939  * @param pat pattern
1940  * @param esc when true, treat literally "\\" as "\", "\%" as "%", "\_" as "_"
1941  * @result true when pattern matched
1942  */
1943 
1944 static int
namematch(char * str,char * pat,int esc)1945 namematch(char *str, char *pat, int esc)
1946 {
1947     int cp, ch;
1948 
1949     while (1) {
1950 	cp = TOLOWER(*pat);
1951 	if (cp == '\0') {
1952 	    if (*str != '\0') {
1953 		goto nomatch;
1954 	    }
1955 	    break;
1956 	}
1957 	if (*str == '\0' && cp != '%') {
1958 	    goto nomatch;
1959 	}
1960 	if (cp == '%') {
1961 	    while (*pat == '%') {
1962 		++pat;
1963 	    }
1964 	    cp = TOLOWER(*pat);
1965 	    if (cp == '\0') {
1966 		break;
1967 	    }
1968 	    while (1) {
1969 		if (cp != '_' && cp != '\\') {
1970 		    while (*str) {
1971 			ch = TOLOWER(*str);
1972 			if (ch == cp) {
1973 			    break;
1974 			}
1975 			++str;
1976 		    }
1977 		}
1978 		if (namematch(str, pat, esc)) {
1979 		    goto match;
1980 		}
1981 		if (*str == '\0') {
1982 		    goto nomatch;
1983 		}
1984 		ch = TOLOWER(*str);
1985 		++str;
1986 	    }
1987 	}
1988 	if (cp == '_') {
1989 	    pat++;
1990 	    str++;
1991 	    continue;
1992 	}
1993 	if (esc && cp == '\\' &&
1994 	    (pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
1995 	    ++pat;
1996 	    cp = TOLOWER(*pat);
1997 	}
1998 	ch = TOLOWER(*str++);
1999 	++pat;
2000 	if (ch != cp) {
2001 	    goto nomatch;
2002 	}
2003     }
2004 match:
2005     return 1;
2006 nomatch:
2007     return 0;
2008 }
2009 
2010 /**
2011  * Busy callback for SQLite.
2012  * @param udata user data, pointer to DBC
2013  * @param count count of subsequenct calls
2014  * @result true or false
2015  */
2016 
2017 static int
busy_handler(void * udata,int count)2018 busy_handler(void *udata, int count)
2019 {
2020     DBC *d = (DBC *) udata;
2021     long t1;
2022     int ret = 0;
2023 #if !defined(_WIN32) && !defined(_WIN64)
2024     struct timeval tv;
2025 #ifdef HAVE_NANOSLEEP
2026     struct timespec ts;
2027 #endif
2028 #endif
2029 
2030     if (d->busyint) {
2031 	d->busyint = 0;
2032 	return ret;
2033     }
2034     if (d->timeout <= 0) {
2035 	return ret;
2036     }
2037     if (count <= 1) {
2038 #if defined(_WIN32) || defined(_WIN64)
2039 	d->t0 = GetTickCount();
2040 #else
2041 	gettimeofday(&tv, NULL);
2042 	d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
2043 #endif
2044     }
2045 #if defined(_WIN32) || defined(_WIN64)
2046     t1 = GetTickCount();
2047 #else
2048     gettimeofday(&tv, NULL);
2049     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
2050 #endif
2051     if (t1 - d->t0 > d->timeout) {
2052 	goto done;
2053     }
2054 #if defined(_WIN32) || defined(_WIN64)
2055     Sleep(10);
2056 #else
2057 #ifdef HAVE_NANOSLEEP
2058     ts.tv_sec = 0;
2059     ts.tv_nsec = 10000000;
2060     do {
2061 	ret = nanosleep(&ts, &ts);
2062 	if (ret < 0 && errno != EINTR) {
2063 	    ret = 0;
2064 	}
2065     } while (ret);
2066 #else
2067 #ifdef HAVE_USLEEP
2068     usleep(10000);
2069 #else
2070     tv.tv_sec = 0;
2071     tv.tv_usec = 10000;
2072     select(0, NULL, NULL, NULL, &tv);
2073 #endif
2074 #endif
2075 #endif
2076     ret = 1;
2077 done:
2078     return ret;
2079 }
2080 
2081 /**
2082  * Set SQLite options (PRAGMAs) given SQLite handle.
2083  * @param x SQLite database handle
2084  * @param d DBC pointer
2085  * @result SQLite error code
2086  *
2087  * SQLite < 3.3.x and not shortnames DSN option:
2088  * "full_column_names" is always turned on and "short_column_names"
2089  * is always turned off, to get the table names in column labels.
2090  */
2091 
2092 static int
setsqliteopts(sqlite3 * x,DBC * d)2093 setsqliteopts(sqlite3 *x, DBC *d)
2094 {
2095     int count = 0, step = 0, max, rc = SQLITE_ERROR;
2096 
2097 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
2098     max = d->longnames ? 3 : 1;
2099 #else
2100     max = 3;
2101 #endif
2102     if (d->shortnames) {
2103 	max = 3;
2104     }
2105     while (step < max) {
2106 	if (step < 1) {
2107 	    rc = sqlite3_exec(x, "PRAGMA empty_result_callbacks = on;",
2108 			      NULL, NULL, NULL);
2109 	    if (rc == SQLITE_OK) {
2110 		rc = sqlite3_exec(x, d->fksupport ?
2111 				  "PRAGMA foreign_keys = on;" :
2112 				  "PRAGMA foreign_keys = off;",
2113 				  NULL, NULL, NULL);
2114 	    }
2115 	} else if (step < 2) {
2116 	    rc = sqlite3_exec(x, d->shortnames ?
2117 			      "PRAGMA full_column_names = off;" :
2118 			      "PRAGMA full_column_names = on;",
2119 			      NULL, NULL, NULL);
2120 	} else if (step < 3) {
2121 	    rc = sqlite3_exec(x, d->shortnames ?
2122 			      "PRAGMA short_column_names = on;" :
2123 			      "PRAGMA short_column_names = off;",
2124 			      NULL, NULL, NULL);
2125 	}
2126 	if (rc != SQLITE_OK) {
2127 	    if (rc != SQLITE_BUSY ||
2128 		!busy_handler((void *) d, ++count)) {
2129 		return rc;
2130 	    }
2131 	    continue;
2132 	}
2133 	count = 0;
2134 	++step;
2135     }
2136     sqlite3_busy_handler(x, busy_handler, (void *) d);
2137     return SQLITE_OK;
2138 }
2139 
2140 /**
2141  * Free counted array of char pointers.
2142  * @param rowp pointer to char pointer array
2143  *
2144  * The -1-th element of the array holds the array size.
2145  * All non-NULL pointers of the array and then the array
2146  * itself are free'd.
2147  */
2148 
2149 static void
freerows(char ** rowp)2150 freerows(char **rowp)
2151 {
2152     PTRDIFF_T size, i;
2153 
2154     if (!rowp) {
2155 	return;
2156     }
2157     --rowp;
2158     size = (PTRDIFF_T) rowp[0];
2159     for (i = 1; i <= size; i++) {
2160 	freep(&rowp[i]);
2161     }
2162     freep(&rowp);
2163 }
2164 
2165 /**
2166  * Map SQL field type from string to ODBC integer type code.
2167  * @param typename field type string
2168  * @param nosign pointer to indicator for unsigned field or NULL
2169  * @param ov3 boolean, true for SQL_OV_ODBC3
2170  * @param nowchar boolean, for WINTERFACE don't use WCHAR
2171  * @param dobigint boolean, force SQL_BIGINT on INTEGER columns
2172  * @result SQL data type
2173  */
2174 
2175 static int
mapsqltype(const char * typename,int * nosign,int ov3,int nowchar,int dobigint)2176 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar,
2177 	   int dobigint)
2178 {
2179     char *p, *q;
2180     int testsign = 0, result;
2181 
2182 #ifdef WINTERFACE
2183     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
2184 #else
2185     result = SQL_VARCHAR;
2186 #endif
2187     if (!typename) {
2188 	return result;
2189     }
2190     q = p = xmalloc(strlen(typename) + 1);
2191     if (!p) {
2192 	return result;
2193     }
2194     strcpy(p, typename);
2195     while (*q) {
2196 	*q = TOLOWER(*q);
2197 	++q;
2198     }
2199     if (strncmp(p, "inter", 5) == 0) {
2200     } else if (strncmp(p, "int", 3) == 0 ||
2201 	strncmp(p, "mediumint", 9) == 0) {
2202 	testsign = 1;
2203 	result = SQL_INTEGER;
2204     } else if (strncmp(p, "numeric", 7) == 0) {
2205 	result = SQL_DOUBLE;
2206     } else if (strncmp(p, "tinyint", 7) == 0) {
2207 	testsign = 1;
2208 	result = SQL_TINYINT;
2209     } else if (strncmp(p, "smallint", 8) == 0) {
2210 	testsign = 1;
2211 	result = SQL_SMALLINT;
2212     } else if (strncmp(p, "float", 5) == 0) {
2213 	result = SQL_DOUBLE;
2214     } else if (strncmp(p, "double", 6) == 0 ||
2215 	strncmp(p, "real", 4) == 0) {
2216 	result = SQL_DOUBLE;
2217     } else if (strncmp(p, "timestamp", 9) == 0) {
2218 #ifdef SQL_TYPE_TIMESTAMP
2219 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
2220 #else
2221 	result = SQL_TIMESTAMP;
2222 #endif
2223     } else if (strncmp(p, "datetime", 8) == 0) {
2224 #ifdef SQL_TYPE_TIMESTAMP
2225 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
2226 #else
2227 	result = SQL_TIMESTAMP;
2228 #endif
2229     } else if (strncmp(p, "time", 4) == 0) {
2230 #ifdef SQL_TYPE_TIME
2231 	result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
2232 #else
2233 	result = SQL_TIME;
2234 #endif
2235     } else if (strncmp(p, "date", 4) == 0) {
2236 #ifdef SQL_TYPE_DATE
2237 	result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
2238 #else
2239 	result = SQL_DATE;
2240 #endif
2241 #ifdef SQL_LONGVARCHAR
2242     } else if (strncmp(p, "text", 4) == 0 ||
2243 	       strncmp(p, "memo", 4) == 0 ||
2244 	       strncmp(p, "longvarchar", 11) == 0) {
2245 #ifdef WINTERFACE
2246 	result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
2247 #else
2248 	result = SQL_LONGVARCHAR;
2249 #endif
2250 #ifdef WINTERFACE
2251     } else if (strncmp(p, "wtext", 5) == 0 ||
2252 	       strncmp(p, "wvarchar", 8) == 0 ||
2253 	       strncmp(p, "longwvarchar", 12) == 0) {
2254 	result = SQL_WLONGVARCHAR;
2255 #endif
2256 #endif
2257 #ifdef SQL_BIT
2258     } else if (strncmp(p, "bool", 4) == 0 ||
2259 	       strncmp(p, "bit", 3) == 0) {
2260 	result = SQL_BIT;
2261 #endif
2262 #ifdef SQL_BIGINT
2263     } else if (strncmp(p, "bigint", 6) == 0) {
2264 	testsign = 1;
2265 	result = SQL_BIGINT;
2266 #endif
2267     } else if (strncmp(p, "blob", 4) == 0) {
2268 	result = SQL_BINARY;
2269     } else if (strncmp(p, "varbinary", 9) == 0) {
2270 	result = SQL_VARBINARY;
2271     } else if (strncmp(p, "longvarbinary", 13) == 0) {
2272 	result = SQL_LONGVARBINARY;
2273     }
2274     if (nosign) {
2275 	if (testsign) {
2276 	    *nosign = strstr(p, "unsigned") != NULL;
2277 	} else {
2278 	    *nosign = 1;
2279 	}
2280     }
2281 #ifdef SQL_BIGINT
2282     if (dobigint && result == SQL_INTEGER) {
2283 	result = SQL_BIGINT;
2284     }
2285 #endif
2286     xfree(p);
2287     return result;
2288 }
2289 
2290 /**
2291  * Get maximum display size and number of digits after decimal point
2292  * from field type specification.
2293  * @param typename field type specification
2294  * @param sqltype target SQL data type
2295  * @param mp pointer to maximum display size or NULL
2296  * @param dp pointer to number of digits after decimal point or NULL
2297  */
2298 
2299 static void
getmd(const char * typename,int sqltype,int * mp,int * dp)2300 getmd(const char *typename, int sqltype, int *mp, int *dp)
2301 {
2302     int m = 0, d = 0;
2303 
2304     switch (sqltype) {
2305     case SQL_INTEGER:       m = 10; d = 9; break;
2306     case SQL_TINYINT:       m = 4; d = 3; break;
2307     case SQL_SMALLINT:      m = 6; d = 5; break;
2308     case SQL_FLOAT:         m = 25; d = 24; break;
2309     case SQL_DOUBLE:        m = 54; d = 53; break;
2310     case SQL_VARCHAR:       m = 255; d = 0; break;
2311 #ifdef WINTERFACE
2312 #ifdef SQL_WVARCHAR
2313     case SQL_WVARCHAR:      m = 255; d = 0; break;
2314 #endif
2315 #endif
2316 #ifdef SQL_TYPE_DATE
2317     case SQL_TYPE_DATE:
2318 #endif
2319     case SQL_DATE:          m = 10; d = 0; break;
2320 #ifdef SQL_TYPE_TIME
2321     case SQL_TYPE_TIME:
2322 #endif
2323     case SQL_TIME:          m = 8; d = 0; break;
2324 #ifdef SQL_TYPE_TIMESTAMP
2325     case SQL_TYPE_TIMESTAMP:
2326 #endif
2327     case SQL_TIMESTAMP:     m = 32; d = 3; break;
2328 #ifdef SQL_LONGVARCHAR
2329     case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
2330 #endif
2331 #ifdef WINTERFACE
2332 #ifdef SQL_WLONGVARCHAR
2333     case SQL_WLONGVARCHAR:  m = 65536; d = 0; break;
2334 #endif
2335 #endif
2336     case SQL_BINARY:
2337     case SQL_VARBINARY:     m = 255; d = 0; break;
2338     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
2339 #ifdef SQL_BIGINT
2340     case SQL_BIGINT:        m = 20; d = 19; break;
2341 #endif
2342 #ifdef SQL_BIT
2343     case SQL_BIT:	    m = 1; d = 1; break;
2344 #endif
2345     }
2346     if (m && typename) {
2347 	int mm, dd;
2348 	char clbr[4];
2349 
2350 	if (sscanf(typename, "%*[^(](%d,%d %1[)]", &mm, &dd, clbr) == 3) {
2351 	    m = mm;
2352 	    d = dd;
2353 	} else if (sscanf(typename, "%*[^(](%d %1[)]", &mm, clbr) == 2) {
2354 	    if (sqltype == SQL_TIMESTAMP) {
2355 		d = mm;
2356 	    }
2357 #ifdef SQL_TYPE_TIMESTAMP
2358 	    else if (sqltype == SQL_TYPE_TIMESTAMP) {
2359 		d = mm;
2360 	    }
2361 #endif
2362 	    else {
2363 		m = d = mm;
2364 	    }
2365 	}
2366     }
2367     if (mp) {
2368 	*mp = m;
2369     }
2370     if (dp) {
2371 	*dp = d;
2372     }
2373 }
2374 
2375 /**
2376  * Map SQL_C_DEFAULT to proper C type.
2377  * @param type input C type
2378  * @param stype input SQL type
2379  * @param nosign 0=signed, 0>unsigned, 0<undefined
2380  * @param nowchar when compiled with WINTERFACE don't use WCHAR
2381  * @result C type
2382  */
2383 
2384 static int
mapdeftype(int type,int stype,int nosign,int nowchar)2385 mapdeftype(int type, int stype, int nosign, int nowchar)
2386 {
2387     if (type == SQL_C_DEFAULT) {
2388 	switch (stype) {
2389 	case SQL_INTEGER:
2390 	    type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
2391 	    break;
2392 	case SQL_TINYINT:
2393 	    type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
2394 	    break;
2395 	case SQL_SMALLINT:
2396 	    type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
2397 	    break;
2398 	case SQL_FLOAT:
2399 	    type = SQL_C_FLOAT;
2400 	    break;
2401 	case SQL_DOUBLE:
2402 	    type = SQL_C_DOUBLE;
2403 	    break;
2404 	case SQL_TIMESTAMP:
2405 	    type = SQL_C_TIMESTAMP;
2406 	    break;
2407 	case SQL_TIME:
2408 	    type = SQL_C_TIME;
2409 	    break;
2410 	case SQL_DATE:
2411 	    type = SQL_C_DATE;
2412 	    break;
2413 #ifdef SQL_C_TYPE_TIMESTAMP
2414 	case SQL_TYPE_TIMESTAMP:
2415 	    type = SQL_C_TYPE_TIMESTAMP;
2416 	    break;
2417 #endif
2418 #ifdef SQL_C_TYPE_TIME
2419 	case SQL_TYPE_TIME:
2420 	    type = SQL_C_TYPE_TIME;
2421 	    break;
2422 #endif
2423 #ifdef SQL_C_TYPE_DATE
2424 	case SQL_TYPE_DATE:
2425 	    type = SQL_C_TYPE_DATE;
2426 	    break;
2427 #endif
2428 #ifdef WINTERFACE
2429 	case SQL_WVARCHAR:
2430 	case SQL_WCHAR:
2431 #ifdef SQL_WLONGVARCHAR
2432 	case SQL_WLONGVARCHAR:
2433 #endif
2434 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
2435 	    break;
2436 #endif
2437 	case SQL_BINARY:
2438 	case SQL_VARBINARY:
2439 	case SQL_LONGVARBINARY:
2440 	    type = SQL_C_BINARY;
2441 	    break;
2442 #ifdef SQL_BIT
2443 	case SQL_BIT:
2444 	    type = SQL_C_BIT;
2445 	    break;
2446 #endif
2447 #ifdef SQL_BIGINT
2448 	case SQL_BIGINT:
2449 	    type = SQL_C_CHAR;
2450 	    break;
2451 #endif
2452 	default:
2453 #ifdef WINTERFACE
2454 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
2455 #else
2456 	    type = SQL_C_CHAR;
2457 #endif
2458 	    break;
2459 	}
2460     }
2461     return type;
2462 }
2463 
2464 /**
2465  * Check if query is a DDL statement.
2466  * @param sql query string
2467  * @result true or false
2468  */
2469 
2470 static int
checkddl(char * sql)2471 checkddl(char *sql)
2472 {
2473     int isddl = 0;
2474 
2475     while (*sql && ISSPACE(*sql)) {
2476 	++sql;
2477     }
2478     if (*sql && *sql != ';') {
2479 	int i, size;
2480 	static const struct {
2481 	    int len;
2482 	    const char *str;
2483 	} ddlstr[] = {
2484 	    { 5, "alter" },
2485 	    { 7, "analyze" },
2486 	    { 6, "attach" },
2487 	    { 5, "begin" },
2488 	    { 6, "commit" },
2489 	    { 6, "create" },
2490 	    { 6, "detach" },
2491 	    { 4, "drop" },
2492 	    { 3, "end" },
2493 	    { 7, "reindex" },
2494 	    { 7, "release" },
2495 	    { 8, "rollback" },
2496 	    { 9, "savepoint" },
2497 	    { 6, "vacuum" }
2498 	};
2499 
2500 	size = strlen(sql);
2501 	for (i = 0; i < array_size(ddlstr); i++) {
2502 	    if (size >= ddlstr[i].len &&
2503 		strncasecmp(sql, ddlstr[i].str, ddlstr[i].len) == 0) {
2504 		isddl = 1;
2505 		break;
2506 	    }
2507 	}
2508     }
2509     return isddl;
2510 }
2511 
2512 /**
2513  * Fixup query string with optional parameter markers.
2514  * @param sql original query string
2515  * @param sqlLen length of query string or SQL_NTS
2516  * @param cte when true, WITH is treated as SELECT
2517  * @param nparam output number of parameters
2518  * @param isselect output indicator for SELECT (1) or DDL statement (2)
2519  * @param errmsg output error message
2520  * @result newly allocated string containing query string for SQLite or NULL
2521  */
2522 
2523 static char *
fixupsql(char * sql,int sqlLen,int cte,int * nparam,int * isselect,char ** errmsg)2524 fixupsql(char *sql, int sqlLen, int cte, int *nparam, int *isselect,
2525 	 char **errmsg)
2526 {
2527     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
2528     int np = 0, isddl = -1, size;
2529 
2530     if (errmsg) {
2531 	*errmsg = NULL;
2532     }
2533     if (sqlLen != SQL_NTS) {
2534 	qz = q = xmalloc(sqlLen + 1);
2535 	if (!qz) {
2536 	    return NULL;
2537 	}
2538 	memcpy(q, sql, sqlLen);
2539 	q[sqlLen] = '\0';
2540 	size = sqlLen * 4;
2541     } else {
2542 	size = strlen(sql) * 4;
2543     }
2544     size += sizeof (char *) - 1;
2545     size &= ~(sizeof (char *) - 1);
2546     p = xmalloc(size);
2547     if (!p) {
2548 errout:
2549 	freep(&qz);
2550 	return NULL;
2551     }
2552     memset(p, 0, size);
2553     out = p;
2554     while (*q) {
2555 	switch (*q) {
2556 	case '\'':
2557 	case '\"':
2558 	    if (q == inq) {
2559 		inq = NULL;
2560 	    } else if (!inq) {
2561 		inq = q + 1;
2562 
2563 		while (*inq) {
2564 		    if (*inq == *q) {
2565 			if (inq[1] == *q) {
2566 			    inq++;
2567 			} else {
2568 			    break;
2569 			}
2570 		    }
2571 		    inq++;
2572 		}
2573 	    }
2574 	    *p++ = *q;
2575 	    break;
2576 	case '?':
2577 	    *p++ = *q;
2578 	    if (!inq) {
2579 		np++;
2580 	    }
2581 	    break;
2582 	case ';':
2583 	    if (!inq) {
2584 		if (isddl < 0) {
2585 		    isddl = checkddl(out);
2586 		}
2587 		if (isddl == 0) {
2588 		    char *qq = q;
2589 
2590 		    do {
2591 			++qq;
2592 		    } while (*qq && ISSPACE(*qq));
2593 		    if (*qq && *qq != ';') {
2594 			freep(&out);
2595 			if (errmsg) {
2596 			    *errmsg = "only one SQL statement allowed";
2597 			}
2598 			goto errout;
2599 		    }
2600 		}
2601 	    }
2602 	    *p++ = *q;
2603 	    break;
2604 	case '{':
2605 	    /*
2606 	     * Deal with escape sequences:
2607 	     * {d 'YYYY-MM-DD'}, {t ...}, {ts ...}
2608 	     * {oj ...}, {fn ...} etc.
2609 	     */
2610 	    if (!inq) {
2611 		int ojfn = 0, brc = 0;
2612 		char *inq2 = NULL, *end = q + 1, *start;
2613 
2614 		while (*end && ISSPACE(*end)) {
2615 		    ++end;
2616 		}
2617 		if (*end != 'd' && *end != 'D' &&
2618 		    *end != 't' && *end != 'T') {
2619 		    ojfn = 1;
2620 		}
2621 		start = end;
2622 		while (*end) {
2623 		    if (inq2 && *end == *inq2) {
2624 			inq2 = NULL;
2625 		    } else if (inq2 == NULL && *end == '{') {
2626 			char *nerr = 0, *nsql;
2627 
2628 			nsql = fixupsql(end, SQL_NTS, cte, 0, 0, &nerr);
2629 			if (nsql && !nerr) {
2630 			    strcpy(end, nsql);
2631 			} else {
2632 			    brc++;
2633 			}
2634 			freep(&nsql);
2635 		    } else if (inq2 == NULL && *end == '}') {
2636 			if (brc-- <= 0) {
2637 			    break;
2638 			}
2639 		    } else if (inq2 == NULL && (*end == '\'' || *end == '"')) {
2640 			inq2 = end;
2641 		    } else if (inq2 == NULL && *end == '?') {
2642 			np++;
2643 		    }
2644 		    ++end;
2645 		}
2646 		if (*end == '}') {
2647 		    char *end2 = end - 1;
2648 
2649 		    if (ojfn) {
2650 			while (start < end) {
2651 			    if (ISSPACE(*start)) {
2652 				break;
2653 			    }
2654 			    ++start;
2655 			}
2656 			while (start < end) {
2657 			    *p++ = *start;
2658 			    ++start;
2659 			}
2660 			q = end;
2661 			break;
2662 		    } else {
2663 			while (start < end2 && *start != '\'') {
2664 			    ++start;
2665 			}
2666 			while (end2 > start && *end2 != '\'') {
2667 			    --end2;
2668 			}
2669 			if (*start == '\'' && *end2 == '\'') {
2670 			    while (start <= end2) {
2671 				*p++ = *start;
2672 				++start;
2673 			    }
2674 			    q = end;
2675 			    break;
2676 			}
2677 		    }
2678 		}
2679 	    }
2680 	    /* FALL THROUGH */
2681 	default:
2682 	    *p++ = *q;
2683 	}
2684 	++q;
2685     }
2686     freep(&qz);
2687     *p = '\0';
2688     if (nparam) {
2689 	*nparam = np;
2690     }
2691     if (isselect) {
2692 	if (isddl < 0) {
2693 	    isddl = checkddl(out);
2694 	}
2695 	if (isddl > 0) {
2696 	    *isselect = 2;
2697 	} else {
2698 	    int incom = 0;
2699 
2700 	    p = out;
2701 	    while (*p) {
2702 		switch (*p) {
2703 		case '-':
2704 		    if (!incom && p[1] == '-') {
2705 			incom = -1;
2706 		    }
2707 		    break;
2708 		case '\n':
2709 		    if (incom < 0) {
2710 			incom = 0;
2711 		    }
2712 		    break;
2713 		case '/':
2714 		    if (incom > 0 && p[-1] == '*') {
2715 			incom = 0;
2716 			p++;
2717 			continue;
2718 		    } else if (!incom && p[1] == '*') {
2719 			incom = 1;
2720 		    }
2721 		    break;
2722 		}
2723 		if (!incom && !ISSPACE(*p)) {
2724 		    break;
2725 		}
2726 		p++;
2727 	    }
2728 	    size = strlen(p);
2729 	    if (size >= 6 &&
2730 		(strncasecmp(p, "select", 6) == 0 ||
2731 		 strncasecmp(p, "pragma", 6) == 0)) {
2732 		*isselect = 1;
2733 	    } else if (cte && size >= 4 && strncasecmp(p, "with", 4) == 0) {
2734 		*isselect = 1;
2735 	    } else if (size >= 7 && strncasecmp(p, "explain", 7) == 0) {
2736 		*isselect = 1;
2737 	    } else {
2738 		*isselect = 0;
2739 	    }
2740 	}
2741     }
2742     return out;
2743 }
2744 
2745 /**
2746  * Find column given name in string array.
2747  * @param cols string array
2748  * @param ncols number of strings
2749  * @param name column name
2750  * @result >= 0 on success, -1 on error
2751  */
2752 
2753 static int
findcol(char ** cols,int ncols,char * name)2754 findcol(char **cols, int ncols, char *name)
2755 {
2756     int i;
2757 
2758     if (cols) {
2759 	for (i = 0; i < ncols; i++) {
2760 	    if (strcmp(cols[i], name) == 0) {
2761 		return i;
2762 	    }
2763 	}
2764     }
2765     return -1;
2766 }
2767 
2768 /**
2769  * Fixup column information for a running statement.
2770  * @param s statement to get fresh column information
2771  * @param d DBC pointer
2772  *
2773  * The column labels get the table names stripped
2774  * when there's more than one column and all table
2775  * names are identical.
2776  *
2777  * The "dyncols" field of STMT is filled with column
2778  * information obtained by SQLite "PRAGMA table_info"
2779  * for each column whose table name is known. If the
2780  * types are already present as with SQLite 2.5.7
2781  * this information is used instead.
2782  */
2783 
2784 static void
fixupdyncols(STMT * s,DBC * d)2785 fixupdyncols(STMT *s, DBC *d)
2786 {
2787     int i, k;
2788 #ifndef FULL_METADATA
2789     int pk, nn, t, r, nrows, ncols;
2790     char **rowp, *flagp, flags[128];
2791 #endif
2792 
2793     if (!s->dyncols) {
2794 	return;
2795     }
2796     /* fixup labels */
2797     if (!s->longnames) {
2798 	if (s->dcols > 1) {
2799 	    char *table = s->dyncols[0].table;
2800 
2801 	    for (i = 1; table[0] && i < s->dcols; i++) {
2802 		if (strcmp(s->dyncols[i].table, table)) {
2803 		    break;
2804 		}
2805 	    }
2806 	    if (i >= s->dcols) {
2807 		for (i = 0; i < s->dcols; i++) {
2808 		    s->dyncols[i].label = s->dyncols[i].column;
2809 		}
2810 	    }
2811 	} else if (s->dcols == 1) {
2812 	    s->dyncols[0].label = s->dyncols[0].column;
2813 	}
2814     }
2815     for (i = 0; i < s->dcols; i++) {
2816 	s->dyncols[i].type =
2817 	    mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3,
2818 		       s->nowchar[0] || s->nowchar[1], s->dobigint);
2819 	getmd(s->dyncols[i].typename, s->dyncols[i].type,
2820 	      &s->dyncols[i].size, &s->dyncols[i].prec);
2821 #ifdef SQL_LONGVARCHAR
2822 	if (s->dyncols[i].type == SQL_VARCHAR &&
2823 	    s->dyncols[i].size > 255) {
2824 	    s->dyncols[i].type = SQL_LONGVARCHAR;
2825 	}
2826 #endif
2827 #ifdef WINTERFACE
2828 #ifdef SQL_WLONGVARCHAR
2829 	if (s->dyncols[i].type == SQL_WVARCHAR &&
2830 	    s->dyncols[i].size > 255) {
2831 	    s->dyncols[i].type = SQL_WLONGVARCHAR;
2832 	}
2833 #endif
2834 #endif
2835 	if (s->dyncols[i].type == SQL_VARBINARY &&
2836 	    s->dyncols[i].size > 255) {
2837 	    s->dyncols[i].type = SQL_LONGVARBINARY;
2838 	}
2839     }
2840 #ifndef FULL_METADATA
2841     if (s->dcols > array_size(flags)) {
2842 	flagp = xmalloc(sizeof (flags[0]) * s->dcols);
2843 	if (flagp == NULL) {
2844 	    return;
2845 	}
2846     } else {
2847 	flagp = flags;
2848     }
2849     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
2850     for (i = 0; i < s->dcols; i++) {
2851 	s->dyncols[i].autoinc = SQL_FALSE;
2852 	s->dyncols[i].notnull = SQL_NULLABLE;
2853     }
2854     for (i = 0; i < s->dcols; i++) {
2855 	int ret, lastpk = -1, autoinccount = 0;
2856 	char *sql;
2857 
2858 	if (!s->dyncols[i].table[0]) {
2859 	    continue;
2860 	}
2861 	if (flagp[i]) {
2862 	    continue;
2863 	}
2864 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", s->dyncols[i].table);
2865 	if (!sql) {
2866 	    continue;
2867 	}
2868 	dbtraceapi(d, "sqlite3_get_table", sql);
2869 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, NULL);
2870 	sqlite3_free(sql);
2871 	if (ret != SQLITE_OK) {
2872 	    continue;
2873 	}
2874 	k = findcol(rowp, ncols, "name");
2875 	t = findcol(rowp, ncols, "type");
2876 	pk = findcol(rowp, ncols, "pk");
2877 	nn = findcol(rowp, ncols, "notnull");
2878 	if (k < 0 || t < 0) {
2879 	    goto freet;
2880 	}
2881 	for (r = 1; r <= nrows; r++) {
2882 	    int m;
2883 
2884 	    for (m = i; m < s->dcols; m++) {
2885 		char *colname = s->dyncols[m].column;
2886 
2887 		if (s->longnames) {
2888 		    char *dotp = strchr(colname, '.');
2889 
2890 		    if (dotp) {
2891 			colname = dotp + 1;
2892 		    }
2893 		}
2894 		if (!flagp[m] &&
2895 		    strcmp(colname, rowp[r * ncols + k]) == 0 &&
2896 		    strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
2897 		    char *typename = rowp[r * ncols + t];
2898 
2899 		    flagp[m] = i + 1;
2900 		    freep(&s->dyncols[m].typename);
2901 		    s->dyncols[m].typename = xstrdup(typename);
2902 		    s->dyncols[m].type =
2903 			mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
2904 				   s->nowchar[0] || s->nowchar[1],
2905 				   s->dobigint);
2906 		    getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
2907 			  &s->dyncols[m].prec);
2908 #ifdef SQL_LONGVARCHAR
2909 		    if (s->dyncols[m].type == SQL_VARCHAR &&
2910 			s->dyncols[m].size > 255) {
2911 			s->dyncols[m].type = SQL_LONGVARCHAR;
2912 		    }
2913 #endif
2914 #ifdef WINTERFACE
2915 #ifdef SQL_WLONGVARCHAR
2916 		    if (s->dyncols[i].type == SQL_WVARCHAR &&
2917 			s->dyncols[i].size > 255) {
2918 			s->dyncols[i].type = SQL_WLONGVARCHAR;
2919 		    }
2920 #endif
2921 #endif
2922 		    if (s->dyncols[i].type == SQL_VARBINARY &&
2923 			s->dyncols[i].size > 255) {
2924 			s->dyncols[i].type = SQL_LONGVARBINARY;
2925 		    }
2926 		    if (pk >= 0	&& strcmp(rowp[r * ncols + pk], "1") == 0) {
2927 			s->dyncols[m].ispk = 1;
2928 			if (++autoinccount > 1) {
2929 			    if (lastpk >= 0) {
2930 				s->dyncols[lastpk].autoinc = SQL_FALSE;
2931 				lastpk = -1;
2932 			    }
2933 			} else {
2934 			    lastpk = m;
2935 			    if (strlen(typename) == 7 &&
2936 				strncasecmp(typename, "integer", 7) == 0) {
2937 				s->dyncols[m].autoinc = SQL_TRUE;
2938 			    }
2939 			}
2940 		    } else {
2941 			s->dyncols[m].ispk = 0;
2942 		    }
2943 		    if (nn >= 0 && rowp[r * ncols + nn][0] != '0') {
2944 			s->dyncols[m].notnull = SQL_NO_NULLS;
2945 		    }
2946 		}
2947 	    }
2948 	}
2949 freet:
2950 	sqlite3_free_table(rowp);
2951     }
2952     for (i = k = 0; i < s->dcols; i++) {
2953 	if (flagp[i] == 0) {
2954 	    break;
2955 	}
2956 	if (k == 0) {
2957 	    k = flagp[i];
2958 	} else if (flagp[i] != k) {
2959 	    k = 0;
2960 	    break;
2961 	}
2962     }
2963     s->one_tbl = k ? 1 : 0;
2964     k = 0;
2965     if (s->one_tbl) {
2966 	for (i = 0; i < s->dcols; i++) {
2967 	    if (s->dyncols[i].ispk > 0) {
2968 		++k;
2969 	    }
2970 	}
2971     }
2972     s->has_pk = k;
2973     if (flagp != flags) {
2974 	freep(&flagp);
2975     }
2976 #else
2977     for (i = 1, k = 0; i < s->dcols; i++) {
2978 	if (strcmp(s->dyncols[i].table, s->dyncols[0].table) == 0) {
2979 	    k++;
2980 	}
2981     }
2982     s->one_tbl = (k && k + 1 == s->dcols) ? 1 : 0;
2983     k = 0;
2984     if (s->one_tbl) {
2985 	for (i = 0; i < s->dcols; i++) {
2986 	    if (s->dyncols[i].ispk > 0) {
2987 		++k;
2988 		if (s->has_rowid < 0 && s->dyncols[i].isrowid > 0) {
2989 		    s->has_rowid = i;
2990 		}
2991 	    }
2992 	}
2993     }
2994     s->has_pk = k;
2995 #endif
2996 }
2997 
2998 /**
2999  * Convert julian day to year/month/day.
3000  * @param jd julian day as stored in database
3001  * @param ds output DATE_STRUCT
3002  */
3003 
3004 static void
convJD2YMD(double jd,DATE_STRUCT * ds)3005 convJD2YMD(double jd, DATE_STRUCT *ds)
3006 {
3007     int z, a, b, c, d, e, x1;
3008     sqlite_int64 ijd;
3009 
3010     ijd = jd * 86400000.0 + 0.5;
3011     z = (int) ((ijd + 43200000) / 86400000);
3012     a = (int) ((z - 1867216.25) / 36524.25);
3013     a = z + 1 + a - (a / 4);
3014     b = a + 1524;
3015     c = (int) ((b - 122.1) / 365.25);
3016     d = (36525 * c) / 100;
3017     e = (int) ((b - d) / 30.6001);
3018     x1 = (int) (30.6001 * e);
3019     ds->day = b - d - x1;
3020     ds->month = (e < 14) ? (e - 1) : (e - 13);
3021     ds->year = (ds->month > 2) ? (c - 4716) : (c - 4715);
3022 }
3023 
3024 
3025 /**
3026  * Convert julian day to hour/minute/second.
3027  * @param jd julian day as stored in database
3028  * @param ts output TIME_STRUCT
3029  * @param fp optional fractional part output
3030  */
3031 
3032 static void
convJD2HMS(double jd,TIME_STRUCT * ts,int * fp)3033 convJD2HMS(double jd, TIME_STRUCT *ts, int *fp)
3034 {
3035     int s;
3036     double ds;
3037     sqlite_int64 ijd;
3038 
3039     ijd = jd * 86400000.0 + 0.5;
3040     s = (int)((ijd + 43200000) % 86400000);
3041     ds = s / 1000.0;
3042     if (fp) {
3043 	*fp = (s % 1000) * 1000000;
3044     }
3045     s = (int) ds;
3046     ds -= s;
3047     ts->hour = s / 3600;
3048     s -= ts->hour * 3600;
3049     ts->minute = s / 60;
3050     ds += s - ts->minute *60;
3051     ts->second = (int) ds;
3052 }
3053 
3054 /**
3055  * Return number of month days.
3056  * @param year
3057  * @param month 1..12
3058  * @result number of month days or 0
3059  */
3060 
3061 static int
getmdays(int year,int month)3062 getmdays(int year, int month)
3063 {
3064     static const int mdays[] = {
3065 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3066     };
3067     int mday;
3068 
3069     if (month < 1) {
3070 	return 0;
3071     }
3072     mday = mdays[(month - 1) % 12];
3073     if (mday == 28 && year % 4 == 0 &&
3074 	(!(year % 100 == 0) || year % 400 == 0)) {
3075 	mday++;
3076     }
3077     return mday;
3078 }
3079 
3080 /**
3081  * Convert string to ODBC DATE_STRUCT.
3082  * @param jdconv when true, allow julian day format
3083  * @param str string to be converted
3084  * @param ds output DATE_STRUCT
3085  * @result 0 on success, -1 on error
3086  *
3087  * Strings of the format 'YYYYMMDD' or 'YYYY-MM-DD' or
3088  * 'YYYY/MM/DD' or 'MM/DD/YYYY' are converted to a
3089  * DATE_STRUCT.
3090  *
3091  * If the string looks like a floating point number,
3092  * SQLite3's julian day format is assumed.
3093  */
3094 
3095 static int
str2date(int jdconv,char * str,DATE_STRUCT * ds)3096 str2date(int jdconv, char *str, DATE_STRUCT *ds)
3097 {
3098     int i, err = 0;
3099     double jd;
3100     char *p, *q, sepc = '\0';
3101 
3102     ds->year = ds->month = ds->day = 0;
3103     if (jdconv) {
3104 	p = strchr(str, '.');
3105 	if (p) {
3106 	    /* julian day format */
3107 	    p = 0;
3108 	    jd = ln_strtod(str, &p);
3109 	    if (p && p > str) {
3110 		convJD2YMD(jd, ds);
3111 		return 0;
3112 	    }
3113 	}
3114     }
3115     p = str;
3116     while (*p && !ISDIGIT(*p)) {
3117 	++p;
3118     }
3119     q = p;
3120     i = 0;
3121     while (*q && !ISDIGIT(*q)) {
3122 	++i;
3123 	++q;
3124     }
3125     if (i >= 8) {
3126 	char buf[8];
3127 
3128 	strncpy(buf, p + 0, 4); buf[4] = '\0';
3129 	ds->year = strtol(buf, NULL, 10);
3130 	strncpy(buf, p + 4, 2); buf[2] = '\0';
3131 	ds->month = strtol(buf, NULL, 10);
3132 	strncpy(buf, p + 6, 2); buf[2] = '\0';
3133 	ds->day = strtol(buf, NULL, 10);
3134 	goto done;
3135     }
3136     i = 0;
3137     while (i < 3) {
3138 	int n;
3139 
3140 	q = NULL;
3141 	n = strtol(p, &q, 10);
3142 	if (!q || q == p) {
3143 	    if (*q == '\0') {
3144 		if (i == 0) {
3145 		    err = 1;
3146 		}
3147 		goto done;
3148 	    }
3149 	}
3150 	if (!sepc) {
3151 	    sepc = *q;
3152 	}
3153 	if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
3154 	    switch (i) {
3155 	    case 0: ds->year = n; break;
3156 	    case 1: ds->month = n; break;
3157 	    case 2: ds->day = n; break;
3158 	    }
3159 	    ++i;
3160 	    if (*q) {
3161 		++q;
3162 	    }
3163 	} else {
3164 	    i = 0;
3165 	    while (*q && !ISDIGIT(*q)) {
3166 		++q;
3167 	    }
3168 	}
3169 	p = q;
3170     }
3171 done:
3172     /* final check for overflow */
3173     if (err ||
3174 	ds->month < 1 || ds->month > 12 ||
3175 	ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
3176 	if (sepc == '/') {
3177 	    /* Try MM/DD/YYYY format */
3178 	    int t[3];
3179 
3180 	    t[0] = ds->year;
3181 	    t[1] = ds->month;
3182 	    t[2] = ds->day;
3183 	    ds->year = t[2];
3184 	    ds->day = t[1];
3185 	    ds->month = t[0];
3186 	    if (ds->month >= 1 && ds->month <= 12 &&
3187 		(ds->day >= 1 || ds->day <= getmdays(ds->year, ds->month))) {
3188 		return 0;
3189 	    }
3190 	}
3191 	return -1;
3192     }
3193     return 0;
3194 }
3195 
3196 /**
3197  * Convert string to ODBC TIME_STRUCT.
3198  * @param jdconv when true, allow julian day format
3199  * @param str string to be converted
3200  * @param ts output TIME_STRUCT
3201  * @result 0 on success, -1 on error
3202  *
3203  * Strings of the format 'HHMMSS' or 'HH:MM:SS'
3204  * are converted to a TIME_STRUCT.
3205  *
3206  * If the string looks like a floating point number,
3207  * SQLite3's julian day format is assumed.
3208  */
3209 
3210 static int
str2time(int jdconv,char * str,TIME_STRUCT * ts)3211 str2time(int jdconv, char *str, TIME_STRUCT *ts)
3212 {
3213     int i, err = 0, ampm = -1;
3214     double jd;
3215     char *p, *q;
3216 
3217     ts->hour = ts->minute = ts->second = 0;
3218     if (jdconv) {
3219 	p = strchr(str, '.');
3220 	if (p) {
3221 	    /* julian day format */
3222 	    p = 0;
3223 	    jd = ln_strtod(str, &p);
3224 	    if (p && p > str) {
3225 		convJD2HMS(jd, ts, 0);
3226 		return 0;
3227 	    }
3228 	}
3229     }
3230     p = str;
3231     while (*p && !ISDIGIT(*p)) {
3232 	++p;
3233     }
3234     q = p;
3235     i = 0;
3236     while (*q && ISDIGIT(*q)) {
3237 	++i;
3238 	++q;
3239     }
3240     if (i >= 6) {
3241 	char buf[4];
3242 
3243 	strncpy(buf, p + 0, 2); buf[2] = '\0';
3244 	ts->hour = strtol(buf, NULL, 10);
3245 	strncpy(buf, p + 2, 2); buf[2] = '\0';
3246 	ts->minute = strtol(buf, NULL, 10);
3247 	strncpy(buf, p + 4, 2); buf[2] = '\0';
3248 	ts->second = strtol(buf, NULL, 10);
3249 	goto done;
3250     }
3251     i = 0;
3252     while (i < 3) {
3253 	int n;
3254 
3255 	q = NULL;
3256 	n = strtol(p, &q, 10);
3257 	if (!q || q == p) {
3258 	    if (*q == '\0') {
3259 		if (i == 0) {
3260 		    err = 1;
3261 		}
3262 		goto done;
3263 	    }
3264 	}
3265 	if (*q == ':' || *q == '\0' || i == 2) {
3266 	    switch (i) {
3267 	    case 0: ts->hour = n; break;
3268 	    case 1: ts->minute = n; break;
3269 	    case 2: ts->second = n; break;
3270 	    }
3271 	    ++i;
3272 	    if (*q) {
3273 		++q;
3274 	    }
3275 	} else {
3276 	    i = 0;
3277 	    while (*q && !ISDIGIT(*q)) {
3278 		++q;
3279 	    }
3280 	}
3281 	p = q;
3282     }
3283     if (!err) {
3284 	while (*p) {
3285 	    if ((p[0] == 'p' || p[0] == 'P') &&
3286 		(p[1] == 'm' || p[1] == 'M')) {
3287 		ampm = 1;
3288 	    } else if ((p[0] == 'a' || p[0] == 'A') &&
3289 		(p[1] == 'm' || p[1] == 'M')) {
3290 		ampm = 0;
3291 	    }
3292 	    ++p;
3293 	}
3294 	if (ampm > 0) {
3295 	    if (ts->hour < 12) {
3296 		ts->hour += 12;
3297 	    }
3298 	} else if (ampm == 0) {
3299 	    if (ts->hour == 12) {
3300 		ts->hour = 0;
3301 	    }
3302 	}
3303     }
3304 done:
3305     /* final check for overflow */
3306     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
3307 	return -1;
3308     }
3309     return 0;
3310 }
3311 
3312 /**
3313  * Convert string to ODBC TIMESTAMP_STRUCT.
3314  * @param jdconv when true, allow julian day format
3315  * @param str string to be converted
3316  * @param tss output TIMESTAMP_STRUCT
3317  * @result 0 on success, -1 on error
3318  *
3319  * Strings of the format 'YYYYMMDDhhmmssff' or 'YYYY-MM-DD hh:mm:ss ff'
3320  * or 'YYYY/MM/DD hh:mm:ss ff' or 'hh:mm:ss ff YYYY-MM-DD' are
3321  * converted to a TIMESTAMP_STRUCT. The ISO8601 formats
3322  *    YYYY-MM-DDThh:mm:ss[.f]Z
3323  *    YYYY-MM-DDThh:mm:ss[.f]shh:mm
3324  * are also supported. In case a time zone field is present,
3325  * the resulting TIMESTAMP_STRUCT is expressed in UTC.
3326  *
3327  * If the string looks like a floating point number,
3328  * SQLite3's julian day format is assumed.
3329  */
3330 
3331 static int
str2timestamp(int jdconv,char * str,TIMESTAMP_STRUCT * tss)3332 str2timestamp(int jdconv, char *str, TIMESTAMP_STRUCT *tss)
3333 {
3334     int i, m, n, err = 0, ampm = -1;
3335     double jd;
3336     char *p, *q, in = '\0', sepc = '\0';
3337 
3338     tss->year = tss->month = tss->day = 0;
3339     tss->hour = tss->minute = tss->second = 0;
3340     tss->fraction = 0;
3341     if (jdconv) {
3342 	p = strchr(str, '.');
3343 	if (p) {
3344 	    q = strchr(str, '-');
3345 	    if (q == str) {
3346 		q = 0;
3347 	    }
3348 	    if (!q) {
3349 		q = strchr(str, '/');
3350 		if (!q) {
3351 		    q = strchr(str, ':');
3352 		}
3353 	    }
3354 	    if (!q || q > p) {
3355 		/* julian day format */
3356 		p = 0;
3357 		jd = ln_strtod(str, &p);
3358 		if (p && p > str) {
3359 		    DATE_STRUCT ds;
3360 		    TIME_STRUCT ts;
3361 
3362 		    convJD2YMD(jd, &ds);
3363 		    convJD2HMS(jd, &ts, &n);
3364 		    tss->year = ds.year;
3365 		    tss->month = ds.month;
3366 		    tss->day = ds.day;
3367 		    tss->hour = ts.hour;
3368 		    tss->minute = ts.minute;
3369 		    tss->second = ts.second;
3370 		    tss->fraction = n;
3371 		    return 0;
3372 		}
3373 	    }
3374 	}
3375     }
3376     p = str;
3377     while (*p && !ISDIGIT(*p)) {
3378 	++p;
3379     }
3380     q = p;
3381     i = 0;
3382     while (*q && ISDIGIT(*q)) {
3383 	++i;
3384 	++q;
3385     }
3386     if (i >= 14) {
3387 	char buf[16];
3388 
3389 	strncpy(buf, p + 0, 4); buf[4] = '\0';
3390 	tss->year = strtol(buf, NULL, 10);
3391 	strncpy(buf, p + 4, 2); buf[2] = '\0';
3392 	tss->month = strtol(buf, NULL, 10);
3393 	strncpy(buf, p + 6, 2); buf[2] = '\0';
3394 	tss->day = strtol(buf, NULL, 10);
3395 	strncpy(buf, p + 8, 2); buf[2] = '\0';
3396 	tss->hour = strtol(buf, NULL, 10);
3397 	strncpy(buf, p + 10, 2); buf[2] = '\0';
3398 	tss->minute = strtol(buf, NULL, 10);
3399 	strncpy(buf, p + 12, 2); buf[2] = '\0';
3400 	tss->second = strtol(buf, NULL, 10);
3401 	if (i > 14) {
3402 	    m = i - 14;
3403 	    strncpy(buf, p + 14, m);
3404 	    while (m < 9) {
3405 		buf[m] = '0';
3406 		++m;
3407 	    }
3408 	    buf[m] = '\0';
3409 	    tss->fraction = strtol(buf, NULL, 10);
3410 	}
3411 	m = 7;
3412 	goto done;
3413     }
3414     m = i = 0;
3415     while ((m & 7) != 7) {
3416 	q = NULL;
3417 	n = strtol(p, &q, 10);
3418 	if (!q || q == p) {
3419 	    if (*q == '\0') {
3420 		if (m < 1) {
3421 		    err = 1;
3422 		}
3423 		goto done;
3424 	    }
3425 	}
3426 	if (in == '\0') {
3427 	    switch (*q) {
3428 	    case '-':
3429 	    case '/':
3430 		if ((m & 1) == 0) {
3431 		    in = *q;
3432 		    i = 0;
3433 		}
3434 		break;
3435 	    case ':':
3436 		if ((m & 2) == 0) {
3437 		    in = *q;
3438 		    i = 0;
3439 		}
3440 		break;
3441 	    case ' ':
3442 	    case '.':
3443 		break;
3444 	    default:
3445 		in = '\0';
3446 		i = 0;
3447 		break;
3448 	    }
3449 	}
3450 	switch (in) {
3451 	case '-':
3452 	case '/':
3453 	    if (!sepc) {
3454 		sepc = in;
3455 	    }
3456 	    switch (i) {
3457 	    case 0: tss->year = n; break;
3458 	    case 1: tss->month = n; break;
3459 	    case 2: tss->day = n; break;
3460 	    }
3461 	    if (++i >= 3) {
3462 		i = 0;
3463 		m |= 1;
3464 		if (!(m & 2)) {
3465 		    m |= 8;
3466 		}
3467 		goto skip;
3468 	    } else {
3469 		++q;
3470 	    }
3471 	    break;
3472 	case ':':
3473 	    switch (i) {
3474 	    case 0: tss->hour = n; break;
3475 	    case 1: tss->minute = n; break;
3476 	    case 2: tss->second = n; break;
3477 	    }
3478 	    if (++i >= 3) {
3479 		i = 0;
3480 		m |= 2;
3481 		if (*q == '.') {
3482 		    in = '.';
3483 		    goto skip2;
3484 		}
3485 		if (*q == ' ') {
3486 		    if ((m & 1) == 0) {
3487 			char *e = NULL;
3488 
3489 			(void) strtol(q + 1, &e, 10);
3490 			if (e && *e == '-') {
3491 			    goto skip;
3492 			}
3493 		    }
3494 		    in = '.';
3495 		    goto skip2;
3496 		}
3497 		goto skip;
3498 	    } else {
3499 		++q;
3500 	    }
3501 	    break;
3502 	case '.':
3503 	    if (++i >= 1) {
3504 		int ndig = q - p;
3505 
3506 		if (p[0] == '+' || p[0] == '-') {
3507 		    ndig--;
3508 		}
3509 		while (ndig < 9) {
3510 		    n = n * 10;
3511 		    ++ndig;
3512 		}
3513 		tss->fraction = n;
3514 		m |= 4;
3515 		i = 0;
3516 	    }
3517 	default:
3518 	skip:
3519 	    in = '\0';
3520 	skip2:
3521 	    while (*q && !ISDIGIT(*q)) {
3522 		if ((q[0] == 'a' || q[0] == 'A') &&
3523 		    (q[1] == 'm' || q[1] == 'M')) {
3524 		    ampm = 0;
3525 		    ++q;
3526 		} else if ((q[0] == 'p' || q[0] == 'P') &&
3527 			   (q[1] == 'm' || q[1] == 'M')) {
3528 		    ampm = 1;
3529 		    ++q;
3530 		}
3531 		++q;
3532 	    }
3533 	}
3534 	p = q;
3535     }
3536     if ((m & 7) > 1 && (m & 8)) {
3537 	/* ISO8601 timezone */
3538 	if (p > str && ISDIGIT(*p)) {
3539 	    int nn, sign;
3540 
3541 	    q = p - 1;
3542 	    if (*q != '+' && *q != '-') {
3543 		goto done;
3544 	    }
3545 	    sign = (*q == '+') ? -1 : 1;
3546 	    q = NULL;
3547 	    n = strtol(p, &q, 10);
3548 	    if (!q || *q++ != ':' || !ISDIGIT(*q)) {
3549 		goto done;
3550 	    }
3551 	    p = q;
3552 	    q = NULL;
3553 	    nn = strtol(p, &q, 10);
3554 	    tss->minute += nn * sign;
3555 	    if ((SQLSMALLINT) tss->minute < 0) {
3556 		tss->hour -= 1;
3557 		tss->minute += 60;
3558 	    } else if (tss->minute >= 60) {
3559 		tss->hour += 1;
3560 		tss->minute -= 60;
3561 	    }
3562 	    tss->hour += n * sign;
3563 	    if ((SQLSMALLINT) tss->hour < 0) {
3564 		tss->day -= 1;
3565 		tss->hour += 24;
3566 	    } else if (tss->hour >= 24) {
3567 		tss->day += 1;
3568 		tss->hour -= 24;
3569 	    }
3570 	    if ((short) tss->day < 1 || tss->day >= 28) {
3571 		int mday, pday, pmon;
3572 
3573 		mday = getmdays(tss->year, tss->month);
3574 		pmon = tss->month - 1;
3575 		if (pmon < 1) {
3576 		    pmon = 12;
3577 		}
3578 		pday = getmdays(tss->year, pmon);
3579 		if ((SQLSMALLINT) tss->day < 1) {
3580 		    tss->month -= 1;
3581 		    tss->day = pday;
3582 		} else if (tss->day > mday) {
3583 		    tss->month += 1;
3584 		    tss->day = 1;
3585 		}
3586 		if ((SQLSMALLINT) tss->month < 1) {
3587 		    tss->year -= 1;
3588 		    tss->month = 12;
3589 		} else if (tss->month > 12) {
3590 		    tss->year += 1;
3591 		    tss->month = 1;
3592 		}
3593 	    }
3594 	}
3595     }
3596 done:
3597     if ((m & 1) &&
3598 	(tss->month < 1 || tss->month > 12 ||
3599 	 tss->day < 1 || tss->day > getmdays(tss->year, tss->month))) {
3600 	if (sepc == '/') {
3601 	    /* Try MM/DD/YYYY format */
3602 	    int t[3];
3603 
3604 	    t[0] = tss->year;
3605 	    t[1] = tss->month;
3606 	    t[2] = tss->day;
3607 	    tss->year = t[2];
3608 	    tss->day = t[1];
3609 	    tss->month = t[0];
3610 	}
3611     }
3612     /* Replace missing year/month/day with current date */
3613     if (!err && (m & 1) == 0) {
3614 #ifdef _WIN32
3615 	SYSTEMTIME t;
3616 
3617 	GetLocalTime(&t);
3618 	tss->year = t.wYear;
3619 	tss->month = t.wMonth;
3620 	tss->day = t.wDay;
3621 #else
3622 	struct timeval tv;
3623 	struct tm tm;
3624 
3625 	gettimeofday(&tv, NULL);
3626 	tm = *localtime(&tv.tv_sec);
3627 	tss->year = tm.tm_year + 1900;
3628 	tss->month = tm.tm_mon + 1;
3629 	tss->day = tm.tm_mday;
3630 #endif
3631     }
3632     /* Normalize fraction */
3633     if (tss->fraction < 0) {
3634 	tss->fraction = 0;
3635     }
3636     /* Final check for overflow */
3637     if (err ||
3638 	tss->month < 1 || tss->month > 12 ||
3639 	tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
3640 	tss->hour > 23 || tss->minute > 59 || tss->second > 59) {
3641 	return -1;
3642     }
3643     if ((m & 7) > 1) {
3644 	if (ampm > 0) {
3645 	    if (tss->hour < 12) {
3646 		tss->hour += 12;
3647 	    }
3648 	} else if (ampm == 0) {
3649 	    if (tss->hour == 12) {
3650 		tss->hour = 0;
3651 	    }
3652 	}
3653     }
3654     return ((m & 7) < 1) ? -1 : 0;
3655 }
3656 
3657 /**
3658  * Get boolean flag from string.
3659  * @param string string to be inspected
3660  * @result true or false
3661  */
3662 
3663 static int
getbool(char * string)3664 getbool(char *string)
3665 {
3666     if (string) {
3667 	return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
3668     }
3669     return 0;
3670 }
3671 
3672 /**
3673  * SQLite function to import a BLOB from a file
3674  * @param ctx function context
3675  * @param nargs number arguments
3676  * @param args arguments
3677  */
3678 
3679 static void
blob_import(sqlite3_context * ctx,int nargs,sqlite3_value ** args)3680 blob_import(sqlite3_context *ctx, int nargs, sqlite3_value **args)
3681 {
3682 #if 0
3683     DBC *d = (DBC *) sqlite3_user_data(ctx);
3684 #endif
3685     char *filename = 0;
3686 
3687     if (nargs > 0) {
3688 	if (sqlite3_value_type(args[0]) != SQLITE_NULL) {
3689 	    filename = (char *) sqlite3_value_text(args[0]);
3690 	}
3691     }
3692     if (filename) {
3693 #ifdef _WIN32
3694 	char *wname = utf_to_wmb(filename, -1);
3695 	FILE *f;
3696 #else
3697 	FILE *f = fopen(filename, "r");
3698 #endif
3699 	char *p;
3700 	long n, nn;
3701 
3702 #ifdef _WIN32
3703 	if (wname) {
3704 	    f = fopen(wname, "rb");
3705 	} else {
3706 	    sqlite3_result_error(ctx, "out of memory", -1);
3707 	    return;
3708 	}
3709 	uc_free(wname);
3710 #endif
3711 	if (f) {
3712 	    if (fseek(f, 0, SEEK_END) == 0) {
3713 		n = ftell(f);
3714 		if (fseek(f, 0, SEEK_SET) == 0) {
3715 		    p = sqlite3_malloc(n);
3716 		    if (p) {
3717 			nn = fread(p, 1, n, f);
3718 			if (nn != n) {
3719 			    sqlite3_result_error(ctx, "read error", -1);
3720 			    sqlite3_free(p);
3721 			} else {
3722 			    sqlite3_result_blob(ctx, p, n, sqlite3_free);
3723 			}
3724 		    } else {
3725 			sqlite3_result_error(ctx, "out of memory", -1);
3726 		    }
3727 		} else {
3728 		    sqlite3_result_error(ctx, "seek error", -1);
3729 		}
3730 	    } else {
3731 		sqlite3_result_error(ctx, "seek error", -1);
3732 	    }
3733 	    fclose(f);
3734 	} else {
3735 	    sqlite3_result_error(ctx, "cannot open file", -1);
3736 	}
3737     } else {
3738 	sqlite3_result_error(ctx, "no filename given", -1);
3739     }
3740 }
3741 
3742 /**
3743  * SQLite function to export a BLOB to a file
3744  * @param ctx function context
3745  * @param nargs number arguments
3746  * @param args arguments
3747  */
3748 
3749 static void
blob_export(sqlite3_context * ctx,int nargs,sqlite3_value ** args)3750 blob_export(sqlite3_context *ctx, int nargs, sqlite3_value **args)
3751 {
3752 #if 0
3753     DBC *d = (DBC *) sqlite3_user_data(ctx);
3754 #endif
3755     char *filename = 0;
3756     char *p = 0;
3757     int n = 0;
3758 
3759     if (nargs > 0) {
3760 	p = (char *) sqlite3_value_blob(args[0]);
3761 	n = sqlite3_value_bytes(args[0]);
3762     }
3763     if (nargs > 1) {
3764 	if (sqlite3_value_type(args[1]) != SQLITE_NULL) {
3765 	    filename = (char *) sqlite3_value_text(args[1]);
3766 	}
3767     }
3768     if (p) {
3769 	if (filename) {
3770 #ifdef _WIN32
3771 	    char *wname = utf_to_wmb(filename, -1);
3772 	    FILE *f;
3773 #else
3774 	    FILE *f = fopen(filename, "w");
3775 #endif
3776 	    int nn;
3777 
3778 #ifdef _WIN32
3779 	    if (wname) {
3780 		f = fopen(wname, "wb");
3781 	    } else {
3782 		sqlite3_result_error(ctx, "out of memory", -1);
3783 		return;
3784 	    }
3785 	    uc_free(wname);
3786 #endif
3787 	    if (f) {
3788 		nn = fwrite(p, 1, n, f);
3789 		fclose(f);
3790 		if (nn != n) {
3791 		    sqlite3_result_error(ctx, "write error", -1);
3792 		} else {
3793 		    sqlite3_result_int(ctx, nn);
3794 		}
3795 	    } else {
3796 		sqlite3_result_error(ctx, "cannot open file", -1);
3797 	    }
3798 	} else {
3799 	    sqlite3_result_error(ctx, "no filename given", -1);
3800 	}
3801     } else {
3802 	sqlite3_result_null(ctx);
3803     }
3804 }
3805 
3806 /**
3807  * SQLite trace or profile callback
3808  * @param arg DBC pointer
3809  * @param msg log message, SQL text
3810  * @param et  elapsed time
3811  */
3812 
3813 static void
3814 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
dbtrace(void * arg,const char * msg,sqlite_uint64 et)3815 dbtrace(void *arg, const char *msg, sqlite_uint64 et)
3816 #else
3817 dbtrace(void *arg, const char *msg)
3818 #endif
3819 {
3820     DBC *d = (DBC *) arg;
3821 
3822     if (msg && d->trace) {
3823 	int len = strlen(msg);
3824 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
3825 	unsigned long s, f;
3826 #endif
3827 
3828 	if (len > 0) {
3829 	    char *end = "\n";
3830 
3831 	    if (msg[len - 1] != ';') {
3832 		end = ";\n";
3833 	    }
3834 	    fprintf(d->trace, "%s%s", msg, end);
3835 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
3836 	    s = et / 1000000000LL;
3837 	    f = et % 1000000000LL;
3838 	    fprintf(d->trace, "-- took %lu.%09lu seconds\n", s, f);
3839 #endif
3840 	    fflush(d->trace);
3841 	}
3842     }
3843 }
3844 
3845 /**
3846  * Trace function for SQLite API calls
3847  * @param d pointer to database connection handle
3848  * @param fn SQLite function name
3849  * @param sql SQL string
3850  */
3851 
3852 static void
dbtraceapi(DBC * d,char * fn,const char * sql)3853 dbtraceapi(DBC *d, char *fn, const char *sql)
3854 {
3855     if (fn && d->trace) {
3856 	if (sql) {
3857 	    fprintf(d->trace, "-- %s: %s\n", fn, sql);
3858 	} else {
3859 	    fprintf(d->trace, "-- %s\n", fn);
3860 	}
3861 	fflush(d->trace);
3862     }
3863 }
3864 
3865 /**
3866  * Trace function for SQLite return codes
3867  * @param d pointer to database connection handle
3868  * @param rc SQLite return code
3869  * @param err error string or NULL
3870  */
3871 
3872 static void
dbtracerc(DBC * d,int rc,char * err)3873 dbtracerc(DBC *d, int rc, char *err)
3874 {
3875     if (rc != SQLITE_OK && d->trace) {
3876 	fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
3877 	fprintf(d->trace, err ? ": %s\n" : "\n", err);
3878 	fflush(d->trace);
3879     }
3880 }
3881 
3882 /**
3883  * Open SQLite database file given file name and flags.
3884  * @param d DBC pointer
3885  * @param name file name
3886  * @param isu true/false: file name is UTF8 encoded
3887  * @param dsn data source name
3888  * @param sflag STEPAPI flag
3889  * @param spflag SyncPragma string
3890  * @param ntflag NoTransaction string
3891  * @param jmode JournalMode string
3892  * @param busy busy/lock timeout
3893  * @result ODBC error code
3894  */
3895 
3896 static SQLRETURN
dbopen(DBC * d,char * name,int isu,char * dsn,char * sflag,char * spflag,char * ntflag,char * jmode,char * busy)3897 dbopen(DBC *d, char *name, int isu, char *dsn, char *sflag,
3898        char *spflag, char *ntflag, char *jmode, char *busy)
3899 {
3900     char *endp = NULL;
3901     int rc, tmp, busyto = 100000;
3902 #if defined(HAVE_SQLITE3VFS) && (HAVE_SQLITE3VFS)
3903     int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
3904     char *uname = name;
3905     const char *vfs_name = NULL;
3906 #endif
3907 
3908     if (d->sqlite) {
3909 	if (d->trace) {
3910 	    fprintf(d->trace, "-- sqlite3_close (deferred): '%s'\n",
3911 		    d->dbname);
3912 	    fflush(d->trace);
3913 	}
3914 #if defined(HAVE_SQLITE3CLOSEV2) && (HAVE_SQLITE3CLOSEV2)
3915 	sqlite3_close_v2(d->sqlite);
3916 #else
3917 	sqlite3_close(d->sqlite);
3918 #endif
3919 	d->sqlite = NULL;
3920     }
3921 #if defined(HAVE_SQLITE3VFS) && (HAVE_SQLITE3VFS)
3922     if (d->nocreat) {
3923 	flags &= ~ SQLITE_OPEN_CREATE;
3924     }
3925 #if defined(_WIN32) || defined(_WIN64)
3926     if (!isu) {
3927 	char expname[SQL_MAX_MESSAGE_LENGTH * 2];
3928 
3929 	expname[0] = '\0';
3930 	rc = ExpandEnvironmentStrings(name, expname, sizeof (expname));
3931 	if (rc <= sizeof (expname)) {
3932 	    uname = wmb_to_utf(expname, rc - 1);
3933 	} else {
3934 	    uname = wmb_to_utf(name, -1);
3935 	}
3936 	if (!uname) {
3937 	    rc = SQLITE_NOMEM;
3938 	    setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
3939 	    return SQL_ERROR;
3940 	}
3941     }
3942 #endif
3943 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
3944     vfs_name = nvfs_makevfs(uname);
3945 #endif
3946 #ifdef SQLITE_OPEN_URI
3947     flags |= SQLITE_OPEN_URI;
3948 #endif
3949     rc = sqlite3_open_v2(uname, &d->sqlite, flags, vfs_name);
3950 #if defined(WINTERFACE) || defined(_WIN32) || defined(_WIN64)
3951     if (uname != name) {
3952 	uc_free(uname);
3953     }
3954 #endif
3955 #else
3956 #if defined(_WIN32) || defined(_WIN64)
3957     if (d->nocreat) {
3958 	char *cname = NULL;
3959 
3960 	if (isu) {
3961 	    cname = utf_to_wmb(name, -1);
3962 	}
3963 	if (GetFileAttributesA(cname ? cname : name) ==
3964 	    INVALID_FILE_ATTRIBUTES) {
3965 	    uc_free(cname);
3966 	    rc = SQLITE_CANTOPEN;
3967 	    setstatd(d, rc, "cannot open database",
3968 		     (*d->ov3) ? "HY000" : "S1000");
3969 	    return SQL_ERROR;
3970 	}
3971 	uc_free(cname);
3972     }
3973 #else
3974     if (d->nocreat && access(name, 004) < 0) {
3975 	rc = SQLITE_CANTOPEN;
3976 	setstatd(d, rc, "cannot open database", (*d->ov3) ? "HY000" : "S1000");
3977 	return SQL_ERROR;
3978     }
3979 #endif
3980 #if defined(_WIN32) || defined(_WIN64)
3981     if (!isu) {
3982 	WCHAR *wname = wmb_to_uc(name, -1);
3983 
3984 	if (!wname) {
3985 	    rc = SQLITE_NOMEM;
3986 	    setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
3987 	    return SQL_ERROR;
3988 	}
3989 	rc = sqlite3_open16(wname, &d->sqlite);
3990 	uc_free(wname);
3991     } else
3992 #endif
3993     rc = sqlite3_open(name, &d->sqlite);
3994 #endif /* !HAVE_SQLITE3VFS */
3995     if (rc != SQLITE_OK) {
3996 connfail:
3997 	setstatd(d, rc, "connect failed", (*d->ov3) ? "HY000" : "S1000");
3998 	if (d->sqlite) {
3999 	    sqlite3_close(d->sqlite);
4000 	    d->sqlite = NULL;
4001 	}
4002 	return SQL_ERROR;
4003     }
4004 #if defined(SQLITE_DYNLOAD) || defined(SQLITE_HAS_CODEC)
4005     if (d->pwd) {
4006 	sqlite3_key(d->sqlite, d->pwd, d->pwdLen);
4007     }
4008 #endif
4009     d->pwd = NULL;
4010     d->pwdLen = 0;
4011     if (d->trace) {
4012 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
4013 	sqlite3_profile(d->sqlite, dbtrace, d);
4014 #else
4015 	sqlite3_trace(d->sqlite, dbtrace, d);
4016 #endif
4017     }
4018     d->step_enable = getbool(sflag);
4019     d->trans_disable = getbool(ntflag);
4020     d->curtype = d->step_enable ?
4021 	SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
4022     tmp = strtol(busy, &endp, 0);
4023     if (endp && *endp == '\0' && endp != busy) {
4024 	busyto = tmp;
4025     }
4026     if (busyto < 1 || busyto > 1000000) {
4027 	busyto = 1000000;
4028     }
4029     d->timeout = busyto;
4030     freep(&d->dbname);
4031     d->dbname = xstrdup(name);
4032     freep(&d->dsn);
4033     d->dsn = xstrdup(dsn);
4034     if ((rc = setsqliteopts(d->sqlite, d)) != SQLITE_OK) {
4035 	if (d->trace) {
4036 	    fprintf(d->trace, "-- sqlite3_close: '%s'\n",
4037 		    d->dbname);
4038 	    fflush(d->trace);
4039 	}
4040 	sqlite3_close(d->sqlite);
4041 	d->sqlite = NULL;
4042 	goto connfail;
4043     }
4044     if (!spflag || spflag[0] == '\0') {
4045 	spflag = "NORMAL";
4046     }
4047     if (spflag[0] != '\0') {
4048 	char syncp[128];
4049 
4050 	sprintf(syncp, "PRAGMA synchronous = %8.8s;", spflag);
4051 	sqlite3_exec(d->sqlite, syncp, NULL, NULL, NULL);
4052     }
4053     if (jmode[0] != '\0') {
4054 	char jourp[128];
4055 
4056 	sprintf(jourp, "PRAGMA journal_mode = %16.16s;", jmode);
4057 	sqlite3_exec(d->sqlite, jourp, NULL, NULL, NULL);
4058     }
4059     if (d->trace) {
4060 	fprintf(d->trace, "-- sqlite3_open: '%s'\n", d->dbname);
4061 	fflush(d->trace);
4062     }
4063 #if defined(_WIN32) || defined(_WIN64)
4064     {
4065 	char pname[MAX_PATH];
4066 	HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4067 			       FALSE, GetCurrentProcessId());
4068 
4069 	pname[0] = '\0';
4070 	if (h) {
4071 	    HMODULE m = NULL, l = LoadLibrary("psapi.dll");
4072 	    DWORD need;
4073 	    typedef BOOL (WINAPI *epmfunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
4074 	    typedef BOOL (WINAPI *gmbfunc)(HANDLE, HMODULE, LPSTR, DWORD);
4075 	    epmfunc epm;
4076 	    gmbfunc gmb;
4077 
4078 	    if (l) {
4079 		epm = (epmfunc) GetProcAddress(l, "EnumProcessModules");
4080 		gmb = (gmbfunc) GetProcAddress(l, "GetModuleBaseNameA");
4081 		if (epm && gmb && epm(h, &m, sizeof (m), &need)) {
4082 		    gmb(h, m, pname, sizeof (pname));
4083 		}
4084 		FreeLibrary(l);
4085 	    }
4086 	    CloseHandle(h);
4087 	}
4088 	d->xcelqrx = strncasecmp(pname, "EXCEL", 5) == 0 ||
4089 		     strncasecmp(pname, "MSQRY", 5) == 0;
4090 	if (d->trace && d->xcelqrx) {
4091 
4092 	    fprintf(d->trace, "-- enabled EXCEL quirks\n");
4093 	    fflush(d->trace);
4094 	}
4095     }
4096 #endif
4097     sqlite3_create_function(d->sqlite, "blob_import", 1, SQLITE_UTF8,
4098 			    d, blob_import, 0, 0);
4099     sqlite3_create_function(d->sqlite, "blob_export", 2, SQLITE_UTF8,
4100 			    d, blob_export, 0, 0);
4101     return SQL_SUCCESS;
4102 }
4103 
4104 /**
4105  * Load SQLite extension modules, if any
4106  * @param d DBC pointer
4107  * @param exts string, comma separated extension names
4108  */
4109 
4110 static void
dbloadext(DBC * d,char * exts)4111 dbloadext(DBC *d, char *exts)
4112 {
4113 #if defined(HAVE_SQLITE3LOADEXTENSION) && (HAVE_SQLITE3LOADEXTENSION)
4114     char *p;
4115     char path[SQL_MAX_MESSAGE_LENGTH];
4116     int plen = 0;
4117 
4118     if (!d->sqlite) {
4119 	return;
4120     }
4121     sqlite3_enable_load_extension(d->sqlite, 1);
4122 #if defined(_WIN32) || defined(_WIN64)
4123     GetModuleFileName(hModule, path, sizeof (path));
4124     p = strrchr(path, '\\');
4125     plen = p ? ((p + 1) - path) : 0;
4126 #endif
4127     do {
4128 	p = strchr(exts, ',');
4129 	if (p) {
4130 	    strncpy(path + plen, exts, p - exts);
4131 	    path[plen + (p - exts)] = '\0';
4132 	} else {
4133 	    strcpy(path + plen, exts);
4134 	}
4135 	if (exts[0]) {
4136 	    char *errmsg = NULL;
4137 	    int rc;
4138 #if defined(_WIN32) || defined(_WIN64)
4139 	    int i;
4140 	    char *q;
4141 
4142 	    q = path + plen;
4143 	    if (!(q[0] &&
4144 		  ((q[1] == ':' && (q[2] == '\\' || q[2] == '/')) ||
4145 		   q[0] == '\\' || q[0] == '/' || q[0] == '.'))) {
4146 		q = path;
4147 	    }
4148 	    /* sqlite3_load_extension() dislikes backslashes */
4149 	    for (i = 0; q[i] != '\0'; i++) {
4150 		if (q[i] == '\\') {
4151 		    q[i] = '/';
4152 		}
4153 	    }
4154 	    rc = sqlite3_load_extension(d->sqlite, q, 0, &errmsg);
4155 #else
4156 	    rc = sqlite3_load_extension(d->sqlite, path, 0, &errmsg);
4157 #endif
4158 	    if (rc != SQLITE_OK) {
4159 #if defined(_WIN32) || defined(_WIN64)
4160 		char buf[512], msg[512];
4161 
4162 		LoadString(hModule, IDS_EXTERR, buf, sizeof (buf));
4163 		wsprintf(msg, buf, q, errmsg ?
4164 			 errmsg : "no error info available");
4165 		LoadString(hModule, IDS_EXTTITLE, buf, sizeof (buf));
4166 		MessageBox(NULL, msg, buf,
4167 			   MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
4168 			   MB_SETFOREGROUND);
4169 #else
4170 		fprintf(stderr, "extension '%s' did not load%s%s\n",
4171 			path, errmsg ? ": " : "", errmsg ? errmsg : "");
4172 #endif
4173 	    }
4174 	}
4175 	if (p) {
4176 	    exts = p + 1;
4177 	}
4178     } while (p);
4179 #endif /* HAVE_SQLITE3LOADEXTENSION */
4180 }
4181 
4182 /**
4183  * Find out column type
4184  * @param s3stmt SQLite statement pointer
4185  * @param col column number
4186  * @param d DBC pointer (for tracing only)
4187  * @param guessed_types flag array
4188  * @result type name as string
4189  */
4190 
4191 static char *
s3stmt_coltype(sqlite3_stmt * s3stmt,int col,DBC * d,int * guessed_types)4192 s3stmt_coltype(sqlite3_stmt *s3stmt, int col, DBC *d, int *guessed_types)
4193 {
4194     char *typename = (char *) sqlite3_column_decltype(s3stmt, col);
4195     char guess[64];
4196 
4197     guess[0] = '\0';
4198     if (!typename) {
4199 	int coltype = sqlite3_column_type(s3stmt, col);
4200 
4201 	if (guessed_types) {
4202 	    guessed_types[0]++;
4203 	}
4204 	if (d->trace) {
4205 	    sprintf(guess, " (guessed from %d)", coltype);
4206 	}
4207 	switch (coltype) {
4208 	case SQLITE_INTEGER: typename = "integer"; break;
4209 	case SQLITE_FLOAT:   typename = "double";  break;
4210 	default:
4211 	case SQLITE_TEXT:    typename = "varchar"; break;
4212 	case SQLITE_BLOB:    typename = "blob";    break;
4213 #if 0
4214 	case SQLITE_NULL:    typename = "null";    break;
4215 #endif
4216 	}
4217     }
4218     if (d->trace) {
4219 	fprintf(d->trace, "-- column %d type%s: '%s'\n", col + 1,
4220 		guess, typename);
4221 	fflush(d->trace);
4222     }
4223     return typename;
4224 }
4225 
4226 #ifdef FULL_METADATA
4227 
4228 /**
4229  * Add meta data for column
4230  * @param s3stmt SQLite statement pointer
4231  * @param col column number
4232  * @param d DBC pointer (for tracing only)
4233  * @param ci pointer to COL
4234  */
4235 
4236 static void
s3stmt_addmeta(sqlite3_stmt * s3stmt,int col,DBC * d,COL * ci)4237 s3stmt_addmeta(sqlite3_stmt *s3stmt, int col, DBC *d, COL *ci)
4238 {
4239     int nn = 0, pk = 0, ai = 0;
4240     const char *dn = NULL, *tn = NULL, *cn = NULL, *dummy[4];
4241 
4242     dn = sqlite3_column_database_name(s3stmt, col);
4243     tn = sqlite3_column_table_name(s3stmt, col);
4244     cn = sqlite3_column_origin_name(s3stmt, col);
4245     dummy[0] = dummy[1] = 0;
4246     if (tn && cn) {
4247 	sqlite3_table_column_metadata(d->sqlite, dn, tn, cn,
4248 				      dummy, dummy + 1,
4249 				      &nn, &pk, &ai);
4250     }
4251     ci->autoinc = ai ? SQL_TRUE: SQL_FALSE;
4252     ci->notnull = nn ? SQL_NO_NULLS : SQL_NULLABLE;
4253     ci->ispk = pk ? 1 : 0;
4254     if (d->trace) {
4255 	fprintf(d->trace, "-- column %d %s\n",
4256 		col + 1, nn ? "notnull" : "nullable");
4257 	if (ai) {
4258 	    fprintf(d->trace, "-- column %d autoincrement\n", col + 1);
4259 	}
4260 	fflush(d->trace);
4261     }
4262     ci->isrowid = 0;
4263     if (ci->ispk && tn) {
4264 	nn = pk = ai = 0;
4265 	dummy[2] = dummy[3] = 0;
4266 
4267 	sqlite3_table_column_metadata(d->sqlite, dn, tn, "rowid",
4268 				      dummy + 2, dummy + 3,
4269 				      &nn, &pk, &ai);
4270 	if (pk && dummy[0] && dummy[0] == dummy[2]) {
4271 	    ci->isrowid = 1;
4272 	}
4273     }
4274 }
4275 
4276 #endif
4277 
4278 /**
4279  * Do one sqlite statement step gathering one result row
4280  * @param s statement pointer
4281  * @result ODBC error code
4282  */
4283 
4284 static int
s3stmt_step(STMT * s)4285 s3stmt_step(STMT *s)
4286 {
4287     DBC *d = (DBC *) s->dbc;
4288     char **rowd = NULL;
4289     const char *errp = NULL;
4290     int i, ncols, rc;
4291 
4292     if (s != d->cur_s3stmt || !s->s3stmt) {
4293 	setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
4294 	return SQL_ERROR;
4295     }
4296     rc = sqlite3_step(s->s3stmt);
4297     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
4298 	++s->s3stmt_rownum;
4299 	ncols = sqlite3_column_count(s->s3stmt);
4300 	if (d->s3stmt_needmeta && s->s3stmt_rownum == 0 && ncols > 0) {
4301 	    PTRDIFF_T size;
4302 	    char *p;
4303 	    COL *dyncols;
4304 	    const char *colname, *typename;
4305 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
4306 	    char *tblname;
4307 #endif
4308 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
4309 	    char *dbname;
4310 #endif
4311 
4312 	    for (i = size = 0; i < ncols; i++) {
4313 		colname = sqlite3_column_name(s->s3stmt, i);
4314 		size += 3 + 3 * strlen(colname);
4315 	    }
4316 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
4317 	    tblname = (char *) size;
4318 	    for (i = 0; i < ncols; i++) {
4319 		p = (char *) sqlite3_column_table_name(s->s3stmt, i);
4320 		size += 2 + (p ? strlen(p) : 0);
4321 	    }
4322 #endif
4323 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
4324 	    dbname = (char *) size;
4325 	    for (i = 0; i < ncols; i++) {
4326 		p = (char *) sqlite3_column_database_name(s->s3stmt, i);
4327 		size += 2 + (p ? strlen(p) : 0);
4328 	    }
4329 #endif
4330 	    dyncols = xmalloc(ncols * sizeof (COL) + size);
4331 	    if (!dyncols) {
4332 		freedyncols(s);
4333 		s->ncols = 0;
4334 		dbtraceapi(d, "sqlite3_finalize", 0);
4335 		sqlite3_finalize(s->s3stmt);
4336 		s->s3stmt = NULL;
4337 		d->cur_s3stmt = NULL;
4338 		return nomem(s);
4339 	    }
4340 	    p = (char *) (dyncols + ncols);
4341 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
4342 	    tblname = p + (PTRDIFF_T) tblname;
4343 #endif
4344 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
4345 	    dbname = p + (PTRDIFF_T) dbname;
4346 #endif
4347 	    for (i = 0; i < ncols; i++) {
4348 		char *q;
4349 
4350 		colname = sqlite3_column_name(s->s3stmt, i);
4351 		if (d->trace) {
4352 		    fprintf(d->trace, "-- column %d name: '%s'\n",
4353 			    i + 1, colname);
4354 		    fflush(d->trace);
4355 		}
4356 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
4357 		q = (char *) sqlite3_column_table_name(s->s3stmt, i);
4358 		strcpy(tblname, q ? q : "");
4359 		if (d->trace) {
4360 		    fprintf(d->trace, "-- table %d name: '%s'\n",
4361 			    i + 1, tblname);
4362 		    fflush(d->trace);
4363 		}
4364 		dyncols[i].table = tblname;
4365 		tblname += strlen(tblname) + 1;
4366 #endif
4367 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
4368 		q = (char *) sqlite3_column_database_name(s->s3stmt, i);
4369 		strcpy(dbname, q ? q : "");
4370 		if (d->trace) {
4371 		    fprintf(d->trace, "-- database %d name: '%s'\n",
4372 			    i + 1, dbname);
4373 		    fflush(d->trace);
4374 		}
4375 		dyncols[i].db = dbname;
4376 		dbname += strlen(dbname) + 1;
4377 #else
4378 		dyncols[i].db = ((DBC *) (s->dbc))->dbname;
4379 #endif
4380 		typename = s3stmt_coltype(s->s3stmt, i, d, 0);
4381 		strcpy(p, colname);
4382 		dyncols[i].label = p;
4383 		p += strlen(p) + 1;
4384 		q = strchr(colname, '.');
4385 		if (q) {
4386 		    char *q2 = strchr(q + 1, '.');
4387 
4388 		    /* SQLite 3.3.4 produces view.table.column sometimes */
4389 		    if (q2) {
4390 			q = q2;
4391 		    }
4392 		}
4393 		if (q) {
4394 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
4395 		    dyncols[i].table = p;
4396 #endif
4397 		    strncpy(p, colname, q - colname);
4398 		    p[q - colname] = '\0';
4399 		    p += strlen(p) + 1;
4400 		    strcpy(p, q + 1);
4401 		    dyncols[i].column = p;
4402 		    p += strlen(p) + 1;
4403 		} else {
4404 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
4405 		    dyncols[i].table = "";
4406 #endif
4407 		    strcpy(p, colname);
4408 		    dyncols[i].column = p;
4409 		    p += strlen(p) + 1;
4410 		}
4411 		if (s->longnames) {
4412 		    dyncols[i].column = dyncols[i].label;
4413 		}
4414 #ifdef SQL_LONGVARCHAR
4415 		dyncols[i].type = SQL_LONGVARCHAR;
4416 		dyncols[i].size = 65535;
4417 #else
4418 		dyncols[i].type = SQL_VARCHAR;
4419 		dyncols[i].size = 255;
4420 #endif
4421 		dyncols[i].index = i;
4422 		dyncols[i].scale = 0;
4423 		dyncols[i].prec = 0;
4424 		dyncols[i].nosign = 1;
4425 		dyncols[i].autoinc = SQL_FALSE;
4426 		dyncols[i].notnull = SQL_NULLABLE;
4427 		dyncols[i].ispk = -1;
4428 		dyncols[i].isrowid = -1;
4429 #ifdef FULL_METADATA
4430 		s3stmt_addmeta(s->s3stmt, i, d, &dyncols[i]);
4431 #endif
4432 		dyncols[i].typename = xstrdup(typename);
4433 	    }
4434 	    freedyncols(s);
4435 	    s->ncols = s->dcols = ncols;
4436 	    s->dyncols = s->cols = dyncols;
4437 	    fixupdyncols(s, d);
4438 	    mkbindcols(s, s->ncols);
4439 	    d->s3stmt_needmeta = 0;
4440 	}
4441 	if (ncols <= 0) {
4442 	    goto killstmt;
4443 	}
4444 	if (rc == SQLITE_DONE) {
4445 	    freeresult(s, 0);
4446 	    s->nrows = 0;
4447 	    dbtraceapi(d, "sqlite3_finalize", 0);
4448 	    sqlite3_finalize(s->s3stmt);
4449 	    s->s3stmt = NULL;
4450 	    d->cur_s3stmt = NULL;
4451 	    return SQL_SUCCESS;
4452 	}
4453 	rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
4454 	if (rowd) {
4455 	    const unsigned char *value;
4456 
4457 	    rowd[0] = (char *) ((PTRDIFF_T) (ncols * 2));
4458 	    ++rowd;
4459 	    for (i = 0; i < ncols; i++) {
4460 		int coltype = sqlite3_column_type(s->s3stmt, i);
4461 
4462 		rowd[i] = rowd[i + ncols] = NULL;
4463 		if (coltype == SQLITE_BLOB) {
4464 		    int k, nbytes = sqlite3_column_bytes(s->s3stmt, i);
4465 		    char *qp;
4466 		    unsigned const char *bp;
4467 
4468 		    bp = sqlite3_column_blob(s->s3stmt, i);
4469 		    qp = xmalloc(nbytes * 2 + 4);
4470 		    if (qp) {
4471 			rowd[i + ncols] = qp;
4472 			*qp++ = 'X';
4473 			*qp++ = '\'';
4474 			for (k = 0; k < nbytes; k++) {
4475 			    *qp++ = xdigits[(bp[k] >> 4)];
4476 			    *qp++ = xdigits[(bp[k] & 0xF)];
4477 			}
4478 			*qp++ = '\'';
4479 			*qp = '\0';
4480 		    }
4481 #ifdef _MSC_VER
4482 		} else if (coltype == SQLITE_FLOAT) {
4483 		    struct lconv *lc = 0;
4484 		    double d = sqlite3_column_double(s->s3stmt, i);
4485 		    char *p, buffer[128];
4486 
4487 		    /*
4488 		     * This avoids floating point rounding
4489 		     * and formatting problems of some SQLite
4490 		     * versions in conjunction with MSVC 2010.
4491 		     */
4492 		    snprintf(buffer, sizeof (buffer), "%.15g", d);
4493 		    lc = localeconv();
4494 		    if (lc && lc->decimal_point && lc->decimal_point[0] &&
4495 			lc->decimal_point[0] != '.') {
4496 			p = strchr(buffer, lc->decimal_point[0]);
4497 			if (p) {
4498 			    *p = '.';
4499 			}
4500 		    }
4501 		    rowd[i + ncols] = xstrdup(buffer);
4502 #endif
4503 		} else if (coltype != SQLITE_NULL) {
4504 		    value = sqlite3_column_text(s->s3stmt, i);
4505 		    rowd[i + ncols] = xstrdup((char *) value);
4506 		}
4507 	    }
4508 	    for (i = 0; i < ncols; i++) {
4509 		int coltype = sqlite3_column_type(s->s3stmt, i);
4510 
4511 		value = NULL;
4512 		if (coltype == SQLITE_BLOB) {
4513 		    value = sqlite3_column_blob(s->s3stmt, i);
4514 		} else if (coltype != SQLITE_NULL) {
4515 		    value = sqlite3_column_text(s->s3stmt, i);
4516 		}
4517 		if (value && !rowd[i + ncols]) {
4518 		    freerows(rowd);
4519 		    rowd = 0;
4520 		    break;
4521 		}
4522 	    }
4523 	}
4524 	if (rowd) {
4525 	    freeresult(s, 0);
4526 	    s->nrows = 1;
4527 	    s->rows = rowd;
4528 	    s->rowfree = freerows;
4529 	    if (rc == SQLITE_DONE) {
4530 		dbtraceapi(d, "sqlite3_finalize", 0);
4531 		sqlite3_finalize(s->s3stmt);
4532 		s->s3stmt = NULL;
4533 		d->cur_s3stmt = NULL;
4534 	    }
4535 	    return SQL_SUCCESS;
4536 	}
4537     }
4538 killstmt:
4539     dbtraceapi(d, "sqlite3_reset", 0);
4540     rc = sqlite3_reset(s->s3stmt);
4541     s->s3stmt_noreset = 1;
4542     errp = sqlite3_errmsg(d->sqlite);
4543     if (d->cur_s3stmt == s) {
4544 	d->cur_s3stmt = NULL;
4545     }
4546     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
4547 	    errp ? errp : "unknown error", rc);
4548     return SQL_ERROR;
4549 }
4550 
4551 /**
4552  * Stop running sqlite statement
4553  * @param s statement pointer
4554  */
4555 
4556 static void
s3stmt_end(STMT * s)4557 s3stmt_end(STMT *s)
4558 {
4559     DBC *d;
4560 
4561     if (!s || !s->s3stmt) {
4562 	return;
4563     }
4564     d = (DBC *) s->dbc;
4565     if (d) {
4566 	d->busyint = 0;
4567     }
4568     if (!s->s3stmt_noreset) {
4569 	dbtraceapi(d, "sqlite3_reset", 0);
4570 	sqlite3_reset(s->s3stmt);
4571 	s->s3stmt_noreset = 1;
4572 	s->s3stmt_rownum = -1;
4573     }
4574     if (d->cur_s3stmt == s) {
4575 	d->cur_s3stmt = NULL;
4576     }
4577 }
4578 
4579 /**
4580  * Conditionally stop running sqlite statement
4581  * @param s statement pointer
4582  */
4583 
4584 static void
s3stmt_end_if(STMT * s)4585 s3stmt_end_if(STMT *s)
4586 {
4587     DBC *d = (DBC *) s->dbc;
4588 
4589     if (d) {
4590 	d->busyint = 0;
4591     }
4592     if (d && d->cur_s3stmt == s) {
4593 	s3stmt_end(s);
4594     }
4595 }
4596 
4597 /**
4598  * Drop running sqlite statement in STMT
4599  * @param s statement pointer
4600  */
4601 
4602 static void
s3stmt_drop(STMT * s)4603 s3stmt_drop(STMT *s)
4604 {
4605     if (s->s3stmt) {
4606 	DBC *d = (DBC *) s->dbc;
4607 
4608 	if (d) {
4609 	    dbtraceapi(d, "sqlite3_finalize", 0);
4610 	}
4611 	sqlite3_finalize(s->s3stmt);
4612 	s->s3stmt = NULL;
4613 	s->s3stmt_rownum = 0;
4614     }
4615 }
4616 
4617 /**
4618  * Start sqlite statement for execution of SELECT statement.
4619  * @param s statement pointer
4620  * @result ODBC error code
4621  */
4622 
4623 static SQLRETURN
s3stmt_start(STMT * s)4624 s3stmt_start(STMT *s)
4625 {
4626     DBC *d = (DBC *) s->dbc;
4627     const char *endp;
4628     sqlite3_stmt *s3stmt = NULL;
4629     int rc, nretry = 0;
4630 
4631     d->s3stmt_needmeta = 0;
4632     if (!s->s3stmt) {
4633 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
4634 	dbtraceapi(d, "sqlite3_prepare_v2", (char *) s->query);
4635 #else
4636 	dbtraceapi(d, "sqlite3_prepare", (char *) s->query);
4637 #endif
4638 	do {
4639 	    s3stmt = NULL;
4640 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
4641 	    rc = sqlite3_prepare_v2(d->sqlite, (char *) s->query, -1,
4642 				    &s3stmt, &endp);
4643 #else
4644 	    rc = sqlite3_prepare(d->sqlite, (char *) s->query, -1,
4645 				 &s3stmt, &endp);
4646 #endif
4647 	    if (rc != SQLITE_OK) {
4648 		if (s3stmt) {
4649 		    sqlite3_finalize(s3stmt);
4650 		    s3stmt = NULL;
4651 		}
4652 	    }
4653 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
4654 	dbtracerc(d, rc, NULL);
4655 	if (rc != SQLITE_OK) {
4656 	    if (s3stmt) {
4657 		dbtraceapi(d, "sqlite3_finalize", NULL);
4658 		sqlite3_finalize(s3stmt);
4659 	    }
4660 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
4661 		    sqlite3_errmsg(d->sqlite), rc);
4662 	    return SQL_ERROR;
4663 	}
4664 	if (sqlite3_bind_parameter_count(s3stmt) != s->nparams) {
4665 	    dbtraceapi(d, "sqlite3_finalize", 0);
4666 	    sqlite3_finalize(s3stmt);
4667 	    setstat(s, SQLITE_ERROR, "parameter marker count incorrect",
4668 		    (*s->ov3) ? "HY000" : "S1000");
4669 	    return SQL_ERROR;
4670 	}
4671 	s->s3stmt = s3stmt;
4672 	s->s3stmt_noreset = 1;
4673 	d->s3stmt_needmeta = 1;
4674     }
4675     d->cur_s3stmt = s;
4676     s->s3stmt_rownum = -1;
4677     s3bind(d, s->s3stmt, s->nparams, s->bindparms);
4678     return SQL_SUCCESS;
4679 }
4680 
4681 #ifndef WINTERFACE
4682 /**
4683  * Function not implemented.
4684  */
4685 
4686 SQLRETURN SQL_API
SQLDataSources(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)4687 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
4688 	       SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
4689 	       SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
4690 {
4691     if (env == SQL_NULL_HENV) {
4692 	return SQL_INVALID_HANDLE;
4693     }
4694     return SQL_ERROR;
4695 }
4696 #endif
4697 
4698 #ifdef WINTERFACE
4699 /**
4700  * Function not implemented.
4701  */
4702 
4703 SQLRETURN SQL_API
SQLDataSourcesW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLWCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)4704 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
4705 		SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
4706 		SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
4707 {
4708     if (env == SQL_NULL_HENV) {
4709 	return SQL_INVALID_HANDLE;
4710     }
4711     return SQL_ERROR;
4712 }
4713 #endif
4714 
4715 #ifndef WINTERFACE
4716 /**
4717  * Function not implemented.
4718  */
4719 
4720 SQLRETURN SQL_API
SQLDrivers(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)4721 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
4722 	   SQLSMALLINT descmax, SQLSMALLINT *desclenp,
4723 	   SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
4724 {
4725     if (env == SQL_NULL_HENV) {
4726 	return SQL_INVALID_HANDLE;
4727     }
4728     return SQL_ERROR;
4729 }
4730 #endif
4731 
4732 #ifdef WINTERFACE
4733 /**
4734  * Function not implemented.
4735  */
4736 
4737 SQLRETURN SQL_API
SQLDriversW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLWCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)4738 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
4739 	    SQLSMALLINT descmax, SQLSMALLINT *desclenp,
4740 	    SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
4741 {
4742     if (env == SQL_NULL_HENV) {
4743 	return SQL_INVALID_HANDLE;
4744     }
4745     return SQL_ERROR;
4746 }
4747 #endif
4748 
4749 #ifndef WINTERFACE
4750 /**
4751  * Function not implemented.
4752  */
4753 
4754 SQLRETURN SQL_API
SQLBrowseConnect(SQLHDBC dbc,SQLCHAR * connin,SQLSMALLINT conninLen,SQLCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)4755 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
4756 		 SQLCHAR *connout, SQLSMALLINT connoutMax,
4757 		 SQLSMALLINT *connoutLen)
4758 {
4759     SQLRETURN ret;
4760 
4761     HDBC_LOCK(dbc);
4762     ret = drvunimpldbc(dbc);
4763     HDBC_UNLOCK(dbc);
4764     return ret;
4765 }
4766 #endif
4767 
4768 #ifdef WINTERFACE
4769 /**
4770  * Function not implemented.
4771  */
4772 
4773 SQLRETURN SQL_API
SQLBrowseConnectW(SQLHDBC dbc,SQLWCHAR * connin,SQLSMALLINT conninLen,SQLWCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)4774 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
4775 		  SQLWCHAR *connout, SQLSMALLINT connoutMax,
4776 		  SQLSMALLINT *connoutLen)
4777 {
4778     SQLRETURN ret;
4779 
4780     HDBC_LOCK(dbc);
4781     ret = drvunimpldbc(dbc);
4782     HDBC_UNLOCK(dbc);
4783     return ret;
4784 }
4785 #endif
4786 
4787 /**
4788  * Internal put (partial) parameter data into executing statement.
4789  * @param stmt statement handle
4790  * @param data pointer to data
4791  * @param len length of data
4792  * @result ODBC error code
4793  */
4794 
4795 static SQLRETURN
drvputdata(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)4796 drvputdata(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
4797 {
4798     STMT *s;
4799     int i, dlen, done = 0;
4800     BINDPARM *p;
4801 
4802     if (stmt == SQL_NULL_HSTMT) {
4803 	return SQL_INVALID_HANDLE;
4804     }
4805     s = (STMT *) stmt;
4806     if (!s->query || s->nparams <= 0) {
4807 seqerr:
4808 	setstat(s, -1, "sequence error", "HY010");
4809 	return SQL_ERROR;
4810     }
4811     for (i = (s->pdcount < 0) ? 0 : s->pdcount; i < s->nparams; i++) {
4812 	p = &s->bindparms[i];
4813 	if (p->need > 0) {
4814 	    int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
4815 
4816 	    if (len == SQL_NULL_DATA) {
4817 		freep(&p->parbuf);
4818 		p->param = NULL;
4819 		p->len = SQL_NULL_DATA;
4820 		p->need = -1;
4821 	    } else if (type != SQL_C_CHAR
4822 #ifdef WCHARSUPPORT
4823 		       && type != SQL_C_WCHAR
4824 #endif
4825 		       && type != SQL_C_BINARY) {
4826 		int size = 0;
4827 
4828 		switch (type) {
4829 		case SQL_C_TINYINT:
4830 		case SQL_C_UTINYINT:
4831 		case SQL_C_STINYINT:
4832 #ifdef SQL_BIT
4833 		case SQL_C_BIT:
4834 #endif
4835 		    size = sizeof (SQLCHAR);
4836 		    break;
4837 		case SQL_C_SHORT:
4838 		case SQL_C_USHORT:
4839 		case SQL_C_SSHORT:
4840 		    size = sizeof (SQLSMALLINT);
4841 		    break;
4842 		case SQL_C_LONG:
4843 		case SQL_C_ULONG:
4844 		case SQL_C_SLONG:
4845 		    size = sizeof (SQLINTEGER);
4846 		    break;
4847 #ifdef SQL_BIGINT
4848 		case SQL_C_UBIGINT:
4849 		case SQL_C_SBIGINT:
4850 		    size = sizeof (SQLBIGINT);
4851 		    break;
4852 #endif
4853 		case SQL_C_FLOAT:
4854 		    size = sizeof (float);
4855 		    break;
4856 		case SQL_C_DOUBLE:
4857 		    size = sizeof (double);
4858 		    break;
4859 #ifdef SQL_C_TYPE_DATE
4860 		case SQL_C_TYPE_DATE:
4861 #endif
4862 		case SQL_C_DATE:
4863 		    size = sizeof (DATE_STRUCT);
4864 		    break;
4865 #ifdef SQL_C_TYPE_DATE
4866 		case SQL_C_TYPE_TIME:
4867 #endif
4868 		case SQL_C_TIME:
4869 		    size = sizeof (TIME_STRUCT);
4870 		    break;
4871 #ifdef SQL_C_TYPE_DATE
4872 		case SQL_C_TYPE_TIMESTAMP:
4873 #endif
4874 		case SQL_C_TIMESTAMP:
4875 		    size = sizeof (TIMESTAMP_STRUCT);
4876 		    break;
4877 		}
4878 		freep(&p->parbuf);
4879 		p->parbuf = xmalloc(size);
4880 		if (!p->parbuf) {
4881 		    return nomem(s);
4882 		}
4883 		p->param = p->parbuf;
4884 		memcpy(p->param, data, size);
4885 		p->len = size;
4886 		p->need = -1;
4887 	    } else if (len == SQL_NTS && (
4888 		       type == SQL_C_CHAR
4889 #ifdef WCHARSUPPORT
4890 		       || type == SQL_C_WCHAR
4891 #endif
4892 		      )) {
4893 		char *dp = data;
4894 
4895 #ifdef WCHARSUPPORT
4896 		if (type == SQL_C_WCHAR) {
4897 		    dp = uc_to_utf(data, len);
4898 		    if (!dp) {
4899 			return nomem(s);
4900 		    }
4901 		}
4902 #endif
4903 #if defined(_WIN32) || defined(_WIN64)
4904 		if (*s->oemcp) {
4905 		    dp = wmb_to_utf(data, strlen (data));
4906 		    if (!dp) {
4907 			return nomem(s);
4908 		    }
4909 		}
4910 #endif
4911 		dlen = strlen(dp);
4912 		freep(&p->parbuf);
4913 		p->parbuf = xmalloc(dlen + 1);
4914 		if (!p->parbuf) {
4915 		    if (dp != data) {
4916 			uc_free(dp);
4917 		    }
4918 		    return nomem(s);
4919 		}
4920 		p->param = p->parbuf;
4921 		strcpy(p->param, dp);
4922 		if (dp != data) {
4923 		    uc_free(dp);
4924 		}
4925 		p->len = dlen;
4926 		p->need = -1;
4927 	    } else if (len < 0) {
4928 		setstat(s, -1, "invalid length", "HY090");
4929 		return SQL_ERROR;
4930 	    } else {
4931 		dlen = min(p->len - p->offs, len);
4932 		if (!p->param) {
4933 		    setstat(s, -1, "no memory for parameter", "HY013");
4934 		    return SQL_ERROR;
4935 		}
4936 		memcpy((char *) p->param + p->offs, data, dlen);
4937 		p->offs += dlen;
4938 		if (p->offs >= p->len) {
4939 #ifdef WCHARSUPPORT
4940 		    if (type == SQL_C_WCHAR) {
4941 			char *dp = uc_to_utf(p->param, p->len);
4942 			char *np;
4943 			int nlen;
4944 
4945 			if (!dp) {
4946 			    return nomem(s);
4947 			}
4948 			nlen = strlen(dp);
4949 			np = xmalloc(nlen + 1);
4950 			if (!np) {
4951 			    uc_free(dp);
4952 			    return nomem(s);
4953 			}
4954 			strcpy(np, dp);
4955 			uc_free(dp);
4956 			if (p->param == p->parbuf) {
4957 			    freep(&p->parbuf);
4958 			}
4959 			p->parbuf = p->param = np;
4960 			p->len = nlen;
4961 		    } else {
4962 			*((char *) p->param + p->len) = '\0';
4963 		    }
4964 		    p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR)
4965 			    ? -1 : 0;
4966 #else
4967 		    *((char *) p->param + p->len) = '\0';
4968 		    p->need = (type == SQL_C_CHAR) ? -1 : 0;
4969 #endif
4970 #if defined(_WIN32) || defined(_WIN64)
4971 		    if (type == SQL_C_CHAR && *s->oemcp &&
4972 			!(p->stype == SQL_BINARY ||
4973 			  p->stype == SQL_VARBINARY ||
4974 			  p->stype == SQL_LONGVARBINARY)) {
4975 			char *dp = wmb_to_utf(p->param, p->len);
4976 
4977 			if (!dp) {
4978 			    return nomem(s);
4979 			}
4980 			if (p->param == p->parbuf) {
4981 			    freep(&p->parbuf);
4982 			}
4983 			p->parbuf = p->param = dp;
4984 			p->len = strlen(dp);
4985 		    }
4986 		    if (p->type == SQL_C_WCHAR &&
4987 			(p->stype == SQL_VARCHAR ||
4988 			 p->stype == SQL_LONGVARCHAR) &&
4989 			 p->len == p->coldef * sizeof (SQLWCHAR)) {
4990 			/* fix for MS-Access */
4991 			p->len = p->coldef;
4992 		    }
4993 #endif
4994 		}
4995 	    }
4996 	    done = 1;
4997 	    break;
4998 	}
4999     }
5000     if (!done) {
5001 	goto seqerr;
5002     }
5003     return SQL_SUCCESS;
5004 }
5005 
5006 /**
5007  * Put (partial) parameter data into executing statement.
5008  * @param stmt statement handle
5009  * @param data pointer to data
5010  * @param len length of data
5011  * @result ODBC error code
5012  */
5013 
5014 SQLRETURN SQL_API
SQLPutData(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)5015 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
5016 {
5017     SQLRETURN ret;
5018 
5019     HSTMT_LOCK(stmt);
5020     ret = drvputdata(stmt, data, len);
5021     HSTMT_UNLOCK(stmt);
5022     return ret;
5023 }
5024 
5025 /**
5026  * Clear out parameter bindings, if any.
5027  * @param s statement pointer
5028  */
5029 
5030 static SQLRETURN
freeparams(STMT * s)5031 freeparams(STMT *s)
5032 {
5033     if (s->bindparms) {
5034 	int n;
5035 
5036 	for (n = 0; n < s->nbindparms; n++) {
5037 	    freep(&s->bindparms[n].parbuf);
5038 	    memset(&s->bindparms[n], 0, sizeof (BINDPARM));
5039 	}
5040     }
5041     return SQL_SUCCESS;
5042 }
5043 
5044 /**
5045  * Setup SQLite3 parameter for statement parameter.
5046  * @param s statement pointer
5047  * @param sql sql string
5048  * @param pnum parameter number
5049  * @result ODBC error code
5050  *
5051  * The parameter is converted within BINDPARM in order to
5052  * be presented to sqlite3_bind_*() functions.
5053  */
5054 
5055 static SQLRETURN
setupparam(STMT * s,char * sql,int pnum)5056 setupparam(STMT *s, char *sql, int pnum)
5057 {
5058     int type, len = 0, needalloc = 0;
5059     BINDPARM *p;
5060 
5061     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
5062 	goto error;
5063     }
5064     p = &s->bindparms[pnum];
5065     type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
5066 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
5067     /* MS Access hack part 4 (map SQL_C_DEFAULT to SQL_C_CHAR) */
5068     if (type == SQL_C_WCHAR && p->type == SQL_C_DEFAULT) {
5069 	type = SQL_C_CHAR;
5070     }
5071 #endif
5072     if (p->need > 0) {
5073 	return setupparbuf(s, p);
5074     }
5075     p->strbuf[0] = '\0';
5076     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
5077 	p->s3type = SQLITE_NULL;
5078 	p->s3size = 0;
5079 	return SQL_SUCCESS;
5080     }
5081     if (type == SQL_C_CHAR &&
5082 	(p->stype == SQL_BINARY ||
5083 	 p->stype == SQL_VARBINARY ||
5084 	 p->stype == SQL_LONGVARBINARY)) {
5085 	type = SQL_C_BINARY;
5086     }
5087     switch (type) {
5088     case SQL_C_BINARY:
5089 	p->s3type = SQLITE_BLOB;
5090 	p->s3size = p->len;
5091 	p->s3val = p->param;
5092 	if (p->need < 0) {
5093 	    break;
5094 	}
5095 	if (!p->lenp) {
5096 	    len = p->len;
5097 	} else if (*p->lenp == SQL_DATA_AT_EXEC) {
5098 	    len = p->len;
5099 	} else {
5100 	    len = *p->lenp;
5101 	    if (len <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
5102 		len = SQL_LEN_DATA_AT_EXEC(len);
5103 	    }
5104 	}
5105 	if (len < 0) {
5106 	    setstat(s, -1, "invalid length", "HY009");
5107 	    return SQL_ERROR;
5108 	}
5109 	p->len = len;
5110 	p->max = p->len;
5111 	p->need = -1;
5112 	p->s3size = len;
5113 	break;
5114 #ifdef WCHARSUPPORT
5115     case SQL_C_WCHAR:
5116 #endif
5117     case SQL_C_CHAR:
5118 	p->s3type = SQLITE_TEXT;
5119 	p->s3size = -1;
5120 	p->s3val = p->param;
5121 	if (!p->parbuf) {
5122 #ifdef WCHARSUPPORT
5123 	    if (type == SQL_C_WCHAR) {
5124 		if (!p->lenp || *p->lenp == SQL_NTS) {
5125 		    p->max = uc_strlen(p->param) * sizeof (SQLWCHAR);
5126 		} else if (*p->lenp >= 0) {
5127 		    p->max = *p->lenp;
5128 		}
5129 	    } else
5130 #endif
5131 	    if (type == SQL_C_CHAR) {
5132 		if (!p->lenp || *p->lenp == SQL_NTS) {
5133 		    p->len = p->max = strlen(p->param);
5134 #if defined(_WIN32) || defined(_WIN64)
5135 		    needalloc = 1;
5136 #endif
5137 		} else if (*p->lenp >= 0) {
5138 		    p->len = p->max = *p->lenp;
5139 		    needalloc = 1;
5140 		}
5141 	    }
5142 	}
5143 	if (p->need < 0 && p->parbuf == p->param) {
5144 	    break;
5145 	}
5146 #ifdef WCHARSUPPORT
5147 	if (type == SQL_C_WCHAR) {
5148 	    char *dp = uc_to_utf(p->param, p->max);
5149 
5150 	    if (!dp) {
5151 		return nomem(s);
5152 	    }
5153 	    if (p->param == p->parbuf) {
5154 		freep(&p->parbuf);
5155 	    }
5156 	    p->parbuf = p->param = dp;
5157 	    p->need = -1;
5158 	    p->len = strlen(p->param);
5159 	    p->s3val = p->param;
5160 	    p->s3size = p->len;
5161 	} else
5162 #endif
5163 	if (type == SQL_C_CHAR) {
5164 	    p->s3val = p->param;
5165 	    if (needalloc) {
5166 		char *dp;
5167 
5168 #if defined(_WIN32) || defined(_WIN64)
5169 		if (*s->oemcp) {
5170 		    dp = wmb_to_utf(p->param, p->len);
5171 		} else {
5172 		    dp = xmalloc(p->len + 1);
5173 		}
5174 #else
5175 		dp = xmalloc(p->len + 1);
5176 #endif
5177 		if (!dp) {
5178 		    return nomem(s);
5179 		}
5180 #if defined(_WIN32) || defined(_WIN64)
5181 		if (*s->oemcp) {
5182 		    p->len = strlen(dp);
5183 		} else {
5184 		    memcpy(dp, p->param, p->len);
5185 		    dp[p->len] = '\0';
5186 		}
5187 #else
5188 		memcpy(dp, p->param, p->len);
5189 		dp[p->len] = '\0';
5190 #endif
5191 		if (p->param == p->parbuf) {
5192 		    freep(&p->parbuf);
5193 		}
5194 		p->parbuf = p->param = dp;
5195 		p->need = -1;
5196 		p->s3val = p->param;
5197 		p->s3size = p->len;
5198 	    }
5199 	}
5200 	break;
5201     case SQL_C_UTINYINT:
5202     case SQL_C_TINYINT:
5203     case SQL_C_STINYINT:
5204 	p->s3type = SQLITE_INTEGER;
5205 	p->s3size = sizeof (int);
5206 	p->s3ival = *((SQLCHAR *) p->param);
5207 	break;
5208     case SQL_C_USHORT:
5209 	p->s3type = SQLITE_INTEGER;
5210 	p->s3size = sizeof (int);
5211 	p->s3ival = *((SQLUSMALLINT *) p->param);
5212 	break;
5213     case SQL_C_SHORT:
5214     case SQL_C_SSHORT:
5215 	p->s3type = SQLITE_INTEGER;
5216 	p->s3size = sizeof (int);
5217 	p->s3ival = *((SQLSMALLINT *) p->param);
5218 	break;
5219     case SQL_C_ULONG:
5220 	p->s3type = SQLITE_INTEGER;
5221 	p->s3size = sizeof (int);
5222 	p->s3ival = *((SQLUINTEGER *) p->param);
5223 	break;
5224     case SQL_C_LONG:
5225     case SQL_C_SLONG:
5226 	p->s3type = SQLITE_INTEGER;
5227 	p->s3size = sizeof (int);
5228 	p->s3ival = *((SQLINTEGER *) p->param);
5229 	break;
5230 #ifdef SQL_BIT
5231     case SQL_C_BIT:
5232 	p->s3type = SQLITE_INTEGER;
5233 	p->s3size = sizeof (int);
5234 	p->s3ival = (*((SQLCHAR *) p->param)) ? 1 : 0;
5235 	break;
5236 #endif
5237 #ifdef SQL_BIGINT
5238     case SQL_C_SBIGINT:
5239 	p->s3type = SQLITE_INTEGER;
5240 	p->s3size = sizeof (sqlite_int64);
5241 	p->s3lival = *((sqlite_int64 *) p->param);
5242 	break;
5243     case SQL_C_UBIGINT:
5244 	p->s3type = SQLITE_INTEGER;
5245 	p->s3size = sizeof (sqlite_int64);
5246 	p->s3lival = *((sqlite_uint64 *) p->param);
5247 	break;
5248 #endif
5249     case SQL_C_FLOAT:
5250 	p->s3type = SQLITE_FLOAT;
5251 	p->s3size = sizeof (double);
5252 	p->s3dval = *((float *) p->param);
5253 	break;
5254     case SQL_C_DOUBLE:
5255 	p->s3type = SQLITE_FLOAT;
5256 	p->s3size = sizeof (double);
5257 	p->s3dval = *((double *) p->param);
5258 	break;
5259 #ifdef SQL_C_TYPE_DATE
5260     case SQL_C_TYPE_DATE:
5261 #endif
5262     case SQL_C_DATE:
5263 	if (*s->jdconv) {
5264 	    int a, b, x1, x2, y, m, d;
5265 
5266 	    p->s3type = SQLITE_FLOAT;
5267 	    p->s3size = sizeof (double);
5268 	    y = ((DATE_STRUCT *) p->param)->year;
5269 	    m = ((DATE_STRUCT *) p->param)->month;
5270 	    d = ((DATE_STRUCT *) p->param)->day;
5271 	    if (m <= 2) {
5272 		y--;
5273 		m += 12;
5274 	    }
5275 	    a = y / 100;
5276 	    b = 2 - a + (a / 4);
5277 	    x1 = 36525 * (y + 4716) / 100;
5278 	    x2 = 306001 * (m + 1) / 10000;
5279 	    p->s3dval = x1 + x2 + d + b - 1524.5;
5280 	    break;
5281 	}
5282 	sprintf(p->strbuf, "%04d-%02d-%02d",
5283 		((DATE_STRUCT *) p->param)->year,
5284 		((DATE_STRUCT *) p->param)->month,
5285 		((DATE_STRUCT *) p->param)->day);
5286 	p->s3type = SQLITE_TEXT;
5287 	p->s3size = -1;
5288 	p->s3val = p->strbuf;
5289 	break;
5290 #ifdef SQL_C_TYPE_TIME
5291     case SQL_C_TYPE_TIME:
5292 #endif
5293     case SQL_C_TIME:
5294 	if (*s->jdconv) {
5295 	    p->s3type = SQLITE_FLOAT;
5296 	    p->s3size = sizeof (double);
5297 	    p->s3dval = 2451544.5 +
5298 	       (((TIME_STRUCT *) p->param)->hour * 3600000.0 +
5299 		((TIME_STRUCT *) p->param)->minute * 60000.0 +
5300 		((TIME_STRUCT *) p->param)->second * 1000.0) / 86400000.0;
5301 	    break;
5302 	}
5303 	sprintf(p->strbuf, "%02d:%02d:%02d",
5304 		((TIME_STRUCT *) p->param)->hour,
5305 		((TIME_STRUCT *) p->param)->minute,
5306 		((TIME_STRUCT *) p->param)->second);
5307 	p->s3type = SQLITE_TEXT;
5308 	p->s3size = -1;
5309 	p->s3val = p->strbuf;
5310 	break;
5311 #ifdef SQL_C_TYPE_TIMESTAMP
5312     case SQL_C_TYPE_TIMESTAMP:
5313 #endif
5314     case SQL_C_TIMESTAMP:
5315 	if (*s->jdconv) {
5316 	    int a, b, x1, x2, y, m, d;
5317 
5318 	    p->s3type = SQLITE_FLOAT;
5319 	    p->s3size = sizeof (double);
5320 	    y = ((TIMESTAMP_STRUCT *) p->param)->year;
5321 	    m = ((TIMESTAMP_STRUCT *) p->param)->month;
5322 	    d = ((TIMESTAMP_STRUCT *) p->param)->day;
5323 	    if (m <= 2) {
5324 		y--;
5325 		m += 12;
5326 	    }
5327 	    a = y / 100;
5328 	    b = 2 - a + (a / 4);
5329 	    x1 = 36525 * (y + 4716) / 100;
5330 	    x2 = 306001 * (m + 1) / 10000;
5331 	    p->s3dval = x1 + x2 + d + b - 1524.5 +
5332 	       (((TIMESTAMP_STRUCT *) p->param)->hour * 3600000.0 +
5333 		((TIMESTAMP_STRUCT *) p->param)->minute * 60000.0 +
5334 		((TIMESTAMP_STRUCT *) p->param)->second * 1000.0 +
5335 		((TIMESTAMP_STRUCT *) p->param)->fraction / 1.0E6)
5336 	       / 86400000.0;
5337 	    break;
5338 	}
5339 	len = (int) ((TIMESTAMP_STRUCT *) p->param)->fraction;
5340 	len /= 1000000;
5341 	len = len % 1000;
5342 	if (len < 0) {
5343 	    len = 0;
5344 	}
5345 	if (p->coldef && p->coldef <= 16) {
5346 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
5347 		    ((TIMESTAMP_STRUCT *) p->param)->year,
5348 		    ((TIMESTAMP_STRUCT *) p->param)->month,
5349 		    ((TIMESTAMP_STRUCT *) p->param)->day,
5350 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
5351 		    ((TIMESTAMP_STRUCT *) p->param)->minute);
5352 	} else if (p->coldef && p->coldef <= 19) {
5353 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
5354 		    ((TIMESTAMP_STRUCT *) p->param)->year,
5355 		    ((TIMESTAMP_STRUCT *) p->param)->month,
5356 		    ((TIMESTAMP_STRUCT *) p->param)->day,
5357 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
5358 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
5359 		    ((TIMESTAMP_STRUCT *) p->param)->second);
5360 	} else {
5361 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
5362 		    ((TIMESTAMP_STRUCT *) p->param)->year,
5363 		    ((TIMESTAMP_STRUCT *) p->param)->month,
5364 		    ((TIMESTAMP_STRUCT *) p->param)->day,
5365 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
5366 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
5367 		    ((TIMESTAMP_STRUCT *) p->param)->second,
5368 		    len);
5369 	}
5370 	p->s3type = SQLITE_TEXT;
5371 	p->s3size = -1;
5372 	p->s3val = p->strbuf;
5373 	break;
5374     default:
5375     error:
5376 	setstat(s, -1, "unsupported parameter type",
5377 		(*s->ov3) ? "07009" : "S1093");
5378 	return SQL_ERROR;
5379     }
5380     return SQL_SUCCESS;
5381 }
5382 
5383 /**
5384  * Internal bind parameter on HSTMT.
5385  * @param stmt statement handle
5386  * @param pnum parameter number, starting at 1
5387  * @param iotype input/output type of parameter
5388  * @param buftype type of host variable
5389  * @param ptype
5390  * @param coldef
5391  * @param scale
5392  * @param data pointer to host variable
5393  * @param buflen length of host variable
5394  * @param len output length pointer
5395  * @result ODBC error code
5396  */
5397 
5398 static SQLRETURN
drvbindparam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLUINTEGER coldef,SQLSMALLINT scale,SQLPOINTER data,SQLINTEGER buflen,SQLLEN * len)5399 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
5400 	     SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
5401 	     SQLSMALLINT scale,
5402 	     SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
5403 {
5404     STMT *s;
5405     BINDPARM *p;
5406 
5407     if (stmt == SQL_NULL_HSTMT) {
5408 	return SQL_INVALID_HANDLE;
5409     }
5410     s = (STMT *) stmt;
5411     if (pnum == 0) {
5412 	setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
5413 	return SQL_ERROR;
5414     }
5415     if (!data && !len) {
5416 	setstat(s, -1, "invalid buffer", "HY003");
5417 	return SQL_ERROR;
5418     }
5419     --pnum;
5420     if (s->bindparms) {
5421 	if (pnum >= s->nbindparms) {
5422 	    BINDPARM *newparms;
5423 
5424 	    newparms = xrealloc(s->bindparms,
5425 				(pnum + 1) * sizeof (BINDPARM));
5426 	    if (!newparms) {
5427 outofmem:
5428 		return nomem(s);
5429 	    }
5430 	    s->bindparms = newparms;
5431 	    memset(&s->bindparms[s->nbindparms], 0,
5432 		   (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
5433 	    s->nbindparms = pnum + 1;
5434 	}
5435     } else {
5436 	int npar = max(10, pnum + 1);
5437 
5438 	s->bindparms = xmalloc(npar * sizeof (BINDPARM));
5439 	if (!s->bindparms) {
5440 	    goto outofmem;
5441 	}
5442 	memset(s->bindparms, 0, npar * sizeof (BINDPARM));
5443 	s->nbindparms = npar;
5444     }
5445     switch (buftype) {
5446     case SQL_C_STINYINT:
5447     case SQL_C_UTINYINT:
5448     case SQL_C_TINYINT:
5449 #ifdef SQL_C_BIT
5450     case SQL_C_BIT:
5451 #endif
5452 	buflen = sizeof (SQLCHAR);
5453 	break;
5454     case SQL_C_SHORT:
5455     case SQL_C_USHORT:
5456     case SQL_C_SSHORT:
5457 	buflen = sizeof (SQLSMALLINT);
5458 	break;
5459     case SQL_C_SLONG:
5460     case SQL_C_ULONG:
5461     case SQL_C_LONG:
5462 	buflen = sizeof (SQLINTEGER);
5463 	break;
5464     case SQL_C_FLOAT:
5465 	buflen = sizeof (float);
5466 	break;
5467     case SQL_C_DOUBLE:
5468 	buflen = sizeof (double);
5469 	break;
5470     case SQL_C_TIMESTAMP:
5471 #ifdef SQL_C_TYPE_TIMESTAMP
5472     case SQL_C_TYPE_TIMESTAMP:
5473 #endif
5474 	buflen = sizeof (TIMESTAMP_STRUCT);
5475 	break;
5476     case SQL_C_TIME:
5477 #ifdef SQL_C_TYPE_TIME
5478     case SQL_C_TYPE_TIME:
5479 #endif
5480 	buflen = sizeof (TIME_STRUCT);
5481 	break;
5482     case SQL_C_DATE:
5483 #ifdef SQL_C_TYPE_DATE
5484     case SQL_C_TYPE_DATE:
5485 #endif
5486 	buflen = sizeof (DATE_STRUCT);
5487 	break;
5488 #ifdef SQL_C_UBIGINT
5489     case SQL_C_UBIGINT:
5490 	buflen = sizeof (SQLBIGINT);
5491 	break;
5492 #endif
5493 #ifdef SQL_C_SBIGINT
5494     case SQL_C_SBIGINT:
5495 	buflen = sizeof (SQLBIGINT);
5496 	break;
5497 #endif
5498 #ifdef SQL_C_BIGINT
5499     case SQL_C_BIGINT:
5500 	buflen = sizeof (SQLBIGINT);
5501 	break;
5502 #endif
5503     }
5504     p = &s->bindparms[pnum];
5505     p->type = buftype;
5506     p->stype = ptype;
5507     p->coldef = coldef;
5508     p->scale = scale;
5509     p->max = buflen;
5510     p->inc = buflen;
5511     p->lenp = p->lenp0 = len;
5512     p->offs = 0;
5513     p->len = 0;
5514     p->param0 = data;
5515     freep(&p->parbuf);
5516     p->param = p->param0;
5517     p->bound = 1;
5518     p->need = 0;
5519     return SQL_SUCCESS;
5520 }
5521 
5522 /**
5523  * Bind parameter on HSTMT.
5524  * @param stmt statement handle
5525  * @param pnum parameter number, starting at 1
5526  * @param iotype input/output type of parameter
5527  * @param buftype type of host variable
5528  * @param ptype
5529  * @param coldef
5530  * @param scale
5531  * @param data pointer to host variable
5532  * @param buflen length of host variable
5533  * @param len output length pointer
5534  * @result ODBC error code
5535  */
5536 
5537 SQLRETURN SQL_API
SQLBindParameter(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER data,SQLLEN buflen,SQLLEN * len)5538 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
5539 		 SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
5540 		 SQLSMALLINT scale,
5541 		 SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
5542 {
5543     SQLRETURN ret;
5544 
5545     HSTMT_LOCK(stmt);
5546     ret = drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
5547 		       scale, data, buflen, len);
5548     HSTMT_UNLOCK(stmt);
5549     return ret;
5550 }
5551 
5552 #ifndef HAVE_IODBC
5553 /**
5554  * Bind parameter on HSTMT.
5555  * @param stmt statement handle
5556  * @param pnum parameter number, starting at 1
5557  * @param vtype input/output type of parameter
5558  * @param ptype
5559  * @param lenprec
5560  * @param scale
5561  * @param val pointer to host variable
5562  * @param lenp output length pointer
5563  * @result ODBC error code
5564  */
5565 
5566 SQLRETURN SQL_API
SQLBindParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT vtype,SQLSMALLINT ptype,SQLULEN lenprec,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * lenp)5567 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
5568 	     SQLSMALLINT ptype, SQLULEN lenprec,
5569 	     SQLSMALLINT scale, SQLPOINTER val,
5570 	     SQLLEN *lenp)
5571 {
5572     SQLRETURN ret;
5573 
5574     HSTMT_LOCK(stmt);
5575     ret = drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
5576 		       lenprec, scale, val, 0, lenp);
5577     HSTMT_UNLOCK(stmt);
5578     return ret;
5579 }
5580 #endif
5581 
5582 /**
5583  * Return number of parameters.
5584  * @param stmt statement handle
5585  * @param nparam output parameter count
5586  * @result ODBC error code
5587  */
5588 
5589 SQLRETURN SQL_API
SQLNumParams(SQLHSTMT stmt,SQLSMALLINT * nparam)5590 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
5591 {
5592     STMT *s;
5593     SQLSMALLINT dummy;
5594 
5595     HSTMT_LOCK(stmt);
5596     if (stmt == SQL_NULL_HSTMT) {
5597 	return SQL_INVALID_HANDLE;
5598     }
5599     s = (STMT *) stmt;
5600     if (!nparam) {
5601 	nparam = &dummy;
5602     }
5603     *nparam = s->nparams;
5604     HSTMT_UNLOCK(stmt);
5605     return SQL_SUCCESS;
5606 }
5607 
5608 /**
5609  * Setup parameter buffer for deferred parameter.
5610  * @param s pointer to STMT
5611  * @param p pointer to BINDPARM
5612  * @result ODBC error code (success indicated by SQL_NEED_DATA)
5613  */
5614 
5615 static SQLRETURN
setupparbuf(STMT * s,BINDPARM * p)5616 setupparbuf(STMT *s, BINDPARM *p)
5617 {
5618     if (!p->parbuf) {
5619 	if (*p->lenp == SQL_DATA_AT_EXEC) {
5620 	    p->len = p->max;
5621 	} else {
5622 	    p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
5623 	}
5624 	if (p->len < 0 && p->len != SQL_NTS &&
5625 	    p->len != SQL_NULL_DATA) {
5626 	    setstat(s, -1, "invalid length", "HY009");
5627 	    return SQL_ERROR;
5628 	}
5629 	if (p->len >= 0) {
5630 	    p->parbuf = xmalloc(p->len + 2);
5631 	    if (!p->parbuf) {
5632 		return nomem(s);
5633 	    }
5634 	    p->param = p->parbuf;
5635 	} else {
5636 	    p->param = NULL;
5637 	}
5638     }
5639     return SQL_NEED_DATA;
5640 }
5641 
5642 /**
5643  * Retrieve next parameter for sending data to executing query.
5644  * @param stmt statement handle
5645  * @param pind pointer to output parameter indicator
5646  * @result ODBC error code
5647  */
5648 
5649 SQLRETURN SQL_API
SQLParamData(SQLHSTMT stmt,SQLPOINTER * pind)5650 SQLParamData(SQLHSTMT stmt, SQLPOINTER *pind)
5651 {
5652     STMT *s;
5653     int i;
5654     SQLPOINTER dummy;
5655     SQLRETURN ret;
5656     BINDPARM *p;
5657 
5658     HSTMT_LOCK(stmt);
5659     if (stmt == SQL_NULL_HSTMT) {
5660 	return SQL_INVALID_HANDLE;
5661     }
5662     s = (STMT *) stmt;
5663     if (!pind) {
5664 	pind = &dummy;
5665     }
5666     if (s->pdcount < s->nparams) {
5667 	s->pdcount++;
5668     }
5669     for (i = 0; i < s->pdcount; i++) {
5670 	p = &s->bindparms[i];
5671 	if (p->need > 0) {
5672 	    int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
5673 
5674 	    p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR) ? -1 : 0;
5675 	}
5676     }
5677     for (; i < s->nparams; i++) {
5678 	p = &s->bindparms[i];
5679 	if (p->need > 0) {
5680 	    *pind = (SQLPOINTER) p->param0;
5681 	    ret = setupparbuf(s, p);
5682 	    s->pdcount = i;
5683 	    goto done;
5684 	}
5685     }
5686     ret = drvexecute(stmt, 0);
5687 done:
5688     HSTMT_UNLOCK(stmt);
5689     return ret;
5690 }
5691 
5692 /**
5693  * Return information about parameter.
5694  * @param stmt statement handle
5695  * @param pnum parameter number, starting at 1
5696  * @param dtype output type indicator
5697  * @param size output size indicator
5698  * @param decdigits output number of digits
5699  * @param nullable output NULL allowed indicator
5700  * @result ODBC error code
5701  */
5702 
5703 SQLRETURN SQL_API
SQLDescribeParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT * dtype,SQLULEN * size,SQLSMALLINT * decdigits,SQLSMALLINT * nullable)5704 SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT *dtype,
5705 		 SQLULEN *size, SQLSMALLINT *decdigits, SQLSMALLINT *nullable)
5706 {
5707     STMT *s;
5708     SQLRETURN ret = SQL_ERROR;
5709 
5710     HSTMT_LOCK(stmt);
5711     if (stmt == SQL_NULL_HSTMT) {
5712 	return SQL_INVALID_HANDLE;
5713     }
5714     s = (STMT *) stmt;
5715     --pnum;
5716     if (pnum >= s->nparams) {
5717 	setstat(s, -1, "invalid parameter index",
5718 		(*s->ov3) ? "HY000" : "S1000");
5719 	goto done;
5720     }
5721     if (dtype) {
5722 #ifdef SQL_LONGVARCHAR
5723 #ifdef WINTERFACE
5724 	*dtype = s->nowchar[0] ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
5725 #else
5726 	*dtype = SQL_LONGVARCHAR;
5727 #endif
5728 #else
5729 #ifdef WINTERFACE
5730 	*dtype = s->nowchar[0] ? SQL_VARCHAR : SQL_WVARCHAR;
5731 #else
5732 	*dtype = SQL_VARCHAR;
5733 #endif
5734 #endif
5735     }
5736     if (size) {
5737 #ifdef SQL_LONGVARCHAR
5738 	*size = 65536;
5739 #else
5740 	*size = 255;
5741 #endif
5742     }
5743     if (decdigits) {
5744 	*decdigits = 0;
5745     }
5746     if (nullable) {
5747 	*nullable = SQL_NULLABLE;
5748     }
5749     ret = SQL_SUCCESS;
5750 done:
5751     HSTMT_UNLOCK(stmt);
5752     return ret;
5753 }
5754 
5755 /**
5756  * Set information on parameter.
5757  * @param stmt statement handle
5758  * @param par parameter number, starting at 1
5759  * @param type type of host variable
5760  * @param sqltype
5761  * @param coldef
5762  * @param scale
5763  * @param val pointer to host variable
5764  * @param nval output length pointer
5765  * @result ODBC error code
5766  */
5767 
5768 SQLRETURN SQL_API
SQLSetParam(SQLHSTMT stmt,SQLUSMALLINT par,SQLSMALLINT type,SQLSMALLINT sqltype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * nval)5769 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
5770 	    SQLSMALLINT sqltype, SQLULEN coldef,
5771 	    SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
5772 {
5773     SQLRETURN ret;
5774 
5775     HSTMT_LOCK(stmt);
5776     ret = drvbindparam(stmt, par, SQL_PARAM_INPUT,
5777 		       type, sqltype, coldef, scale, val,
5778 		       SQL_SETPARAM_VALUE_MAX, nval);
5779     HSTMT_UNLOCK(stmt);
5780     return ret;
5781 }
5782 
5783 /**
5784  * Function not implemented.
5785  */
5786 
5787 SQLRETURN SQL_API
SQLParamOptions(SQLHSTMT stmt,SQLULEN rows,SQLULEN * rowp)5788 SQLParamOptions(SQLHSTMT stmt, SQLULEN rows, SQLULEN *rowp)
5789 {
5790     SQLRETURN ret;
5791 
5792     HSTMT_LOCK(stmt);
5793     ret = drvunimplstmt(stmt);
5794     HSTMT_UNLOCK(stmt);
5795     return ret;
5796 }
5797 
5798 #ifndef WINTERFACE
5799 /**
5800  * Function not implemented.
5801  */
5802 
5803 SQLRETURN SQL_API
SQLGetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)5804 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
5805 		SQLSMALLINT fieldid, SQLPOINTER value,
5806 		SQLINTEGER buflen, SQLINTEGER *strlen)
5807 {
5808     return SQL_ERROR;
5809 }
5810 #endif
5811 
5812 #ifdef WINTERFACE
5813 /**
5814  * Function not implemented.
5815  */
5816 
5817 SQLRETURN SQL_API
SQLGetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)5818 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
5819 		 SQLSMALLINT fieldid, SQLPOINTER value,
5820 		 SQLINTEGER buflen, SQLINTEGER *strlen)
5821 {
5822     return SQL_ERROR;
5823 }
5824 #endif
5825 
5826 #ifndef WINTERFACE
5827 /**
5828  * Function not implemented.
5829  */
5830 
5831 SQLRETURN SQL_API
SQLSetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)5832 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
5833 		SQLSMALLINT fieldid, SQLPOINTER value,
5834 		SQLINTEGER buflen)
5835 {
5836     return SQL_ERROR;
5837 }
5838 #endif
5839 
5840 #ifdef WINTERFACE
5841 /**
5842  * Function not implemented.
5843  */
5844 
5845 SQLRETURN SQL_API
SQLSetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)5846 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
5847 		 SQLSMALLINT fieldid, SQLPOINTER value,
5848 		 SQLINTEGER buflen)
5849 {
5850     return SQL_ERROR;
5851 }
5852 #endif
5853 
5854 #ifndef WINTERFACE
5855 /**
5856  * Function not implemented.
5857  */
5858 
5859 SQLRETURN SQL_API
SQLGetDescRec(SQLHDESC handle,SQLSMALLINT recno,SQLCHAR * name,SQLSMALLINT buflen,SQLSMALLINT * strlen,SQLSMALLINT * type,SQLSMALLINT * subtype,SQLLEN * len,SQLSMALLINT * prec,SQLSMALLINT * scale,SQLSMALLINT * nullable)5860 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
5861 	      SQLCHAR *name, SQLSMALLINT buflen,
5862 	      SQLSMALLINT *strlen, SQLSMALLINT *type,
5863 	      SQLSMALLINT *subtype, SQLLEN *len,
5864 	      SQLSMALLINT *prec, SQLSMALLINT *scale,
5865 	      SQLSMALLINT *nullable)
5866 {
5867     return SQL_ERROR;
5868 }
5869 #endif
5870 
5871 #ifdef WINTERFACE
5872 /**
5873  * Function not implemented.
5874  */
5875 
5876 SQLRETURN SQL_API
SQLGetDescRecW(SQLHDESC handle,SQLSMALLINT recno,SQLWCHAR * name,SQLSMALLINT buflen,SQLSMALLINT * strlen,SQLSMALLINT * type,SQLSMALLINT * subtype,SQLLEN * len,SQLSMALLINT * prec,SQLSMALLINT * scale,SQLSMALLINT * nullable)5877 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
5878 	       SQLWCHAR *name, SQLSMALLINT buflen,
5879 	       SQLSMALLINT *strlen, SQLSMALLINT *type,
5880 	       SQLSMALLINT *subtype, SQLLEN *len,
5881 	       SQLSMALLINT *prec, SQLSMALLINT *scale,
5882 	       SQLSMALLINT *nullable)
5883 {
5884     return SQL_ERROR;
5885 }
5886 #endif
5887 
5888 /**
5889  * Function not implemented.
5890  */
5891 
5892 SQLRETURN SQL_API
SQLSetDescRec(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT type,SQLSMALLINT subtype,SQLLEN len,SQLSMALLINT prec,SQLSMALLINT scale,SQLPOINTER data,SQLLEN * strlen,SQLLEN * indicator)5893 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
5894 	      SQLSMALLINT type, SQLSMALLINT subtype,
5895 	      SQLLEN len, SQLSMALLINT prec,
5896 	      SQLSMALLINT scale, SQLPOINTER data,
5897 	      SQLLEN *strlen, SQLLEN *indicator)
5898 {
5899     return SQL_ERROR;
5900 }
5901 
5902 /**
5903  * Setup empty result set from constant column specification.
5904  * @param stmt statement handle
5905  * @param colspec column specification array (default, ODBC2)
5906  * @param ncols number of columns (default, ODBC2)
5907  * @param colspec3 column specification array (ODBC3)
5908  * @param ncols3 number of columns (ODBC3)
5909  * @param nret returns number of columns
5910  * @result ODBC error code
5911  */
5912 
5913 static SQLRETURN
mkresultset(HSTMT stmt,COL * colspec,int ncols,COL * colspec3,int ncols3,int * nret)5914 mkresultset(HSTMT stmt, COL *colspec, int ncols, COL *colspec3,
5915 	    int ncols3, int *nret)
5916 {
5917     STMT *s;
5918     DBC *d;
5919 
5920     if (stmt == SQL_NULL_HSTMT) {
5921 	return SQL_INVALID_HANDLE;
5922     }
5923     s = (STMT *) stmt;
5924     if (s->dbc == SQL_NULL_HDBC) {
5925 noconn:
5926 	return noconn(s);
5927     }
5928     d = (DBC *) s->dbc;
5929     if (!d->sqlite) {
5930 	goto noconn;
5931     }
5932     s3stmt_end_if(s);
5933     freeresult(s, 0);
5934     if (colspec3 && *s->ov3) {
5935 	s->ncols = ncols3;
5936 	s->cols = colspec3;
5937     } else {
5938 	s->ncols = ncols;
5939 	s->cols = colspec;
5940     }
5941     mkbindcols(s, s->ncols);
5942     s->nowchar[1] = 1;
5943     s->nrows = 0;
5944     s->rowp = s->rowprs = -1;
5945     s->isselect = -1;
5946     if (nret) {
5947 	*nret = s->ncols;
5948     }
5949     return SQL_SUCCESS;
5950 }
5951 
5952 /**
5953  * Columns for result set of SQLTablePrivileges().
5954  */
5955 
5956 static COL tablePrivSpec2[] = {
5957     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5958     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
5959     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5960     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5961     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5962     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
5963     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
5964 };
5965 
5966 static COL tablePrivSpec3[] = {
5967     { "SYSTEM", "TABLEPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
5968     { "SYSTEM", "TABLEPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
5969     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5970     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5971     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5972     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
5973     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
5974 };
5975 
5976 /**
5977  * Retrieve privileges on tables and/or views.
5978  * @param stmt statement handle
5979  * @param cat catalog name/pattern or NULL
5980  * @param catLen length of catalog name/pattern or SQL_NTS
5981  * @param schema schema name/pattern or NULL
5982  * @param schemaLen length of schema name/pattern or SQL_NTS
5983  * @param table table name/pattern or NULL
5984  * @param tableLen length of table name/pattern or SQL_NTS
5985  * @result ODBC error code
5986  */
5987 
5988 static SQLRETURN
drvtableprivileges(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5989 drvtableprivileges(SQLHSTMT stmt,
5990 		   SQLCHAR *cat, SQLSMALLINT catLen,
5991 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
5992 		   SQLCHAR *table, SQLSMALLINT tableLen)
5993 {
5994     SQLRETURN ret;
5995     STMT *s;
5996     DBC *d;
5997     int ncols, rc, size, npatt;
5998     char *errp = NULL, *sql, tname[512];
5999 
6000     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
6001 		      tablePrivSpec3, array_size(tablePrivSpec3), NULL);
6002     if (ret != SQL_SUCCESS) {
6003 	return ret;
6004     }
6005     s = (STMT *) stmt;
6006     d = (DBC *) s->dbc;
6007     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
6008 	table = NULL;
6009 	goto doit;
6010     }
6011     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
6012 	schema[0] == '%') {
6013 	if ((!cat || catLen == 0 || !cat[0]) &&
6014 	    (!table || tableLen == 0 || !table[0])) {
6015 	    table = NULL;
6016 	    goto doit;
6017 	}
6018     }
6019 doit:
6020     if (!table) {
6021 	size = 1;
6022 	tname[0] = '%';
6023     } else {
6024 	if (tableLen == SQL_NTS) {
6025 	    size = sizeof (tname) - 1;
6026 	} else {
6027 	    size = min(sizeof (tname) - 1, tableLen);
6028 	}
6029 	strncpy(tname, (char *) table, size);
6030     }
6031     tname[size] = '\0';
6032     npatt = unescpat(tname);
6033 #if defined(_WIN32) || defined(_WIN64)
6034     if (npatt) {
6035 	sql = sqlite3_mprintf("select %s as 'TABLE_QUALIFIER', "
6036 			      "%s as 'TABLE_OWNER', "
6037 			      "tbl_name as 'TABLE_NAME', "
6038 			      "'' as 'GRANTOR', "
6039 			      "'' as 'GRANTEE', "
6040 			      "'SELECT' AS 'PRIVILEGE', "
6041 			      "NULL as 'IS_GRANTABLE' "
6042 			      "from sqlite_master where "
6043 			      "(type = 'table' or type = 'view') "
6044 			      "and tbl_name like %Q "
6045 			      "UNION "
6046 			      "select %s as 'TABLE_QUALIFIER', "
6047 			      "%s as 'TABLE_OWNER', "
6048 			      "tbl_name as 'TABLE_NAME', "
6049 			      "'' as 'GRANTOR', "
6050 			      "'' as 'GRANTEE', "
6051 			      "'UPDATE' AS 'PRIVILEGE', "
6052 			      "NULL as 'IS_GRANTABLE' "
6053 			      "from sqlite_master where "
6054 			      "(type = 'table' or type = 'view') "
6055 			      "and tbl_name like %Q "
6056 			      "UNION "
6057 			      "select %s as 'TABLE_QUALIFIER', "
6058 			      "%s as 'TABLE_OWNER', "
6059 			      "tbl_name as 'TABLE_NAME', "
6060 			      "'' as 'GRANTOR', "
6061 			      "'' as 'GRANTEE', "
6062 			      "'DELETE' AS 'PRIVILEGE', "
6063 			      "NULL as 'IS_GRANTABLE' "
6064 			      "from sqlite_master where "
6065 			      "(type = 'table' or type = 'view') "
6066 			      "and tbl_name like %Q "
6067 			      "UNION "
6068 			      "select %s as 'TABLE_QUALIFIER', "
6069 			      "%s as 'TABLE_OWNER', "
6070 			      "tbl_name as 'TABLE_NAME', "
6071 			      "'' as 'GRANTOR', "
6072 			      "'' as 'GRANTEE', "
6073 			      "'INSERT' AS 'PRIVILEGE', "
6074 			      "NULL as 'IS_GRANTABLE' "
6075 			      "from sqlite_master where "
6076 			      "(type = 'table' or type = 'view') "
6077 			      "and tbl_name like %Q "
6078 			      "UNION "
6079 			      "select %s as 'TABLE_QUALIFIER', "
6080 			      "%s as 'TABLE_OWNER', "
6081 			      "tbl_name as 'TABLE_NAME', "
6082 			      "'' as 'GRANTOR', "
6083 			      "'' as 'GRANTEE', "
6084 			      "'REFERENCES' AS 'PRIVILEGE', "
6085 			      "NULL as 'IS_GRANTABLE' "
6086 			      "from sqlite_master where "
6087 			      "(type = 'table' or type = 'view') "
6088 			      "and tbl_name like %Q",
6089 			      d->xcelqrx ? "'main'" : "NULL",
6090 			      d->xcelqrx ? "''" : "NULL",
6091 			      tname,
6092 			      d->xcelqrx ? "'main'" : "NULL",
6093 			      d->xcelqrx ? "''" : "NULL",
6094 			      tname,
6095 			      d->xcelqrx ? "'main'" : "NULL",
6096 			      d->xcelqrx ? "''" : "NULL",
6097 			      tname,
6098 			      d->xcelqrx ? "'main'" : "NULL",
6099 			      d->xcelqrx ? "''" : "NULL",
6100 			      tname,
6101 			      d->xcelqrx ? "'main'" : "NULL",
6102 			      d->xcelqrx ? "''" : "NULL",
6103 			      tname);
6104     } else {
6105 	sql = sqlite3_mprintf("select %s as 'TABLE_QUALIFIER', "
6106 			      "%s as 'TABLE_OWNER', "
6107 			      "tbl_name as 'TABLE_NAME', "
6108 			      "'' as 'GRANTOR', "
6109 			      "'' as 'GRANTEE', "
6110 			      "'SELECT' AS 'PRIVILEGE', "
6111 			      "NULL as 'IS_GRANTABLE' "
6112 			      "from sqlite_master where "
6113 			      "(type = 'table' or type = 'view') "
6114 			      "and lower(tbl_name) = lower(%Q) "
6115 			      "UNION "
6116 			      "select %s as 'TABLE_QUALIFIER', "
6117 			      "%s as 'TABLE_OWNER', "
6118 			      "tbl_name as 'TABLE_NAME', "
6119 			      "'' as 'GRANTOR', "
6120 			      "'' as 'GRANTEE', "
6121 			      "'UPDATE' AS 'PRIVILEGE', "
6122 			      "NULL as 'IS_GRANTABLE' "
6123 			      "from sqlite_master where "
6124 			      "(type = 'table' or type = 'view') "
6125 			      "and lower(tbl_name) = lower(%Q) "
6126 			      "UNION "
6127 			      "select %s as 'TABLE_QUALIFIER', "
6128 			      "%s as 'TABLE_OWNER', "
6129 			      "tbl_name as 'TABLE_NAME', "
6130 			      "'' as 'GRANTOR', "
6131 			      "'' as 'GRANTEE', "
6132 			      "'DELETE' AS 'PRIVILEGE', "
6133 			      "NULL as 'IS_GRANTABLE' "
6134 			      "from sqlite_master where "
6135 			      "(type = 'table' or type = 'view') "
6136 			      "and lower(tbl_name) = lower(%Q) "
6137 			      "UNION "
6138 			      "select %s as 'TABLE_QUALIFIER', "
6139 			      "%s as 'TABLE_OWNER', "
6140 			      "tbl_name as 'TABLE_NAME', "
6141 			      "'' as 'GRANTOR', "
6142 			      "'' as 'GRANTEE', "
6143 			      "'INSERT' AS 'PRIVILEGE', "
6144 			      "NULL as 'IS_GRANTABLE' "
6145 			      "from sqlite_master where "
6146 			      "(type = 'table' or type = 'view') "
6147 			      "and lower(tbl_name) = lower(%Q) "
6148 			      "UNION "
6149 			      "select %s as 'TABLE_QUALIFIER', "
6150 			      "%s as 'TABLE_OWNER', "
6151 			      "tbl_name as 'TABLE_NAME', "
6152 			      "'' as 'GRANTOR', "
6153 			      "'' as 'GRANTEE', "
6154 			      "'REFERENCES' AS 'PRIVILEGE', "
6155 			      "NULL as 'IS_GRANTABLE' "
6156 			      "from sqlite_master where "
6157 			      "(type = 'table' or type = 'view') "
6158 			      "and lower(tbl_name) = lower(%Q)",
6159 			      d->xcelqrx ? "'main'" : "NULL",
6160 			      d->xcelqrx ? "''" : "NULL",
6161 			      tname,
6162 			      d->xcelqrx ? "'main'" : "NULL",
6163 			      d->xcelqrx ? "''" : "NULL",
6164 			      tname,
6165 			      d->xcelqrx ? "'main'" : "NULL",
6166 			      d->xcelqrx ? "''" : "NULL",
6167 			      tname,
6168 			      d->xcelqrx ? "'main'" : "NULL",
6169 			      d->xcelqrx ? "''" : "NULL",
6170 			      tname,
6171 			      d->xcelqrx ? "'main'" : "NULL",
6172 			      d->xcelqrx ? "''" : "NULL",
6173 			      tname);
6174     }
6175 #else
6176     if (npatt) {
6177 	sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
6178 			      "NULL as 'TABLE_OWNER', "
6179 			      "tbl_name as 'TABLE_NAME', "
6180 			      "'' as 'GRANTOR', "
6181 			      "'' as 'GRANTEE', "
6182 			      "'SELECT' AS 'PRIVILEGE', "
6183 			      "NULL as 'IS_GRANTABLE' "
6184 			      "from sqlite_master where "
6185 			      "(type = 'table' or type = 'view') "
6186 			      "and tbl_name like %Q "
6187 			      "UNION "
6188 			      "select NULL as 'TABLE_QUALIFIER', "
6189 			      "NULL as 'TABLE_OWNER', "
6190 			      "tbl_name as 'TABLE_NAME', "
6191 			      "'' as 'GRANTOR', "
6192 			      "'' as 'GRANTEE', "
6193 			      "'UPDATE' AS 'PRIVILEGE', "
6194 			      "NULL as 'IS_GRANTABLE' "
6195 			      "from sqlite_master where "
6196 			      "(type = 'table' or type = 'view') "
6197 			      "and tbl_name like %Q "
6198 			      "UNION "
6199 			      "select NULL as 'TABLE_QUALIFIER', "
6200 			      "NULL as 'TABLE_OWNER', "
6201 			      "tbl_name as 'TABLE_NAME', "
6202 			      "'' as 'GRANTOR', "
6203 			      "'' as 'GRANTEE', "
6204 			      "'DELETE' AS 'PRIVILEGE', "
6205 			      "NULL as 'IS_GRANTABLE' "
6206 			      "from sqlite_master where "
6207 			      "(type = 'table' or type = 'view') "
6208 			      "and tbl_name like %Q "
6209 			      "UNION "
6210 			      "select NULL as 'TABLE_QUALIFIER', "
6211 			      "NULL as 'TABLE_OWNER', "
6212 			      "tbl_name as 'TABLE_NAME', "
6213 			      "'' as 'GRANTOR', "
6214 			      "'' as 'GRANTEE', "
6215 			      "'INSERT' AS 'PRIVILEGE', "
6216 			      "NULL as 'IS_GRANTABLE' "
6217 			      "from sqlite_master where "
6218 			      "(type = 'table' or type = 'view') "
6219 			      "and tbl_name like %Q "
6220 			      "UNION "
6221 			      "select NULL as 'TABLE_QUALIFIER', "
6222 			      "NULL as 'TABLE_OWNER', "
6223 			      "tbl_name as 'TABLE_NAME', "
6224 			      "'' as 'GRANTOR', "
6225 			      "'' as 'GRANTEE', "
6226 			      "'REFERENCES' AS 'PRIVILEGE', "
6227 			      "NULL as 'IS_GRANTABLE' "
6228 			      "from sqlite_master where "
6229 			      "(type = 'table' or type = 'view') "
6230 			      "and tbl_name like %Q",
6231 			      tname, tname, tname, tname, tname);
6232     } else {
6233 	sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
6234 			      "NULL as 'TABLE_OWNER', "
6235 			      "tbl_name as 'TABLE_NAME', "
6236 			      "'' as 'GRANTOR', "
6237 			      "'' as 'GRANTEE', "
6238 			      "'SELECT' AS 'PRIVILEGE', "
6239 			      "NULL as 'IS_GRANTABLE' "
6240 			      "from sqlite_master where "
6241 			      "(type = 'table' or type = 'view') "
6242 			      "and lower(tbl_name) = lower(%Q) "
6243 			      "UNION "
6244 			      "select NULL as 'TABLE_QUALIFIER', "
6245 			      "NULL as 'TABLE_OWNER', "
6246 			      "tbl_name as 'TABLE_NAME', "
6247 			      "'' as 'GRANTOR', "
6248 			      "'' as 'GRANTEE', "
6249 			      "'UPDATE' AS 'PRIVILEGE', "
6250 			      "NULL as 'IS_GRANTABLE' "
6251 			      "from sqlite_master where "
6252 			      "(type = 'table' or type = 'view') "
6253 			      "and lower(tbl_name) = lower(%Q) "
6254 			      "UNION "
6255 			      "select NULL as 'TABLE_QUALIFIER', "
6256 			      "NULL as 'TABLE_OWNER', "
6257 			      "tbl_name as 'TABLE_NAME', "
6258 			      "'' as 'GRANTOR', "
6259 			      "'' as 'GRANTEE', "
6260 			      "'DELETE' AS 'PRIVILEGE', "
6261 			      "NULL as 'IS_GRANTABLE' "
6262 			      "from sqlite_master where "
6263 			      "(type = 'table' or type = 'view') "
6264 			      "and lower(tbl_name) = lower(%Q) "
6265 			      "UNION "
6266 			      "select NULL as 'TABLE_QUALIFIER', "
6267 			      "NULL as 'TABLE_OWNER', "
6268 			      "tbl_name as 'TABLE_NAME', "
6269 			      "'' as 'GRANTOR', "
6270 			      "'' as 'GRANTEE', "
6271 			      "'INSERT' AS 'PRIVILEGE', "
6272 			      "NULL as 'IS_GRANTABLE' "
6273 			      "from sqlite_master where "
6274 			      "(type = 'table' or type = 'view') "
6275 			      "and lower(tbl_name) = lower(%Q) "
6276 			      "UNION "
6277 			      "select NULL as 'TABLE_QUALIFIER', "
6278 			      "NULL as 'TABLE_OWNER', "
6279 			      "tbl_name as 'TABLE_NAME', "
6280 			      "'' as 'GRANTOR', "
6281 			      "'' as 'GRANTEE', "
6282 			      "'REFERENCES' AS 'PRIVILEGE', "
6283 			      "NULL as 'IS_GRANTABLE' "
6284 			      "from sqlite_master where "
6285 			      "(type = 'table' or type = 'view') "
6286 			      "and lower(tbl_name) = lower(%Q)",
6287 			      tname, tname, tname, tname, tname);
6288     }
6289 #endif
6290     if (!sql) {
6291 	return nomem(s);
6292     }
6293     ret = starttran(s);
6294     if (ret != SQL_SUCCESS) {
6295 	sqlite3_free(sql);
6296 	return ret;
6297     }
6298     dbtraceapi(d, "sqlite3_get_table", sql);
6299     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
6300     sqlite3_free(sql);
6301     if (rc == SQLITE_OK) {
6302 	if (ncols != s->ncols) {
6303 	    freeresult(s, 0);
6304 	    s->nrows = 0;
6305 	} else {
6306 	    s->rowfree = sqlite3_free_table;
6307 	}
6308     } else {
6309 	s->nrows = 0;
6310 	s->rows = NULL;
6311 	s->rowfree = NULL;
6312     }
6313     if (errp) {
6314 	sqlite3_free(errp);
6315 	errp = NULL;
6316     }
6317     s->rowp = s->rowprs = -1;
6318     return SQL_SUCCESS;
6319 }
6320 
6321 
6322 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
6323 /**
6324  * Retrieve privileges on tables and/or views.
6325  * @param stmt statement handle
6326  * @param catalog catalog name/pattern or NULL
6327  * @param catalogLen length of catalog name/pattern or SQL_NTS
6328  * @param schema schema name/pattern or NULL
6329  * @param schemaLen length of schema name/pattern or SQL_NTS
6330  * @param table table name/pattern or NULL
6331  * @param tableLen length of table name/pattern or SQL_NTS
6332  * @result ODBC error code
6333  */
6334 
6335 SQLRETURN SQL_API
SQLTablePrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)6336 SQLTablePrivileges(SQLHSTMT stmt,
6337 		   SQLCHAR *catalog, SQLSMALLINT catalogLen,
6338 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
6339 		   SQLCHAR *table, SQLSMALLINT tableLen)
6340 {
6341 #if defined(_WIN32) || defined(_WIN64)
6342     char *c = NULL, *s = NULL, *t = NULL;
6343 #endif
6344     SQLRETURN ret;
6345 
6346     HSTMT_LOCK(stmt);
6347 #if defined(_WIN32) || defined(_WIN64)
6348     if (!((STMT *) stmt)->oemcp[0]) {
6349 	ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
6350 				 table, tableLen);
6351 	goto done2;
6352     }
6353     if (catalog) {
6354 	c = wmb_to_utf_c((char *) catalog, catalogLen);
6355 	if (!c) {
6356 	    ret = nomem((STMT *) stmt);
6357 	    goto done;
6358 	}
6359     }
6360     if (schema) {
6361 	s = wmb_to_utf_c((char *) schema, schemaLen);
6362 	if (!s) {
6363 	    ret = nomem((STMT *) stmt);
6364 	    goto done;
6365 	}
6366     }
6367     if (table) {
6368 	t = wmb_to_utf_c((char *) table, tableLen);
6369 	if (!t) {
6370 	    ret = nomem((STMT *) stmt);
6371 	    goto done;
6372 	}
6373     }
6374     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
6375 			     (SQLCHAR *) s, SQL_NTS,
6376 			     (SQLCHAR *) t, SQL_NTS);
6377 #else
6378     ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
6379 			     table, tableLen);
6380 #endif
6381 #if defined(_WIN32) || defined(_WIN64)
6382 done:
6383     uc_free(t);
6384     uc_free(s);
6385     uc_free(c);
6386 done2:
6387     ;
6388 #endif
6389     HSTMT_UNLOCK(stmt);
6390     return ret;
6391 }
6392 #endif
6393 
6394 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
6395 #ifdef WINTERFACE
6396 /**
6397  * Retrieve privileges on tables and/or views (UNICODE version).
6398  * @param stmt statement handle
6399  * @param catalog catalog name/pattern or NULL
6400  * @param catalogLen length of catalog name/pattern or SQL_NTS
6401  * @param schema schema name/pattern or NULL
6402  * @param schemaLen length of schema name/pattern or SQL_NTS
6403  * @param table table name/pattern or NULL
6404  * @param tableLen length of table name/pattern or SQL_NTS
6405  * @result ODBC error code
6406  */
6407 
6408 SQLRETURN SQL_API
SQLTablePrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)6409 SQLTablePrivilegesW(SQLHSTMT stmt,
6410 		    SQLWCHAR *catalog, SQLSMALLINT catalogLen,
6411 		    SQLWCHAR *schema, SQLSMALLINT schemaLen,
6412 		    SQLWCHAR *table, SQLSMALLINT tableLen)
6413 {
6414     char *c = NULL, *s = NULL, *t = NULL;
6415     SQLRETURN ret;
6416 
6417     HSTMT_LOCK(stmt);
6418     if (catalog) {
6419 	c = uc_to_utf_c(catalog, catalogLen);
6420 	if (!c) {
6421 	    ret = nomem((STMT *) stmt);
6422 	    goto done;
6423 	}
6424     }
6425     if (schema) {
6426 	s = uc_to_utf_c(schema, schemaLen);
6427 	if (!s) {
6428 	    ret = nomem((STMT *) stmt);
6429 	    goto done;
6430 	}
6431     }
6432     if (table) {
6433 	t = uc_to_utf_c(table, tableLen);
6434 	if (!t) {
6435 	    ret = nomem((STMT *) stmt);
6436 	    goto done;
6437 	}
6438     }
6439     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
6440 			     (SQLCHAR *) s, SQL_NTS,
6441 			     (SQLCHAR *) t, SQL_NTS);
6442 done:
6443     uc_free(t);
6444     uc_free(s);
6445     uc_free(c);
6446     HSTMT_UNLOCK(stmt);
6447     return ret;
6448 }
6449 #endif
6450 #endif
6451 
6452 /**
6453  * Columns for result set of SQLColumnPrivileges().
6454  */
6455 
6456 static COL colPrivSpec2[] = {
6457     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6458     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
6459     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
6460     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6461     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
6462     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
6463     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
6464 };
6465 
6466 static COL colPrivSpec3[] = {
6467     { "SYSTEM", "COLPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
6468     { "SYSTEM", "COLPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
6469     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
6470     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6471     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
6472     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
6473     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
6474 };
6475 
6476 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
6477 /**
6478  * Retrieve privileges on columns.
6479  * @param stmt statement handle
6480  * @param catalog catalog name/pattern or NULL
6481  * @param catalogLen length of catalog name/pattern or SQL_NTS
6482  * @param schema schema name/pattern or NULL
6483  * @param schemaLen length of schema name/pattern or SQL_NTS
6484  * @param table table name/pattern or NULL
6485  * @param tableLen length of table name/pattern or SQL_NTS
6486  * @param column column name or NULL
6487  * @param columnLen length of column name or SQL_NTS
6488  * @result ODBC error code
6489  */
6490 
6491 SQLRETURN SQL_API
SQLColumnPrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * column,SQLSMALLINT columnLen)6492 SQLColumnPrivileges(SQLHSTMT stmt,
6493 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
6494 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
6495 		    SQLCHAR *table, SQLSMALLINT tableLen,
6496 		    SQLCHAR *column, SQLSMALLINT columnLen)
6497 {
6498     SQLRETURN ret;
6499 
6500     HSTMT_LOCK(stmt);
6501     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
6502 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
6503     HSTMT_UNLOCK(stmt);
6504     return ret;
6505 }
6506 #endif
6507 
6508 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
6509 #ifdef WINTERFACE
6510 /**
6511  * Retrieve privileges on columns (UNICODE version).
6512  * @param stmt statement handle
6513  * @param catalog catalog name/pattern or NULL
6514  * @param catalogLen length of catalog name/pattern or SQL_NTS
6515  * @param schema schema name/pattern or NULL
6516  * @param schemaLen length of schema name/pattern or SQL_NTS
6517  * @param table table name/pattern or NULL
6518  * @param tableLen length of table name/pattern or SQL_NTS
6519  * @param column column name or NULL
6520  * @param columnLen length of column name or SQL_NTS
6521  * @result ODBC error code
6522  */
6523 
6524 SQLRETURN SQL_API
SQLColumnPrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * column,SQLSMALLINT columnLen)6525 SQLColumnPrivilegesW(SQLHSTMT stmt,
6526 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
6527 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
6528 		     SQLWCHAR *table, SQLSMALLINT tableLen,
6529 		     SQLWCHAR *column, SQLSMALLINT columnLen)
6530 {
6531     SQLRETURN ret;
6532 
6533     HSTMT_LOCK(stmt);
6534     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
6535 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
6536     HSTMT_UNLOCK(stmt);
6537     return ret;
6538 }
6539 #endif
6540 #endif
6541 
6542 /**
6543  * Columns for result set of SQLPrimaryKeys().
6544  */
6545 
6546 static COL pkeySpec2[] = {
6547     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6548     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
6549     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
6550     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6551     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
6552     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
6553 };
6554 
6555 static COL pkeySpec3[] = {
6556     { "SYSTEM", "PRIMARYKEY", "TABLE_CAT", SCOL_VARCHAR, 50 },
6557     { "SYSTEM", "PRIMARYKEY", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
6558     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
6559     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6560     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
6561     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
6562 };
6563 
6564 /**
6565  * Internal retrieve information about indexed columns.
6566  * @param stmt statement handle
6567  * @param cat catalog name/pattern or NULL
6568  * @param catLen length of catalog name/pattern or SQL_NTS
6569  * @param schema schema name/pattern or NULL
6570  * @param schemaLen length of schema name/pattern or SQL_NTS
6571  * @param table table name/pattern or NULL
6572  * @param tableLen length of table name/pattern or SQL_NTS
6573  * @result ODBC error code
6574  */
6575 
6576 static SQLRETURN
drvprimarykeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)6577 drvprimarykeys(SQLHSTMT stmt,
6578 	       SQLCHAR *cat, SQLSMALLINT catLen,
6579 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
6580 	       SQLCHAR *table, SQLSMALLINT tableLen)
6581 {
6582     STMT *s;
6583     DBC *d;
6584     SQLRETURN sret;
6585     int i, asize, ret, nrows, ncols, nrows2 = 0, ncols2 = 0;
6586     int namec = -1, uniquec = -1, namec2 = -1, uniquec2 = -1, offs, seq = 1;
6587     PTRDIFF_T size;
6588     char **rowp = NULL, **rowp2 = NULL, *errp = NULL, *sql, tname[512];
6589 
6590     sret = mkresultset(stmt, pkeySpec2, array_size(pkeySpec2),
6591 		       pkeySpec3, array_size(pkeySpec3), &asize);
6592     if (sret != SQL_SUCCESS) {
6593 	return sret;
6594     }
6595     s = (STMT *) stmt;
6596     d = (DBC *) s->dbc;
6597     if (!table || table[0] == '\0' || table[0] == '%') {
6598 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
6599 	return SQL_ERROR;
6600     }
6601     if (tableLen == SQL_NTS) {
6602 	size = sizeof (tname) - 1;
6603     } else {
6604 	size = min(sizeof (tname) - 1, tableLen);
6605     }
6606     strncpy(tname, (char *) table, size);
6607     tname[size] = '\0';
6608     unescpat(tname);
6609     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
6610     if (!sql) {
6611 	return nomem(s);
6612     }
6613     sret = starttran(s);
6614     if (sret != SQL_SUCCESS) {
6615 	sqlite3_free(sql);
6616 	return sret;
6617     }
6618     dbtraceapi(d, "sqlite3_get_table", sql);
6619     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
6620     sqlite3_free(sql);
6621     if (ret != SQLITE_OK) {
6622 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6623 		errp ? errp : "unknown error", ret);
6624 	if (errp) {
6625 	    sqlite3_free(errp);
6626 	    errp = NULL;
6627 	}
6628 	return SQL_ERROR;
6629     }
6630     if (errp) {
6631 	sqlite3_free(errp);
6632 	errp = NULL;
6633     }
6634     size = 0;
6635     if (ncols * nrows > 0) {
6636 	int typec;
6637 
6638 	namec = findcol(rowp, ncols, "name");
6639 	uniquec = findcol(rowp, ncols, "pk");
6640 	typec = findcol(rowp, ncols, "type");
6641 	if (namec >= 0 && uniquec >= 0 && typec >= 0) {
6642 	    for (i = 1; i <= nrows; i++) {
6643 		if (*rowp[i * ncols + uniquec] != '0') {
6644 		    size++;
6645 		}
6646 	    }
6647 	}
6648     }
6649     if (size == 0) {
6650 	sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
6651 	if (!sql) {
6652 	    sqlite3_free_table(rowp);
6653 	    return nomem(s);
6654 	}
6655 	dbtraceapi(d, "sqlite3_get_table", sql);
6656 	ret = sqlite3_get_table(d->sqlite, sql, &rowp2, &nrows2, &ncols2,
6657 				&errp);
6658 	sqlite3_free(sql);
6659 	if (ret != SQLITE_OK) {
6660 	    sqlite3_free_table(rowp);
6661 	    sqlite3_free_table(rowp2);
6662 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6663 		    errp ? errp : "unknown error", ret);
6664 	    if (errp) {
6665 		sqlite3_free(errp);
6666 		errp = NULL;
6667 	    }
6668 	    return SQL_ERROR;
6669 	}
6670 	if (errp) {
6671 	    sqlite3_free(errp);
6672 	    errp = NULL;
6673 	}
6674     }
6675     if (ncols2 * nrows2 > 0) {
6676 	namec2 = findcol(rowp2, ncols2, "name");
6677 	uniquec2 = findcol(rowp2, ncols2, "unique");
6678 	if (namec2 >= 0 && uniquec2 >=  0) {
6679 	    for (i = 1; i <= nrows2; i++) {
6680 		int nnrows, nncols, nlen = 0;
6681 		char **rowpp;
6682 
6683 		if (rowp2[i * ncols2 + namec2]) {
6684 		    nlen = strlen(rowp2[i * ncols2 + namec2]);
6685 		}
6686 		if (nlen < 17 ||
6687 		    strncmp(rowp2[i * ncols2 + namec2],
6688 			    "sqlite_autoindex_", 17)) {
6689 		    continue;
6690 		}
6691 		if (*rowp2[i * ncols2 + uniquec2] != '0') {
6692 		    ret = SQLITE_ERROR;
6693 		    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
6694 					  rowp2[i * ncols2 + namec2]);
6695 		    if (sql) {
6696 			dbtraceapi(d, "sqlite3_get_table", sql);
6697 			ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6698 						&nnrows, &nncols, NULL);
6699 			sqlite3_free(sql);
6700 		    }
6701 		    if (ret == SQLITE_OK) {
6702 			size += nnrows;
6703 			sqlite3_free_table(rowpp);
6704 		    }
6705 		}
6706 	    }
6707 	}
6708     }
6709     if (size == 0) {
6710 	sqlite3_free_table(rowp);
6711 	sqlite3_free_table(rowp2);
6712 	return SQL_SUCCESS;
6713     }
6714     s->nrows = size;
6715     size = (size + 1) * asize;
6716     s->rows = xmalloc((size + 1) * sizeof (char *));
6717     if (!s->rows) {
6718 	s->nrows = 0;
6719 	sqlite3_free_table(rowp);
6720 	sqlite3_free_table(rowp2);
6721 	return nomem(s);
6722     }
6723     s->rows[0] = (char *) size;
6724     s->rows += 1;
6725     memset(s->rows, 0, sizeof (char *) * size);
6726     s->rowfree = freerows;
6727     offs = s->ncols;
6728     if (rowp) {
6729 	for (i = 1; i <= nrows; i++) {
6730 	    if (*rowp[i * ncols + uniquec] != '0') {
6731 		char buf[32];
6732 
6733 #if defined(_WIN32) || defined(_WIN64)
6734 		s->rows[offs + 0] = xstrdup(d->xcelqrx ? "main" : "");
6735 		s->rows[offs + 1] = xstrdup("");
6736 #else
6737 		s->rows[offs + 0] = xstrdup("");
6738 		s->rows[offs + 1] = xstrdup("");
6739 #endif
6740 		s->rows[offs + 2] = xstrdup(tname);
6741 		s->rows[offs + 3] = xstrdup(rowp[i * ncols + namec]);
6742 		sprintf(buf, "%d", seq++);
6743 		s->rows[offs + 4] = xstrdup(buf);
6744 		offs += s->ncols;
6745 	    }
6746 	}
6747     }
6748     if (rowp2) {
6749 	for (i = 1; i <= nrows2; i++) {
6750 	    int nnrows, nncols, nlen = 0;
6751 	    char **rowpp;
6752 
6753 	    if (rowp2[i * ncols2 + namec2]) {
6754 		nlen = strlen(rowp2[i * ncols2 + namec2]);
6755 	    }
6756 	    if (nlen < 17 ||
6757 		strncmp(rowp2[i * ncols2 + namec2], "sqlite_autoindex_", 17)) {
6758 		continue;
6759 	    }
6760 	    if (*rowp2[i * ncols2 + uniquec2] != '0') {
6761 		int k;
6762 
6763 		ret = SQLITE_ERROR;
6764 		sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
6765 				      rowp2[i * ncols2 + namec2]);
6766 		if (sql) {
6767 		    dbtraceapi(d, "sqlite3_get_table", sql);
6768 		    ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6769 					    &nnrows, &nncols, NULL);
6770 		    sqlite3_free(sql);
6771 		}
6772 		if (ret != SQLITE_OK) {
6773 		    continue;
6774 		}
6775 		for (k = 0; nnrows && k < nncols; k++) {
6776 		    if (strcmp(rowpp[k], "name") == 0) {
6777 			int m;
6778 
6779 			for (m = 1; m <= nnrows; m++) {
6780 			    int roffs = offs + (m - 1) * s->ncols;
6781 
6782 #if defined(_WIN32) || defined(_WIN64)
6783 			    s->rows[roffs + 0] =
6784 				xstrdup(d->xcelqrx ? "main" : "");
6785 			    s->rows[roffs + 1] = xstrdup("");
6786 #else
6787 			    s->rows[roffs + 0] = xstrdup("");
6788 			    s->rows[roffs + 1] = xstrdup("");
6789 #endif
6790 			    s->rows[roffs + 2] = xstrdup(tname);
6791 			    s->rows[roffs + 3] =
6792 				xstrdup(rowpp[m * nncols + k]);
6793 			    s->rows[roffs + 5] =
6794 				xstrdup(rowp2[i * ncols2 + namec2]);
6795 			}
6796 		    } else if (strcmp(rowpp[k], "seqno") == 0) {
6797 			int m;
6798 
6799 			for (m = 1; m <= nnrows; m++) {
6800 			    int roffs = offs + (m - 1) * s->ncols;
6801 			    int pos = m - 1;
6802 			    char buf[32];
6803 
6804 			    sscanf(rowpp[m * nncols + k], "%d", &pos);
6805 			    sprintf(buf, "%d", pos + 1);
6806 			    s->rows[roffs + 4] = xstrdup(buf);
6807 			}
6808 		    }
6809 		}
6810 		offs += nnrows * s->ncols;
6811 		sqlite3_free_table(rowpp);
6812 	    }
6813 	}
6814     }
6815     sqlite3_free_table(rowp);
6816     sqlite3_free_table(rowp2);
6817     return SQL_SUCCESS;
6818 }
6819 
6820 #ifndef WINTERFACE
6821 /**
6822  * Retrieve information about indexed columns.
6823  * @param stmt statement handle
6824  * @param cat catalog name/pattern or NULL
6825  * @param catLen length of catalog name/pattern or SQL_NTS
6826  * @param schema schema name/pattern or NULL
6827  * @param schemaLen length of schema name/pattern or SQL_NTS
6828  * @param table table name/pattern or NULL
6829  * @param tableLen length of table name/pattern or SQL_NTS
6830  * @result ODBC error code
6831  */
6832 
6833 SQLRETURN SQL_API
SQLPrimaryKeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)6834 SQLPrimaryKeys(SQLHSTMT stmt,
6835 	       SQLCHAR *cat, SQLSMALLINT catLen,
6836 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
6837 	       SQLCHAR *table, SQLSMALLINT tableLen)
6838 {
6839 #if defined(_WIN32) || defined(_WIN64)
6840     char *c = NULL, *s = NULL, *t = NULL;
6841 #endif
6842     SQLRETURN ret;
6843 
6844     HSTMT_LOCK(stmt);
6845 #if defined(_WIN32) || defined(_WIN64)
6846     if (!((STMT *) stmt)->oemcp[0]) {
6847 	ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
6848 			     table, tableLen);
6849 	goto done2;
6850     }
6851     if (cat) {
6852 	c = wmb_to_utf_c((char *) cat, catLen);
6853 	if (!c) {
6854 	    ret = nomem((STMT *) stmt);
6855 	    goto done;
6856 	}
6857     }
6858     if (schema) {
6859 	s = wmb_to_utf_c((char *) schema, schemaLen);
6860 	if (!s) {
6861 	    ret = nomem((STMT *) stmt);
6862 	    goto done;
6863 	}
6864     }
6865     if (table) {
6866 	t = wmb_to_utf_c((char *) table, tableLen);
6867 	if (!t) {
6868 	    ret = nomem((STMT *) stmt);
6869 	    goto done;
6870 	}
6871     }
6872     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
6873 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
6874 #else
6875     ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
6876 			 table, tableLen);
6877 #endif
6878 #if defined(_WIN32) || defined(_WIN64)
6879 done:
6880     uc_free(t);
6881     uc_free(s);
6882     uc_free(c);
6883 done2:
6884     ;
6885 #endif
6886     HSTMT_UNLOCK(stmt);
6887     return ret;
6888 }
6889 #endif
6890 
6891 #ifdef WINTERFACE
6892 /**
6893  * Retrieve information about indexed columns (UNICODE version).
6894  * @param stmt statement handle
6895  * @param cat catalog name/pattern or NULL
6896  * @param catLen length of catalog name/pattern or SQL_NTS
6897  * @param schema schema name/pattern or NULL
6898  * @param schemaLen length of schema name/pattern or SQL_NTS
6899  * @param table table name/pattern or NULL
6900  * @param tableLen length of table name/pattern or SQL_NTS
6901  * @result ODBC error code
6902  */
6903 
6904 SQLRETURN SQL_API
SQLPrimaryKeysW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)6905 SQLPrimaryKeysW(SQLHSTMT stmt,
6906 		SQLWCHAR *cat, SQLSMALLINT catLen,
6907 		SQLWCHAR *schema, SQLSMALLINT schemaLen,
6908 		SQLWCHAR *table, SQLSMALLINT tableLen)
6909 {
6910     char *c = NULL, *s = NULL, *t = NULL;
6911     SQLRETURN ret;
6912 
6913     HSTMT_LOCK(stmt);
6914     if (cat) {
6915 	c = uc_to_utf_c(cat, catLen);
6916 	if (!c) {
6917 	    ret = nomem((STMT *) stmt);
6918 	    goto done;
6919 	}
6920     }
6921     if (schema) {
6922 	s = uc_to_utf_c(schema, schemaLen);
6923 	if (!s) {
6924 	    ret = nomem((STMT *) stmt);
6925 	    goto done;
6926 	}
6927     }
6928     if (table) {
6929 	t = uc_to_utf_c(table, tableLen);
6930 	if (!t) {
6931 	    ret = nomem((STMT *) stmt);
6932 	    goto done;
6933 	}
6934     }
6935     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
6936 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
6937 done:
6938     uc_free(t);
6939     uc_free(s);
6940     uc_free(c);
6941     HSTMT_UNLOCK(stmt);
6942     return ret;
6943 }
6944 #endif
6945 
6946 /**
6947  * Columns for result set of SQLSpecialColumns().
6948  */
6949 
6950 static COL scolSpec2[] = {
6951     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
6952     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6953     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
6954     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
6955     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
6956     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
6957     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
6958     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
6959     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
6960 };
6961 
6962 static COL scolSpec3[] = {
6963     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
6964     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6965     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
6966     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
6967     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
6968     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
6969     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
6970     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
6971     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
6972 };
6973 
6974 /**
6975  * Internal retrieve information about indexed columns.
6976  * @param stmt statement handle
6977  * @param id type of information, e.g. best row id
6978  * @param cat catalog name/pattern or NULL
6979  * @param catLen length of catalog name/pattern or SQL_NTS
6980  * @param schema schema name/pattern or NULL
6981  * @param schemaLen length of schema name/pattern or SQL_NTS
6982  * @param table table name/pattern or NULL
6983  * @param tableLen length of table name/pattern or SQL_NTS
6984  * @param scope
6985  * @param nullable
6986  * @result ODBC error code
6987  */
6988 
6989 static SQLRETURN
drvspecialcolumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6990 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
6991 		  SQLCHAR *cat, SQLSMALLINT catLen,
6992 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
6993 		  SQLCHAR *table, SQLSMALLINT tableLen,
6994 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
6995 {
6996     STMT *s;
6997     DBC *d;
6998     SQLRETURN sret;
6999     int i, asize, ret, nrows, ncols, nnnrows, nnncols, offs;
7000     PTRDIFF_T size;
7001     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
7002     int notnullcc = -1, mkrowid = 0;
7003     char *errp = NULL, *sql, tname[512];
7004     char **rowp = NULL, **rowppp = NULL;
7005 
7006     sret = mkresultset(stmt, scolSpec2, array_size(scolSpec2),
7007 		       scolSpec3, array_size(scolSpec3), &asize);
7008     if (sret != SQL_SUCCESS) {
7009 	return sret;
7010     }
7011     s = (STMT *) stmt;
7012     d = (DBC *) s->dbc;
7013     if (!table || table[0] == '\0' || table[0] == '%') {
7014 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
7015 	return SQL_ERROR;
7016     }
7017     if (tableLen == SQL_NTS) {
7018 	size = sizeof (tname) - 1;
7019     } else {
7020 	size = min(sizeof (tname) - 1, tableLen);
7021     }
7022     strncpy(tname, (char *) table, size);
7023     tname[size] = '\0';
7024     unescpat(tname);
7025     if (id != SQL_BEST_ROWID) {
7026 	return SQL_SUCCESS;
7027     }
7028     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
7029     if (!sql) {
7030 	return nomem(s);
7031     }
7032     sret = starttran(s);
7033     if (sret != SQL_SUCCESS) {
7034 	sqlite3_free(sql);
7035 	return sret;
7036     }
7037     dbtraceapi(d, "sqlite3_get_table", sql);
7038     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
7039     sqlite3_free(sql);
7040     if (ret != SQLITE_OK) {
7041 doerr:
7042 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7043 		errp ? errp : "unknown error", ret);
7044 	if (errp) {
7045 	    sqlite3_free(errp);
7046 	    errp = NULL;
7047 	}
7048 	return SQL_ERROR;
7049     }
7050     if (errp) {
7051 	sqlite3_free(errp);
7052 	errp = NULL;
7053     }
7054     size = 0; /* number result rows */
7055     if (ncols * nrows <= 0) {
7056 	goto nodata_but_rowid;
7057     }
7058     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
7059     if (!sql) {
7060 	return nomem(s);
7061     }
7062     dbtraceapi(d, "sqlite3_get_table", sql);
7063     ret = sqlite3_get_table(d->sqlite, sql, &rowppp, &nnnrows, &nnncols,
7064 			    &errp);
7065     sqlite3_free(sql);
7066     if (ret != SQLITE_OK) {
7067 	sqlite3_free_table(rowp);
7068 	goto doerr;
7069     }
7070     if (errp) {
7071 	sqlite3_free(errp);
7072 	errp = NULL;
7073     }
7074     namec = findcol(rowp, ncols, "name");
7075     uniquec = findcol(rowp, ncols, "unique");
7076     if (namec < 0 || uniquec < 0) {
7077 	goto nodata_but_rowid;
7078     }
7079     namecc = findcol(rowppp, nnncols, "name");
7080     typecc = findcol(rowppp, nnncols, "type");
7081     notnullcc = findcol(rowppp, nnncols, "notnull");
7082     for (i = 1; i <= nrows; i++) {
7083 	int nnrows, nncols;
7084 	char **rowpp = NULL;
7085 
7086 	if (*rowp[i * ncols + uniquec] != '0') {
7087 	    ret = SQLITE_ERROR;
7088 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
7089 				  rowp[i * ncols + namec]);
7090 	    if (sql) {
7091 		dbtraceapi(d, "sqlite3_get_table", sql);
7092 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
7093 					&nnrows, &nncols, NULL);
7094 		sqlite3_free(sql);
7095 	    }
7096 	    if (ret == SQLITE_OK) {
7097 		size += nnrows;
7098 		sqlite3_free_table(rowpp);
7099 	    }
7100 	}
7101     }
7102 nodata_but_rowid:
7103     if (size == 0) {
7104 	size = 1;
7105 	mkrowid = 1;
7106     }
7107     s->nrows = size;
7108     size = (size + 1) * asize;
7109     s->rows = xmalloc((size + 1) * sizeof (char *));
7110     if (!s->rows) {
7111 	s->nrows = 0;
7112 	sqlite3_free_table(rowp);
7113 	sqlite3_free_table(rowppp);
7114 	return nomem(s);
7115     }
7116     s->rows[0] = (char *) size;
7117     s->rows += 1;
7118     memset(s->rows, 0, sizeof (char *) * size);
7119     s->rowfree = freerows;
7120     if (mkrowid) {
7121 	s->nrows = 0;
7122 	goto mkrowid;
7123     }
7124     offs = 0;
7125     for (i = 1; i <= nrows; i++) {
7126 	int nnrows, nncols;
7127 	char **rowpp = NULL;
7128 
7129 	if (*rowp[i * ncols + uniquec] != '0') {
7130 	    int k;
7131 
7132 	    ret = SQLITE_ERROR;
7133 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
7134 				  rowp[i * ncols + namec]);
7135 	    if (sql) {
7136 		dbtraceapi(d, "sqlite3_get_table", sql);
7137 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
7138 					&nnrows, &nncols, NULL);
7139 		sqlite3_free(sql);
7140 	    }
7141 	    if (ret != SQLITE_OK) {
7142 		continue;
7143 	    }
7144 	    for (k = 0; nnrows && k < nncols; k++) {
7145 		if (strcmp(rowpp[k], "name") == 0) {
7146 		    int m;
7147 
7148 		    for (m = 1; m <= nnrows; m++) {
7149 			int roffs = (offs + m) * s->ncols;
7150 
7151 			s->rows[roffs + 0] =
7152 			    xstrdup(stringify(SQL_SCOPE_SESSION));
7153 			s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
7154 			s->rows[roffs + 4] = xstrdup("0");
7155 			s->rows[roffs + 7] =
7156 			    xstrdup(stringify(SQL_PC_NOT_PSEUDO));
7157 			if (namecc >= 0 && typecc >= 0) {
7158 			    int ii;
7159 
7160 			    for (ii = 1; ii <= nnnrows; ii++) {
7161 				if (strcmp(rowppp[ii * nnncols + namecc],
7162 					   rowpp[m * nncols + k]) == 0) {
7163 				    char *typen = rowppp[ii * nnncols + typecc];
7164 				    int sqltype, mm, dd, isnullable = 0;
7165 				    char buf[32];
7166 
7167 				    s->rows[roffs + 3] = xstrdup(typen);
7168 				    sqltype = mapsqltype(typen, NULL, *s->ov3,
7169 							 s->nowchar[0],
7170 							 s->dobigint);
7171 				    getmd(typen, sqltype, &mm, &dd);
7172 #ifdef SQL_LONGVARCHAR
7173 				    if (sqltype == SQL_VARCHAR && mm > 255) {
7174 					sqltype = SQL_LONGVARCHAR;
7175 				    }
7176 #endif
7177 #ifdef WINTERFACE
7178 #ifdef SQL_WLONGVARCHAR
7179 				    if (sqltype == SQL_WVARCHAR && mm > 255) {
7180 					sqltype = SQL_WLONGVARCHAR;
7181 				    }
7182 #endif
7183 #endif
7184 				    if (sqltype == SQL_VARBINARY && mm > 255) {
7185 					sqltype = SQL_LONGVARBINARY;
7186 				    }
7187 				    sprintf(buf, "%d", sqltype);
7188 				    s->rows[roffs + 2] = xstrdup(buf);
7189 				    sprintf(buf, "%d", mm);
7190 				    s->rows[roffs + 5] = xstrdup(buf);
7191 				    sprintf(buf, "%d", dd);
7192 				    s->rows[roffs + 6] = xstrdup(buf);
7193 				    if (notnullcc >= 0) {
7194 					char *inp =
7195 					   rowppp[ii * nnncols + notnullcc];
7196 
7197 					isnullable = inp[0] != '0';
7198 				    }
7199 				    sprintf(buf, "%d", isnullable);
7200 				    s->rows[roffs + 8] = xstrdup(buf);
7201 				}
7202 			    }
7203 			}
7204 		    }
7205 		}
7206 	    }
7207 	    offs += nnrows;
7208 	    sqlite3_free_table(rowpp);
7209 	}
7210     }
7211     if (nullable == SQL_NO_NULLS) {
7212 	for (i = 1; i < s->nrows; i++) {
7213 	    if (s->rows[i * s->ncols + 8][0] == '0') {
7214 		int m, i1 = i + 1;
7215 
7216 		for (m = 0; m < s->ncols; m++) {
7217 		    freep(&s->rows[i * s->ncols + m]);
7218 		}
7219 		size = s->ncols * sizeof (char *) * (s->nrows - i1);
7220 		if (size > 0) {
7221 		    memmove(s->rows + i * s->ncols,
7222 			    s->rows + i1 * s->ncols,
7223 			    size);
7224 		    memset(s->rows + s->nrows * s->ncols, 0,
7225 			   s->ncols * sizeof (char *));
7226 		}
7227 		s->nrows--;
7228 		--i;
7229 	    }
7230 	}
7231     }
7232 mkrowid:
7233     sqlite3_free_table(rowp);
7234     sqlite3_free_table(rowppp);
7235     if (s->nrows == 0) {
7236 	s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
7237 	s->rows[s->ncols + 1] = xstrdup("_ROWID_");
7238 	s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
7239 	s->rows[s->ncols + 3] = xstrdup("integer");
7240 	s->rows[s->ncols + 4] = xstrdup("0");
7241 	s->rows[s->ncols + 5] = xstrdup("10");
7242 	s->rows[s->ncols + 6] = xstrdup("9");
7243 	s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
7244 	s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
7245 	s->nrows = 1;
7246     }
7247     return SQL_SUCCESS;
7248 }
7249 
7250 #ifndef WINTERFACE
7251 /**
7252  * Retrieve information about indexed columns.
7253  * @param stmt statement handle
7254  * @param id type of information, e.g. best row id
7255  * @param cat catalog name/pattern or NULL
7256  * @param catLen length of catalog name/pattern or SQL_NTS
7257  * @param schema schema name/pattern or NULL
7258  * @param schemaLen length of schema name/pattern or SQL_NTS
7259  * @param table table name/pattern or NULL
7260  * @param tableLen length of table name/pattern or SQL_NTS
7261  * @param scope
7262  * @param nullable
7263  * @result ODBC error code
7264  */
7265 
7266 SQLRETURN SQL_API
SQLSpecialColumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)7267 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
7268 		  SQLCHAR *cat, SQLSMALLINT catLen,
7269 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
7270 		  SQLCHAR *table, SQLSMALLINT tableLen,
7271 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
7272 {
7273 #if defined(_WIN32) || defined(_WIN64)
7274     char *c = NULL, *s = NULL, *t = NULL;
7275 #endif
7276     SQLRETURN ret;
7277 
7278     HSTMT_LOCK(stmt);
7279 #if defined(_WIN32) || defined(_WIN64)
7280     if (!((STMT *) stmt)->oemcp[0]) {
7281 	ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
7282 				table, tableLen, scope, nullable);
7283 	goto done2;
7284     }
7285     if (cat) {
7286 	c = wmb_to_utf_c((char *) cat, catLen);
7287 	if (!c) {
7288 	    ret = nomem((STMT *) stmt);
7289 	    goto done;
7290 	}
7291     }
7292     if (schema) {
7293 	s = wmb_to_utf_c((char *) schema, schemaLen);
7294 	if (!s) {
7295 	    ret = nomem((STMT *) stmt);
7296 	    goto done;
7297 	}
7298     }
7299     if (table) {
7300 	t = wmb_to_utf_c((char *) table, tableLen);
7301 	if (!t) {
7302 	    ret = nomem((STMT *) stmt);
7303 	    goto done;
7304 	}
7305     }
7306     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
7307 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
7308 			    scope, nullable);
7309 #else
7310     ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
7311 			    table, tableLen, scope, nullable);
7312 #endif
7313 #if defined(_WIN32) || defined(_WIN64)
7314 done:
7315     uc_free(t);
7316     uc_free(s);
7317     uc_free(c);
7318 done2:
7319     ;
7320 #endif
7321     HSTMT_UNLOCK(stmt);
7322     return ret;
7323 }
7324 #endif
7325 
7326 #ifdef WINTERFACE
7327 /**
7328  * Retrieve information about indexed columns (UNICODE version).
7329  * @param stmt statement handle
7330  * @param id type of information, e.g. best row id
7331  * @param cat catalog name/pattern or NULL
7332  * @param catLen length of catalog name/pattern or SQL_NTS
7333  * @param schema schema name/pattern or NULL
7334  * @param schemaLen length of schema name/pattern or SQL_NTS
7335  * @param table table name/pattern or NULL
7336  * @param tableLen length of table name/pattern or SQL_NTS
7337  * @param scope
7338  * @param nullable
7339  * @result ODBC error code
7340  */
7341 
7342 SQLRETURN SQL_API
SQLSpecialColumnsW(SQLHSTMT stmt,SQLUSMALLINT id,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)7343 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
7344 		   SQLWCHAR *cat, SQLSMALLINT catLen,
7345 		   SQLWCHAR *schema, SQLSMALLINT schemaLen,
7346 		   SQLWCHAR *table, SQLSMALLINT tableLen,
7347 		   SQLUSMALLINT scope, SQLUSMALLINT nullable)
7348 {
7349     char *c = NULL, *s = NULL, *t = NULL;
7350     SQLRETURN ret;
7351 
7352     HSTMT_LOCK(stmt);
7353     if (cat) {
7354 	c = uc_to_utf_c(cat, catLen);
7355 	if (!c) {
7356 	    ret = nomem((STMT *) stmt);
7357 	    goto done;
7358 	}
7359     }
7360     if (schema) {
7361 	s = uc_to_utf_c(schema, schemaLen);
7362 	if (!s) {
7363 	    ret = nomem((STMT *) stmt);
7364 	    goto done;
7365 	}
7366     }
7367     if (table) {
7368 	t = uc_to_utf_c(table, tableLen);
7369 	if (!t) {
7370 	    ret = nomem((STMT *) stmt);
7371 	    goto done;
7372 	}
7373     }
7374     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
7375 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
7376 			    scope, nullable);
7377 done:
7378     uc_free(t);
7379     uc_free(s);
7380     uc_free(c);
7381     HSTMT_UNLOCK(stmt);
7382     return ret;
7383 }
7384 #endif
7385 
7386 /**
7387  * Columns for result set of SQLForeignKeys().
7388  */
7389 
7390 static COL fkeySpec2[] = {
7391     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
7392     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
7393     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
7394     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
7395     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
7396     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
7397     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
7398     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
7399     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
7400     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
7401     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
7402     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
7403     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
7404     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
7405 };
7406 
7407 static COL fkeySpec3[] = {
7408     { "SYSTEM", "FOREIGNKEY", "PKTABLE_CAT", SCOL_VARCHAR, 50 },
7409     { "SYSTEM", "FOREIGNKEY", "PKTABLE_SCHEM", SCOL_VARCHAR, 50 },
7410     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
7411     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
7412     { "SYSTEM", "FOREIGNKEY", "FKTABLE_CAT", SCOL_VARCHAR, 50 },
7413     { "SYSTEM", "FOREIGNKEY", "FKTABLE_SCHEM", SCOL_VARCHAR, 50 },
7414     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
7415     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
7416     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
7417     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
7418     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
7419     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
7420     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
7421     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
7422 };
7423 
7424 /**
7425  * Internal retrieve information about primary/foreign keys.
7426  * @param stmt statement handle
7427  * @param PKcatalog primary key catalog name/pattern or NULL
7428  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7429  * @param PKschema primary key schema name/pattern or NULL
7430  * @param PKschemaLen length of PKschema or SQL_NTS
7431  * @param PKtable primary key table name/pattern or NULL
7432  * @param PKtableLen length of PKtable or SQL_NTS
7433  * @param FKcatalog foreign key catalog name/pattern or NULL
7434  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7435  * @param FKschema foreign key schema name/pattern or NULL
7436  * @param FKschemaLen length of FKschema or SQL_NTS
7437  * @param FKtable foreign key table name/pattern or NULL
7438  * @param FKtableLen length of FKtable or SQL_NTS
7439  * @result ODBC error code
7440  */
7441 
7442 static SQLRETURN SQL_API
drvforeignkeys(SQLHSTMT stmt,SQLCHAR * PKcatalog,SQLSMALLINT PKcatalogLen,SQLCHAR * PKschema,SQLSMALLINT PKschemaLen,SQLCHAR * PKtable,SQLSMALLINT PKtableLen,SQLCHAR * FKcatalog,SQLSMALLINT FKcatalogLen,SQLCHAR * FKschema,SQLSMALLINT FKschemaLen,SQLCHAR * FKtable,SQLSMALLINT FKtableLen)7443 drvforeignkeys(SQLHSTMT stmt,
7444 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7445 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
7446 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
7447 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7448 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
7449 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
7450 {
7451     STMT *s;
7452     DBC *d;
7453     SQLRETURN sret;
7454     int i, asize, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
7455     int onu, ond;
7456     PTRDIFF_T size;
7457     char **rowp, *errp = NULL, *sql, pname[512], fname[512];
7458 
7459     sret = mkresultset(stmt, fkeySpec2, array_size(fkeySpec2),
7460 		       fkeySpec3, array_size(fkeySpec3), &asize);
7461     if (sret != SQL_SUCCESS) {
7462 	return sret;
7463     }
7464     s = (STMT *) stmt;
7465     sret = starttran(s);
7466     if (sret != SQL_SUCCESS) {
7467 	return sret;
7468     }
7469     d = (DBC *) s->dbc;
7470     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
7471 	(!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
7472 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
7473 	return SQL_ERROR;
7474     }
7475     size = 0;
7476     if (PKtable) {
7477 	if (PKtableLen == SQL_NTS) {
7478 	    size = sizeof (pname) - 1;
7479 	} else {
7480 	    size = min(sizeof (pname) - 1, PKtableLen);
7481 	}
7482 	strncpy(pname, (char *) PKtable, size);
7483     }
7484     pname[size] = '\0';
7485     size = 0;
7486     if (FKtable) {
7487 
7488 	if (FKtableLen == SQL_NTS) {
7489 	    size = sizeof (fname) - 1;
7490 	} else {
7491 	    size = min(sizeof (fname) - 1, FKtableLen);
7492 	}
7493 	strncpy(fname, (char *) FKtable, size);
7494     }
7495     fname[size] = '\0';
7496     if (fname[0] != '\0') {
7497 	int plen;
7498 
7499 	ret = SQLITE_ERROR;
7500 	sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", fname);
7501 	if (sql) {
7502 	    dbtraceapi(d, "sqlite3_get_table", sql);
7503 	    ret = sqlite3_get_table(d->sqlite, sql, &rowp,
7504 				    &nrows, &ncols, &errp);
7505 	    sqlite3_free(sql);
7506 	}
7507 	if (ret != SQLITE_OK) {
7508 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7509 		    errp ? errp : "unknown error", ret);
7510 	    if (errp) {
7511 		sqlite3_free(errp);
7512 		errp = NULL;
7513 	    }
7514 	    return SQL_ERROR;
7515 	}
7516 	if (errp) {
7517 	    sqlite3_free(errp);
7518 	    errp = NULL;
7519 	}
7520 	if (ncols * nrows <= 0) {
7521 nodata:
7522 	    sqlite3_free_table(rowp);
7523 	    return SQL_SUCCESS;
7524 	}
7525 	size = 0;
7526 	namec = findcol(rowp, ncols, "table");
7527 	seqc = findcol(rowp, ncols, "seq");
7528 	fromc = findcol(rowp, ncols, "from");
7529 	toc = findcol(rowp, ncols, "to");
7530 	onu = findcol(rowp, ncols, "on_update");
7531 	ond = findcol(rowp, ncols, "on_delete");
7532 	if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
7533 	    goto nodata;
7534 	}
7535 	plen = strlen(pname);
7536 	for (i = 1; i <= nrows; i++) {
7537 	    char *ptab = unquote(rowp[i * ncols + namec]);
7538 
7539 	    if (plen && ptab) {
7540 		int len = strlen(ptab);
7541 
7542 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
7543 		    continue;
7544 		}
7545 	    }
7546 	    size++;
7547 	}
7548 	if (size == 0) {
7549 	    goto nodata;
7550 	}
7551 	s->nrows = size;
7552 	size = (size + 1) * asize;
7553 	s->rows = xmalloc((size + 1) * sizeof (char *));
7554 	if (!s->rows) {
7555 	    s->nrows = 0;
7556 	    return nomem(s);
7557 	}
7558 	s->rows[0] = (char *) size;
7559 	s->rows += 1;
7560 	memset(s->rows, 0, sizeof (char *) * size);
7561 	s->rowfree = freerows;
7562 	offs = 0;
7563 	for (i = 1; i <= nrows; i++) {
7564 	    int pos = 0, roffs = (offs + 1) * s->ncols;
7565 	    char *ptab = rowp[i * ncols + namec];
7566 	    char buf[32];
7567 
7568 	    if (plen && ptab) {
7569 		int len = strlen(ptab);
7570 
7571 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
7572 		    continue;
7573 		}
7574 	    }
7575 #if defined(_WIN32) || defined(_WIN64)
7576 	    s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
7577 	    s->rows[roffs + 1] = xstrdup("");
7578 #else
7579 	    s->rows[roffs + 0] = xstrdup("");
7580 	    s->rows[roffs + 1] = xstrdup("");
7581 #endif
7582 	    s->rows[roffs + 2] = xstrdup(ptab);
7583 	    s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
7584 	    s->rows[roffs + 4] = xstrdup("");
7585 	    s->rows[roffs + 5] = xstrdup("");
7586 	    s->rows[roffs + 6] = xstrdup(fname);
7587 	    s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
7588 	    sscanf(rowp[i * ncols + seqc], "%d", &pos);
7589 	    sprintf(buf, "%d", pos + 1);
7590 	    s->rows[roffs + 8] = xstrdup(buf);
7591 	    if (onu < 0) {
7592 		s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7593 	    } else {
7594 		if (strcmp(rowp[i * ncols + onu], "SET NULL") == 0) {
7595 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
7596 		} else if (strcmp(rowp[i * ncols + onu], "SET DEFAULT") == 0) {
7597 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_DEFAULT));
7598 		} else if (strcmp(rowp[i * ncols + onu], "CASCADE") == 0) {
7599 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
7600 		} else if (strcmp(rowp[i * ncols + onu], "RESTRICT") == 0) {
7601 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
7602 		} else {
7603 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7604 		}
7605 	    }
7606 	    if (ond < 0) {
7607 		s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7608 	    } else {
7609 		if (strcmp(rowp[i * ncols + ond], "SET NULL") == 0) {
7610 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
7611 		} else if (strcmp(rowp[i * ncols + ond], "SET DEFAULT") == 0) {
7612 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_DEFAULT));
7613 		} else if (strcmp(rowp[i * ncols + ond], "CASCADE") == 0) {
7614 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
7615 		} else if (strcmp(rowp[i * ncols + ond], "RESTRICT") == 0) {
7616 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
7617 		} else {
7618 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7619 		}
7620 	    }
7621 	    s->rows[roffs + 11] = NULL;
7622 	    s->rows[roffs + 12] = NULL;
7623 	    s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
7624 	    offs++;
7625 	}
7626 	sqlite3_free_table(rowp);
7627     } else {
7628 	int nnrows, nncols, plen = strlen(pname);
7629 	char **rowpp;
7630 
7631 	sql = "select name from sqlite_master where type='table'";
7632 	dbtraceapi(d, "sqlite3_get_table", sql);
7633 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
7634 	if (ret != SQLITE_OK) {
7635 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7636 		    errp ? errp : "unknown error", ret);
7637 	    if (errp) {
7638 		sqlite3_free(errp);
7639 		errp = NULL;
7640 	    }
7641 	    return SQL_ERROR;
7642 	}
7643 	if (errp) {
7644 	    sqlite3_free(errp);
7645 	    errp = NULL;
7646 	}
7647 	if (ncols * nrows <= 0) {
7648 	    goto nodata;
7649 	}
7650 	size = 0;
7651 	for (i = 1; i <= nrows; i++) {
7652 	    int k;
7653 
7654 	    if (!rowp[i]) {
7655 		continue;
7656 	    }
7657 	    rowpp = NULL;
7658 	    ret = SQLITE_ERROR;
7659 	    sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
7660 	    if (sql) {
7661 		dbtraceapi(d, "sqlite3_get_table", sql);
7662 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
7663 				      &nnrows, &nncols, NULL);
7664 		sqlite3_free(sql);
7665 	    }
7666 	    if (ret != SQLITE_OK || nncols * nnrows <= 0) {
7667 		sqlite3_free_table(rowpp);
7668 		continue;
7669 	    }
7670 	    namec = findcol(rowpp, nncols, "table");
7671 	    seqc = findcol(rowpp, nncols, "seq");
7672 	    fromc = findcol(rowpp, nncols, "from");
7673 	    toc = findcol(rowpp, nncols, "to");
7674 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
7675 		sqlite3_free_table(rowpp);
7676 		continue;
7677 	    }
7678 	    for (k = 1; k <= nnrows; k++) {
7679 		char *ptab = unquote(rowpp[k * nncols + namec]);
7680 
7681 		if (plen && ptab) {
7682 		    int len = strlen(ptab);
7683 
7684 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
7685 			continue;
7686 		    }
7687 		}
7688 		size++;
7689 	    }
7690 	    sqlite3_free_table(rowpp);
7691 	}
7692 	if (size == 0) {
7693 	    goto nodata;
7694 	}
7695 	s->nrows = size;
7696 	size = (size + 1) * asize;
7697 	s->rows = xmalloc((size + 1) * sizeof (char *));
7698 	if (!s->rows) {
7699 	    s->nrows = 0;
7700 	    return nomem(s);
7701 	}
7702 	s->rows[0] = (char *) size;
7703 	s->rows += 1;
7704 	memset(s->rows, 0, sizeof (char *) * size);
7705 	s->rowfree = freerows;
7706 	offs = 0;
7707 	for (i = 1; i <= nrows; i++) {
7708 	    int k;
7709 
7710 	    if (!rowp[i]) {
7711 		continue;
7712 	    }
7713 	    rowpp = NULL;
7714 	    ret = SQLITE_ERROR;
7715 	    sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
7716 	    if (sql) {
7717 		dbtraceapi(d, "sqlite3_get_table", sql);
7718 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
7719 					&nnrows, &nncols, NULL);
7720 		sqlite3_free(sql);
7721 	    }
7722 	    if (ret != SQLITE_OK || nncols * nnrows <= 0) {
7723 		sqlite3_free_table(rowpp);
7724 		continue;
7725 	    }
7726 	    namec = findcol(rowpp, nncols, "table");
7727 	    seqc = findcol(rowpp, nncols, "seq");
7728 	    fromc = findcol(rowpp, nncols, "from");
7729 	    toc = findcol(rowpp, nncols, "to");
7730 	    onu = findcol(rowpp, nncols, "on_update");
7731 	    ond = findcol(rowpp, nncols, "on_delete");
7732 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
7733 		sqlite3_free_table(rowpp);
7734 		continue;
7735 	    }
7736 	    for (k = 1; k <= nnrows; k++) {
7737 		int pos = 0, roffs = (offs + 1) * s->ncols;
7738 		char *ptab = unquote(rowpp[k * nncols + namec]);
7739 		char buf[32];
7740 
7741 		if (plen && ptab) {
7742 		    int len = strlen(ptab);
7743 
7744 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
7745 			continue;
7746 		    }
7747 		}
7748 #if defined(_WIN32) || defined(_WIN64)
7749 		s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
7750 		s->rows[roffs + 1] = xstrdup("");
7751 #else
7752 		s->rows[roffs + 0] = xstrdup("");
7753 		s->rows[roffs + 1] = xstrdup("");
7754 #endif
7755 		s->rows[roffs + 2] = xstrdup(ptab);
7756 		s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
7757 		s->rows[roffs + 4] = xstrdup("");
7758 		s->rows[roffs + 5] = xstrdup("");
7759 		s->rows[roffs + 6] = xstrdup(rowp[i]);
7760 		s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
7761 		sscanf(rowpp[k * nncols + seqc], "%d", &pos);
7762 		sprintf(buf, "%d", pos + 1);
7763 		s->rows[roffs + 8] = xstrdup(buf);
7764 		if (onu < 0) {
7765 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7766 		} else {
7767 		    if (strcmp(rowpp[k * nncols + onu], "SET NULL") == 0) {
7768 			s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
7769 		    } else if (strcmp(rowpp[k * nncols + onu], "SET DEFAULT")
7770 			       == 0) {
7771 			s->rows[roffs + 9] =
7772 			    xstrdup(stringify(SQL_SET_DEFAULT));
7773 		    } else if (strcmp(rowpp[k * nncols + onu], "CASCADE")
7774 			       == 0) {
7775 			s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
7776 		    } else if (strcmp(rowpp[k * nncols + onu], "RESTRICT")
7777 			       == 0) {
7778 			s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
7779 		    } else {
7780 			s->rows[roffs + 9] =
7781 			    xstrdup(stringify(SQL_NO_ACTION));
7782 		    }
7783 		}
7784 		if (ond < 0) {
7785 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7786 		} else {
7787 		    if (strcmp(rowpp[k * nncols + ond], "SET NULL") == 0) {
7788 			s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
7789 		    } else if (strcmp(rowpp[k * nncols + ond], "SET DEFAULT")
7790 			       == 0) {
7791 			s->rows[roffs + 10] =
7792 			    xstrdup(stringify(SQL_SET_DEFAULT));
7793 		    } else if (strcmp(rowpp[k * nncols + ond], "CASCADE")
7794 			       == 0) {
7795 			s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
7796 		    } else if (strcmp(rowpp[k * nncols + ond], "RESTRICT")
7797 			       == 0) {
7798 			s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
7799 		    } else {
7800 			s->rows[roffs + 10] =
7801 			    xstrdup(stringify(SQL_NO_ACTION));
7802 		    }
7803 		}
7804 		s->rows[roffs + 11] = NULL;
7805 		s->rows[roffs + 12] = NULL;
7806 		s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
7807 		offs++;
7808 	    }
7809 	    sqlite3_free_table(rowpp);
7810 	}
7811 	sqlite3_free_table(rowp);
7812     }
7813     return SQL_SUCCESS;
7814 }
7815 
7816 #ifndef WINTERFACE
7817 /**
7818  * Retrieve information about primary/foreign keys.
7819  * @param stmt statement handle
7820  * @param PKcatalog primary key catalog name/pattern or NULL
7821  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7822  * @param PKschema primary key schema name/pattern or NULL
7823  * @param PKschemaLen length of PKschema or SQL_NTS
7824  * @param PKtable primary key table name/pattern or NULL
7825  * @param PKtableLen length of PKtable or SQL_NTS
7826  * @param FKcatalog foreign key catalog name/pattern or NULL
7827  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7828  * @param FKschema foreign key schema name/pattern or NULL
7829  * @param FKschemaLen length of FKschema or SQL_NTS
7830  * @param FKtable foreign key table name/pattern or NULL
7831  * @param FKtableLen length of FKtable or SQL_NTS
7832  * @result ODBC error code
7833  */
7834 
7835 SQLRETURN SQL_API
SQLForeignKeys(SQLHSTMT stmt,SQLCHAR * PKcatalog,SQLSMALLINT PKcatalogLen,SQLCHAR * PKschema,SQLSMALLINT PKschemaLen,SQLCHAR * PKtable,SQLSMALLINT PKtableLen,SQLCHAR * FKcatalog,SQLSMALLINT FKcatalogLen,SQLCHAR * FKschema,SQLSMALLINT FKschemaLen,SQLCHAR * FKtable,SQLSMALLINT FKtableLen)7836 SQLForeignKeys(SQLHSTMT stmt,
7837 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7838 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
7839 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
7840 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7841 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
7842 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
7843 {
7844 #if defined(_WIN32) || defined(_WIN64)
7845     char *pc = NULL, *ps = NULL, *pt = NULL;
7846     char *fc = NULL, *fs = NULL, *ft = NULL;
7847 #endif
7848     SQLRETURN ret;
7849 
7850     HSTMT_LOCK(stmt);
7851 #if defined(_WIN32) || defined(_WIN64)
7852     if (!((STMT *) stmt)->oemcp[0]) {
7853 	ret = drvforeignkeys(stmt,
7854 			     PKcatalog, PKcatalogLen,
7855 			     PKschema, PKschemaLen, PKtable, PKtableLen,
7856 			     FKcatalog, FKcatalogLen,
7857 			     FKschema, FKschemaLen,
7858 			     FKtable, FKtableLen);
7859 	goto done2;
7860     }
7861     if (PKcatalog) {
7862 	pc = wmb_to_utf_c((char *) PKcatalog, PKcatalogLen);
7863 	if (!pc) {
7864 	    ret = nomem((STMT *) stmt);
7865 	    goto done;
7866 	}
7867     }
7868     if (PKschema) {
7869 	ps = wmb_to_utf_c((char *) PKschema, PKschemaLen);
7870 	if (!ps) {
7871 	    ret = nomem((STMT *) stmt);
7872 	    goto done;
7873 	}
7874     }
7875     if (PKtable) {
7876 	pt = wmb_to_utf_c((char *) PKtable, PKtableLen);
7877 	if (!pt) {
7878 	    ret = nomem((STMT *) stmt);
7879 	    goto done;
7880 	}
7881     }
7882     if (FKcatalog) {
7883 	fc = wmb_to_utf_c((char *) FKcatalog, FKcatalogLen);
7884 	if (!fc) {
7885 	    ret = nomem((STMT *) stmt);
7886 	    goto done;
7887 	}
7888     }
7889     if (FKschema) {
7890 	fs = wmb_to_utf_c((char *) FKschema, FKschemaLen);
7891 	if (!fs) {
7892 	    ret = nomem((STMT *) stmt);
7893 	    goto done;
7894 	}
7895     }
7896     if (FKtable) {
7897 	ft = wmb_to_utf_c((char *) FKtable, FKtableLen);
7898 	if (!ft) {
7899 	    ret = nomem((STMT *) stmt);
7900 	    goto done;
7901 	}
7902     }
7903     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
7904 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
7905 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
7906 			 (SQLCHAR *) ft, SQL_NTS);
7907 #else
7908     ret = drvforeignkeys(stmt,
7909 			 PKcatalog, PKcatalogLen,
7910 			 PKschema, PKschemaLen, PKtable, PKtableLen,
7911 			 FKcatalog, FKcatalogLen,
7912 			 FKschema, FKschemaLen,
7913 			 FKtable, FKtableLen);
7914 #endif
7915 #if defined(_WIN32) || defined(_WIN64)
7916 done:
7917     uc_free(ft);
7918     uc_free(fs);
7919     uc_free(fc);
7920     uc_free(pt);
7921     uc_free(ps);
7922     uc_free(pc);
7923 done2:
7924     ;
7925 #endif
7926     HSTMT_UNLOCK(stmt);
7927     return ret;
7928 }
7929 #endif
7930 
7931 #ifdef WINTERFACE
7932 /**
7933  * Retrieve information about primary/foreign keys (UNICODE version).
7934  * @param stmt statement handle
7935  * @param PKcatalog primary key catalog name/pattern or NULL
7936  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7937  * @param PKschema primary key schema name/pattern or NULL
7938  * @param PKschemaLen length of PKschema or SQL_NTS
7939  * @param PKtable primary key table name/pattern or NULL
7940  * @param PKtableLen length of PKtable or SQL_NTS
7941  * @param FKcatalog foreign key catalog name/pattern or NULL
7942  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7943  * @param FKschema foreign key schema name/pattern or NULL
7944  * @param FKschemaLen length of FKschema or SQL_NTS
7945  * @param FKtable foreign key table name/pattern or NULL
7946  * @param FKtableLen length of FKtable or SQL_NTS
7947  * @result ODBC error code
7948  */
7949 
7950 SQLRETURN SQL_API
SQLForeignKeysW(SQLHSTMT stmt,SQLWCHAR * PKcatalog,SQLSMALLINT PKcatalogLen,SQLWCHAR * PKschema,SQLSMALLINT PKschemaLen,SQLWCHAR * PKtable,SQLSMALLINT PKtableLen,SQLWCHAR * FKcatalog,SQLSMALLINT FKcatalogLen,SQLWCHAR * FKschema,SQLSMALLINT FKschemaLen,SQLWCHAR * FKtable,SQLSMALLINT FKtableLen)7951 SQLForeignKeysW(SQLHSTMT stmt,
7952 		SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7953 		SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
7954 		SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
7955 		SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7956 		SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
7957 		SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
7958 {
7959     char *pc = NULL, *ps = NULL, *pt = NULL;
7960     char *fc = NULL, *fs = NULL, *ft = NULL;
7961     SQLRETURN ret;
7962 
7963     HSTMT_LOCK(stmt);
7964     if (PKcatalog) {
7965 	pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
7966 	if (!pc) {
7967 	    ret = nomem((STMT *) stmt);
7968 	    goto done;
7969 	}
7970     }
7971     if (PKschema) {
7972 	ps = uc_to_utf_c(PKschema, PKschemaLen);
7973 	if (!ps) {
7974 	    ret = nomem((STMT *) stmt);
7975 	    goto done;
7976 	}
7977     }
7978     if (PKtable) {
7979 	pt = uc_to_utf_c(PKtable, PKtableLen);
7980 	if (!pt) {
7981 	    ret = nomem((STMT *) stmt);
7982 	    goto done;
7983 	}
7984     }
7985     if (FKcatalog) {
7986 	fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
7987 	if (!fc) {
7988 	    ret = nomem((STMT *) stmt);
7989 	    goto done;
7990 	}
7991     }
7992     if (FKschema) {
7993 	fs = uc_to_utf_c(FKschema, FKschemaLen);
7994 	if (!fs) {
7995 	    ret = nomem((STMT *) stmt);
7996 	    goto done;
7997 	}
7998     }
7999     if (FKtable) {
8000 	ft = uc_to_utf_c(FKtable, FKtableLen);
8001 	if (!ft) {
8002 	    ret = nomem((STMT *) stmt);
8003 	    goto done;
8004 	}
8005     }
8006     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
8007 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
8008 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
8009 			 (SQLCHAR *) ft, SQL_NTS);
8010 done:
8011     uc_free(ft);
8012     uc_free(fs);
8013     uc_free(fc);
8014     uc_free(pt);
8015     uc_free(ps);
8016     uc_free(pc);
8017     HSTMT_UNLOCK(stmt);
8018     return ret;
8019 }
8020 #endif
8021 
8022 /**
8023  * Start transaction when autocommit off
8024  * @param s statement pointer
8025  * @result ODBC error code
8026  */
8027 
8028 static SQLRETURN
starttran(STMT * s)8029 starttran(STMT *s)
8030 {
8031     int ret = SQL_SUCCESS, rc, busy_count = 0;
8032     char *errp = NULL;
8033     DBC *d = (DBC *) s->dbc;
8034 
8035     if (!d->autocommit && !d->intrans && !d->trans_disable) {
8036 begin_again:
8037 	rc = sqlite3_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL, &errp);
8038 	if (rc == SQLITE_BUSY) {
8039 	    if (busy_handler((void *) d, ++busy_count)) {
8040 		if (errp) {
8041 		    sqlite3_free(errp);
8042 		    errp = NULL;
8043 		}
8044 		goto begin_again;
8045 	    }
8046 	}
8047 	dbtracerc(d, rc, errp);
8048 	if (rc != SQLITE_OK) {
8049 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
8050 		    errp ? errp : "unknown error", rc);
8051 	    ret = SQL_ERROR;
8052 	} else {
8053 	    d->intrans = 1;
8054 	}
8055 	if (errp) {
8056 	    sqlite3_free(errp);
8057 	    errp = NULL;
8058 	}
8059     }
8060     return ret;
8061 }
8062 
8063 /**
8064  * Internal commit or rollback transaction.
8065  * @param d database connection pointer
8066  * @param comptype type of transaction's end, SQL_COMMIT or SQL_ROLLBACK
8067  * @param force force action regardless of DBC's autocommit state
8068  * @result ODBC error code
8069  */
8070 
8071 static SQLRETURN
endtran(DBC * d,SQLSMALLINT comptype,int force)8072 endtran(DBC *d, SQLSMALLINT comptype, int force)
8073 {
8074     int ret, busy_count = 0;
8075     char *sql, *errp = NULL;
8076 
8077     if (!d->sqlite) {
8078 	setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
8079 	return SQL_ERROR;
8080     }
8081     if ((!force && d->autocommit) || !d->intrans) {
8082 	return SQL_SUCCESS;
8083     }
8084     switch (comptype) {
8085     case SQL_COMMIT:
8086 	sql = "COMMIT TRANSACTION";
8087 	goto doit;
8088     case SQL_ROLLBACK:
8089 	sql = "ROLLBACK TRANSACTION";
8090     doit:
8091 	ret = sqlite3_exec(d->sqlite, sql, NULL, NULL, &errp);
8092 	dbtracerc(d, ret, errp);
8093 	if (ret == SQLITE_BUSY && busy_count < 10) {
8094 	    if (busy_handler((void *) d, ++busy_count)) {
8095 		if (errp) {
8096 		    sqlite3_free(errp);
8097 		    errp = NULL;
8098 		}
8099 		goto doit;
8100 	    }
8101 	}
8102 	if (ret != SQLITE_OK) {
8103 	    setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
8104 		     errp ? errp : "transaction failed");
8105 	    if (errp) {
8106 		sqlite3_free(errp);
8107 		errp = NULL;
8108 	    }
8109 	    return SQL_ERROR;
8110 	}
8111 	if (errp) {
8112 	    sqlite3_free(errp);
8113 	    errp = NULL;
8114 	}
8115 	d->intrans = 0;
8116 	return SQL_SUCCESS;
8117     }
8118     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
8119     return SQL_ERROR;
8120 }
8121 
8122 /**
8123  * Internal commit or rollback transaction.
8124  * @param type type of handle
8125  * @param handle HDBC, HENV, or HSTMT handle
8126  * @param comptype SQL_COMMIT or SQL_ROLLBACK
8127  * @result ODBC error code
8128  */
8129 
8130 static SQLRETURN
drvendtran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)8131 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
8132 {
8133     DBC *dbc = NULL;
8134     int fail = 0;
8135     SQLRETURN ret;
8136 #if defined(_WIN32) || defined(_WIN64)
8137     ENV *env;
8138 #endif
8139 
8140     switch (type) {
8141     case SQL_HANDLE_DBC:
8142 	HDBC_LOCK((SQLHDBC) handle);
8143 	if (handle == SQL_NULL_HDBC) {
8144 	    return SQL_INVALID_HANDLE;
8145 	}
8146 	dbc = (DBC *) handle;
8147 	ret = endtran(dbc, comptype, 0);
8148 	HDBC_UNLOCK((SQLHDBC) handle);
8149 	return ret;
8150     case SQL_HANDLE_ENV:
8151 	if (handle == SQL_NULL_HENV) {
8152 	    return SQL_INVALID_HANDLE;
8153 	}
8154 #if defined(_WIN32) || defined(_WIN64)
8155 	env = (ENV *) handle;
8156 	if (env->magic != ENV_MAGIC) {
8157 	    return SQL_INVALID_HANDLE;
8158 	}
8159 	EnterCriticalSection(&env->cs);
8160 #endif
8161 	dbc = ((ENV *) handle)->dbcs;
8162 	while (dbc) {
8163 	    HDBC_LOCK((SQLHDBC) dbc);
8164 	    ret = endtran(dbc, comptype, 0);
8165 	    HDBC_UNLOCK((SQLHDBC) dbc);
8166 	    if (ret != SQL_SUCCESS) {
8167 		fail++;
8168 	    }
8169 	    dbc = dbc->next;
8170 	}
8171 #if defined(_WIN32) || defined(_WIN64)
8172 	LeaveCriticalSection(&env->cs);
8173 #endif
8174 	return fail ? SQL_ERROR : SQL_SUCCESS;
8175     }
8176     return SQL_INVALID_HANDLE;
8177 }
8178 
8179 /**
8180  * Commit or rollback transaction.
8181  * @param type type of handle
8182  * @param handle HDBC, HENV, or HSTMT handle
8183  * @param comptype SQL_COMMIT or SQL_ROLLBACK
8184  * @result ODBC error code
8185  */
8186 
8187 SQLRETURN SQL_API
SQLEndTran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)8188 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
8189 {
8190     return drvendtran(type, handle, comptype);
8191 }
8192 
8193 /**
8194  * Commit or rollback transaction.
8195  * @param env environment handle or NULL
8196  * @param dbc database connection handle or NULL
8197  * @param type SQL_COMMIT or SQL_ROLLBACK
8198  * @result ODBC error code
8199  */
8200 
8201 SQLRETURN SQL_API
SQLTransact(SQLHENV env,SQLHDBC dbc,SQLUSMALLINT type)8202 SQLTransact(SQLHENV env, SQLHDBC dbc, SQLUSMALLINT type)
8203 {
8204     if (dbc != SQL_NULL_HDBC) {
8205 	return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
8206     }
8207     return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
8208 }
8209 
8210 /**
8211  * Function not implemented.
8212  */
8213 
8214 SQLRETURN SQL_API
SQLCopyDesc(SQLHDESC source,SQLHDESC target)8215 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
8216 {
8217     return SQL_ERROR;
8218 }
8219 
8220 #ifndef WINTERFACE
8221 /**
8222  * Translate SQL string.
8223  * @param stmt statement handle
8224  * @param sqlin input string
8225  * @param sqlinLen length of input string
8226  * @param sql output string
8227  * @param sqlMax max space in output string
8228  * @param sqlLen value return for length of output string
8229  * @result ODBC error code
8230  */
8231 
8232 SQLRETURN SQL_API
SQLNativeSql(SQLHSTMT stmt,SQLCHAR * sqlin,SQLINTEGER sqlinLen,SQLCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)8233 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
8234 	     SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
8235 {
8236     int outLen = 0;
8237     SQLRETURN ret = SQL_SUCCESS;
8238 
8239     HSTMT_LOCK(stmt);
8240     if (sqlinLen == SQL_NTS) {
8241 	sqlinLen = strlen((char *) sqlin);
8242     }
8243     if (sql) {
8244 	if (sqlMax > 0) {
8245 	    strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
8246 	    sqlin[sqlMax - 1] = '\0';
8247 	    outLen = min(sqlMax - 1, sqlinLen);
8248 	}
8249     } else {
8250 	outLen = sqlinLen;
8251     }
8252     if (sqlLen) {
8253 	*sqlLen = outLen;
8254     }
8255     if (sql && outLen < sqlinLen) {
8256 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
8257 	ret = SQL_SUCCESS_WITH_INFO;
8258     }
8259     HSTMT_UNLOCK(stmt);
8260     return ret;
8261 }
8262 #endif
8263 
8264 #ifdef WINTERFACE
8265 /**
8266  * Translate SQL string (UNICODE version).
8267  * @param stmt statement handle
8268  * @param sqlin input string
8269  * @param sqlinLen length of input string
8270  * @param sql output string
8271  * @param sqlMax max space in output string
8272  * @param sqlLen value return for length of output string
8273  * @result ODBC error code
8274  */
8275 
8276 SQLRETURN SQL_API
SQLNativeSqlW(SQLHSTMT stmt,SQLWCHAR * sqlin,SQLINTEGER sqlinLen,SQLWCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)8277 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
8278 	      SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
8279 {
8280     int outLen = 0;
8281     SQLRETURN ret = SQL_SUCCESS;
8282 
8283     HSTMT_LOCK(stmt);
8284     if (sqlinLen == SQL_NTS) {
8285 	sqlinLen = uc_strlen(sqlin);
8286     }
8287     if (sql) {
8288 	if (sqlMax > 0) {
8289 	    uc_strncpy(sql, sqlin, sqlMax - 1);
8290 	    sqlin[sqlMax - 1] = 0;
8291 	    outLen = min(sqlMax  - 1, sqlinLen);
8292 	}
8293     } else {
8294 	outLen = sqlinLen;
8295     }
8296     if (sqlLen) {
8297 	*sqlLen = outLen;
8298     }
8299     if (sql && outLen < sqlinLen) {
8300 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
8301 	ret = SQL_SUCCESS_WITH_INFO;
8302     }
8303     HSTMT_UNLOCK(stmt);
8304     return ret;
8305 }
8306 #endif
8307 
8308 /**
8309  * Columns for result set of SQLProcedures().
8310  */
8311 
8312 static COL procSpec2[] = {
8313     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
8314     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
8315     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
8316     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
8317     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
8318     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
8319     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
8320     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
8321 };
8322 
8323 static COL procSpec3[] = {
8324     { "SYSTEM", "PROCEDURE", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
8325     { "SYSTEM", "PROCEDURE", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
8326     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
8327     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
8328     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
8329     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
8330     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
8331     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
8332 };
8333 
8334 #ifndef WINTERFACE
8335 /**
8336  * Retrieve information about stored procedures.
8337  * @param stmt statement handle
8338  * @param catalog catalog name/pattern or NULL
8339  * @param catalogLen length of catalog or SQL_NTS
8340  * @param schema schema name/pattern or NULL
8341  * @param schemaLen length of schema or SQL_NTS
8342  * @param proc procedure name/pattern or NULL
8343  * @param procLen length of proc or SQL_NTS
8344  * @result ODBC error code
8345  */
8346 
8347 SQLRETURN SQL_API
SQLProcedures(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen)8348 SQLProcedures(SQLHSTMT stmt,
8349 	      SQLCHAR *catalog, SQLSMALLINT catalogLen,
8350 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
8351 	      SQLCHAR *proc, SQLSMALLINT procLen)
8352 {
8353     SQLRETURN ret;
8354 
8355     HSTMT_LOCK(stmt);
8356     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
8357 		      procSpec3, array_size(procSpec3), NULL);
8358     HSTMT_UNLOCK(stmt);
8359     return ret;
8360 }
8361 #endif
8362 
8363 #ifdef WINTERFACE
8364 /**
8365  * Retrieve information about stored procedures (UNICODE version).
8366  * @param stmt statement handle
8367  * @param catalog catalog name/pattern or NULL
8368  * @param catalogLen length of catalog or SQL_NTS
8369  * @param schema schema name/pattern or NULL
8370  * @param schemaLen length of schema or SQL_NTS
8371  * @param proc procedure name/pattern or NULL
8372  * @param procLen length of proc or SQL_NTS
8373  * @result ODBC error code
8374  */
8375 
8376 SQLRETURN SQL_API
SQLProceduresW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen)8377 SQLProceduresW(SQLHSTMT stmt,
8378 	       SQLWCHAR *catalog, SQLSMALLINT catalogLen,
8379 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
8380 	       SQLWCHAR *proc, SQLSMALLINT procLen)
8381 {
8382     SQLRETURN ret;
8383 
8384     HSTMT_LOCK(stmt);
8385     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
8386 		      procSpec3, array_size(procSpec3), NULL);
8387     HSTMT_UNLOCK(stmt);
8388     return ret;
8389 }
8390 #endif
8391 
8392 /**
8393  * Columns for result set of SQLProcedureColumns().
8394  */
8395 
8396 static COL procColSpec2[] = {
8397     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
8398     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
8399     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
8400     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
8401     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
8402     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
8403     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
8404     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
8405     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
8406     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
8407     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
8408     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
8409     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
8410     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
8411     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
8412     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
8413     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
8414     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
8415     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
8416 };
8417 
8418 static COL procColSpec3[] = {
8419     { "SYSTEM", "PROCCOL", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
8420     { "SYSTEM", "PROCCOL", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
8421     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
8422     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
8423     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
8424     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
8425     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
8426     { "SYSTEM", "PROCCOL", "COLUMN_SIZE", SQL_INTEGER, 10 },
8427     { "SYSTEM", "PROCCOL", "BUFFER_LENGTH", SQL_INTEGER, 10 },
8428     { "SYSTEM", "PROCCOL", "DECIMAL_DIGITS", SQL_SMALLINT, 5 },
8429     { "SYSTEM", "PROCCOL", "NUM_PREC_RADIX", SQL_SMALLINT, 5 },
8430     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
8431     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
8432     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
8433     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
8434     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
8435     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
8436     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
8437     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
8438 };
8439 
8440 #ifndef WINTERFACE
8441 /**
8442  * Retrieve information about columns in result set of stored procedures.
8443  * @param stmt statement handle
8444  * @param catalog catalog name/pattern or NULL
8445  * @param catalogLen length of catalog or SQL_NTS
8446  * @param schema schema name/pattern or NULL
8447  * @param schemaLen length of schema or SQL_NTS
8448  * @param proc procedure name/pattern or NULL
8449  * @param procLen length of proc or SQL_NTS
8450  * @param column column name/pattern or NULL
8451  * @param columnLen length of column or SQL_NTS
8452  * @result ODBC error code
8453  */
8454 
8455 SQLRETURN SQL_API
SQLProcedureColumns(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen,SQLCHAR * column,SQLSMALLINT columnLen)8456 SQLProcedureColumns(SQLHSTMT stmt,
8457 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
8458 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
8459 		    SQLCHAR *proc, SQLSMALLINT procLen,
8460 		    SQLCHAR *column, SQLSMALLINT columnLen)
8461 {
8462     SQLRETURN ret;
8463 
8464     HSTMT_LOCK(stmt);
8465     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
8466 		      procColSpec3, array_size(procColSpec3), NULL);
8467     HSTMT_UNLOCK(stmt);
8468     return ret;
8469 }
8470 #endif
8471 
8472 #ifdef WINTERFACE
8473 /**
8474  * Retrieve information about columns in result
8475  * set of stored procedures (UNICODE version).
8476  * @param stmt statement handle
8477  * @param catalog catalog name/pattern or NULL
8478  * @param catalogLen length of catalog or SQL_NTS
8479  * @param schema schema name/pattern or NULL
8480  * @param schemaLen length of schema or SQL_NTS
8481  * @param proc procedure name/pattern or NULL
8482  * @param procLen length of proc or SQL_NTS
8483  * @param column column name/pattern or NULL
8484  * @param columnLen length of column or SQL_NTS
8485  * @result ODBC error code
8486  */
8487 
8488 SQLRETURN SQL_API
SQLProcedureColumnsW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen,SQLWCHAR * column,SQLSMALLINT columnLen)8489 SQLProcedureColumnsW(SQLHSTMT stmt,
8490 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
8491 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
8492 		     SQLWCHAR *proc, SQLSMALLINT procLen,
8493 		     SQLWCHAR *column, SQLSMALLINT columnLen)
8494 {
8495     SQLRETURN ret;
8496 
8497     HSTMT_LOCK(stmt);
8498     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
8499 		      procColSpec3, array_size(procColSpec3), NULL);
8500     HSTMT_UNLOCK(stmt);
8501     return ret;
8502 }
8503 #endif
8504 
8505 /**
8506  * Get information of HENV.
8507  * @param env environment handle
8508  * @param attr attribute to be retrieved
8509  * @param val output buffer
8510  * @param len length of output buffer
8511  * @param lenp output length
8512  * @result ODBC error code
8513  */
8514 
8515 SQLRETURN SQL_API
SQLGetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len,SQLINTEGER * lenp)8516 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
8517 	      SQLINTEGER len, SQLINTEGER *lenp)
8518 {
8519     ENV *e;
8520     SQLRETURN ret = SQL_ERROR;
8521 
8522     if (env == SQL_NULL_HENV) {
8523 	return SQL_INVALID_HANDLE;
8524     }
8525     e = (ENV *) env;
8526     if (!e || e->magic != ENV_MAGIC) {
8527 	return SQL_INVALID_HANDLE;
8528     }
8529 #if defined(_WIN32) || defined(_WIN64)
8530     EnterCriticalSection(&e->cs);
8531 #endif
8532     switch (attr) {
8533     case SQL_ATTR_CONNECTION_POOLING:
8534 	if (val) {
8535 	    *((SQLINTEGER *) val) = e->pool ?
8536 		SQL_CP_ONE_PER_DRIVER : SQL_CP_OFF;
8537 	}
8538 	if (lenp) {
8539 	    *lenp = sizeof (SQLINTEGER);
8540 	}
8541 	ret = SQL_SUCCESS;
8542 	break;
8543     case SQL_ATTR_CP_MATCH:
8544 	*((SQLINTEGER *) val) = SQL_CP_RELAXED_MATCH;
8545 	if (lenp) {
8546 	    *lenp = sizeof (SQLINTEGER);
8547 	}
8548 	ret = SQL_SUCCESS;
8549 	break;
8550     case SQL_ATTR_OUTPUT_NTS:
8551 	if (val) {
8552 	    *((SQLINTEGER *) val) = SQL_TRUE;
8553 	}
8554 	if (lenp) {
8555 	    *lenp = sizeof (SQLINTEGER);
8556 	}
8557 	ret = SQL_SUCCESS;
8558 	break;
8559     case SQL_ATTR_ODBC_VERSION:
8560 	if (val) {
8561 	    *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
8562 	}
8563 	if (lenp) {
8564 	    *lenp = sizeof (SQLINTEGER);
8565 	}
8566 	ret = SQL_SUCCESS;
8567 	break;
8568     }
8569 #if defined(_WIN32) || defined(_WIN64)
8570     LeaveCriticalSection(&e->cs);
8571 #endif
8572     return ret;
8573 }
8574 
8575 /**
8576  * Set information in HENV.
8577  * @param env environment handle
8578  * @param attr attribute to be retrieved
8579  * @param val parameter buffer
8580  * @param len length of parameter
8581  * @result ODBC error code
8582  */
8583 
8584 SQLRETURN SQL_API
SQLSetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)8585 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
8586 {
8587     ENV *e;
8588     SQLRETURN ret = SQL_ERROR;
8589 
8590     if (env == SQL_NULL_HENV) {
8591 	return SQL_INVALID_HANDLE;
8592     }
8593     e = (ENV *) env;
8594     if (!e || e->magic != ENV_MAGIC) {
8595 	return SQL_INVALID_HANDLE;
8596     }
8597 #if defined(_WIN32) || defined(_WIN64)
8598     EnterCriticalSection(&e->cs);
8599 #endif
8600     switch (attr) {
8601     case SQL_ATTR_CONNECTION_POOLING:
8602 	if (val == (SQLPOINTER) SQL_CP_ONE_PER_DRIVER) {
8603 	    e->pool = 1;
8604 	    ret = SQL_SUCCESS;
8605 	} else if (val == (SQLPOINTER) SQL_CP_OFF) {
8606 	    e->pool = 0;
8607 	    ret = SQL_SUCCESS;
8608 	}
8609 	break;
8610     case SQL_ATTR_CP_MATCH:
8611 	ret = SQL_SUCCESS;
8612 	break;
8613     case SQL_ATTR_OUTPUT_NTS:
8614 	if (val == (SQLPOINTER) SQL_TRUE) {
8615 	    ret = SQL_SUCCESS;
8616 	}
8617 	break;
8618     case SQL_ATTR_ODBC_VERSION:
8619 	if (!val) {
8620 	    break;
8621 	}
8622 	if (val == (SQLPOINTER) SQL_OV_ODBC2) {
8623 	    e->ov3 = 0;
8624 	    ret = SQL_SUCCESS;
8625 	} else if (val == (SQLPOINTER) SQL_OV_ODBC3) {
8626 	    e->ov3 = 1;
8627 	    ret = SQL_SUCCESS;
8628 	}
8629 	break;
8630     }
8631 #if defined(_WIN32) || defined(_WIN64)
8632     LeaveCriticalSection(&e->cs);
8633 #endif
8634     return ret;
8635 }
8636 
8637 /**
8638  * Internal get error message given handle (HENV, HDBC, or HSTMT).
8639  * @param htype handle type
8640  * @param handle HENV, HDBC, or HSTMT
8641  * @param recno
8642  * @param sqlstate output buffer for SQL state
8643  * @param nativeerr output buffer of native error code
8644  * @param msg output buffer for error message
8645  * @param buflen length of output buffer
8646  * @param msglen output length
8647  * @result ODBC error code
8648  */
8649 
8650 static SQLRETURN
drvgetdiagrec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8651 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8652 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
8653 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8654 {
8655     DBC *d = NULL;
8656     STMT *s = NULL;
8657     int len, naterr;
8658     char *logmsg, *sqlst;
8659     SQLRETURN ret = SQL_ERROR;
8660 
8661     if (handle == SQL_NULL_HANDLE) {
8662 	return SQL_INVALID_HANDLE;
8663     }
8664     if (sqlstate) {
8665 	sqlstate[0] = '\0';
8666     }
8667     if (msg && buflen > 0) {
8668 	msg[0] = '\0';
8669     }
8670     if (msglen) {
8671 	*msglen = 0;
8672     }
8673     if (nativeerr) {
8674 	*nativeerr = 0;
8675     }
8676     switch (htype) {
8677     case SQL_HANDLE_ENV:
8678     case SQL_HANDLE_DESC:
8679 	return SQL_NO_DATA;
8680     case SQL_HANDLE_DBC:
8681 	HDBC_LOCK((SQLHDBC) handle);
8682 	d = (DBC *) handle;
8683 	logmsg = (char *) d->logmsg;
8684 	sqlst = d->sqlstate;
8685 	naterr = d->naterr;
8686 	break;
8687     case SQL_HANDLE_STMT:
8688 	HSTMT_LOCK((SQLHSTMT) handle);
8689 	s = (STMT *) handle;
8690 	logmsg = (char *) s->logmsg;
8691 	sqlst = s->sqlstate;
8692 	naterr = s->naterr;
8693 	break;
8694     default:
8695 	return SQL_INVALID_HANDLE;
8696     }
8697     if (buflen < 0) {
8698 	goto done;
8699     }
8700     if (recno > 1) {
8701 	ret = SQL_NO_DATA;
8702 	goto done;
8703     }
8704     len = strlen(logmsg);
8705     if (len == 0) {
8706 	ret = SQL_NO_DATA;
8707 	goto done;
8708     }
8709     if (nativeerr) {
8710 	*nativeerr = naterr;
8711     }
8712     if (sqlstate) {
8713 	strcpy((char *) sqlstate, sqlst);
8714     }
8715     if (msglen) {
8716 	*msglen = len;
8717     }
8718     if (len >= buflen) {
8719 	if (msg && buflen > 0) {
8720 	    strncpy((char *) msg, logmsg, buflen);
8721 	    msg[buflen - 1] = '\0';
8722 	    logmsg[0] = '\0';
8723 	}
8724     } else if (msg) {
8725 	strcpy((char *) msg, logmsg);
8726 	logmsg[0] = '\0';
8727     }
8728     ret = SQL_SUCCESS;
8729 done:
8730     switch (htype) {
8731     case SQL_HANDLE_DBC:
8732 	HDBC_UNLOCK((SQLHDBC) handle);
8733 	break;
8734     case SQL_HANDLE_STMT:
8735 	HSTMT_UNLOCK((SQLHSTMT) handle);
8736 	break;
8737     }
8738     return ret;
8739 }
8740 
8741 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
8742 /**
8743  * Get error message given handle (HENV, HDBC, or HSTMT).
8744  * @param htype handle type
8745  * @param handle HENV, HDBC, or HSTMT
8746  * @param recno
8747  * @param sqlstate output buffer for SQL state
8748  * @param nativeerr output buffer of native error code
8749  * @param msg output buffer for error message
8750  * @param buflen length of output buffer
8751  * @param msglen output length
8752  * @result ODBC error code
8753  */
8754 
8755 SQLRETURN SQL_API
SQLGetDiagRec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8756 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8757 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
8758 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8759 {
8760     return drvgetdiagrec(htype, handle, recno, sqlstate,
8761 			 nativeerr, msg, buflen, msglen);
8762 }
8763 #endif
8764 
8765 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
8766 #ifdef WINTERFACE
8767 /**
8768  * Get error message given handle (HENV, HDBC, or HSTMT)
8769  * (UNICODE version).
8770  * @param htype handle type
8771  * @param handle HENV, HDBC, or HSTMT
8772  * @param recno
8773  * @param sqlstate output buffer for SQL state
8774  * @param nativeerr output buffer of native error code
8775  * @param msg output buffer for error message
8776  * @param buflen length of output buffer
8777  * @param msglen output length
8778  * @result ODBC error code
8779  */
8780 
8781 SQLRETURN SQL_API
SQLGetDiagRecW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLWCHAR * sqlstate,SQLINTEGER * nativeerr,SQLWCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8782 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8783 	      SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
8784 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8785 {
8786     char state[16];
8787     SQLSMALLINT len;
8788     SQLRETURN ret;
8789 
8790     ret = drvgetdiagrec(htype, handle, recno, (SQLCHAR *) state,
8791 			nativeerr, (SQLCHAR *) msg, buflen, &len);
8792     if (ret == SQL_SUCCESS) {
8793 	if (sqlstate) {
8794 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlstate,
8795 			    6 * sizeof (SQLWCHAR));
8796 	}
8797 	if (msg) {
8798 	    if (len > 0) {
8799 		SQLWCHAR *m = NULL;
8800 
8801 		m = uc_from_utf((unsigned char *) msg, len);
8802 		if (m) {
8803 		    if (buflen) {
8804 			buflen /= sizeof (SQLWCHAR);
8805 			uc_strncpy(msg, m, buflen);
8806 			m[len] = 0;
8807 			len = min(buflen, uc_strlen(m));
8808 		    } else {
8809 			len = uc_strlen(m);
8810 		    }
8811 		    uc_free(m);
8812 		} else {
8813 		    len = 0;
8814 		}
8815 	    }
8816 	    if (len <= 0) {
8817 		len = 0;
8818 		if (buflen > 0) {
8819 		    msg[0] = 0;
8820 		}
8821 	    }
8822 	} else {
8823 	    /* estimated length !!! */
8824 	    len *= sizeof (SQLWCHAR);
8825 	}
8826 	if (msglen) {
8827 	    *msglen = len;
8828 	}
8829     } else if (ret == SQL_NO_DATA) {
8830 	if (sqlstate) {
8831 	    sqlstate[0] = 0;
8832 	}
8833 	if (msg) {
8834 	    if (buflen > 0) {
8835 		msg[0] = 0;
8836 	    }
8837 	}
8838 	if (msglen) {
8839 	    *msglen = 0;
8840 	}
8841     }
8842     return ret;
8843 }
8844 #endif
8845 #endif
8846 
8847 /**
8848  * Get error record given handle (HDBC or HSTMT).
8849  * @param htype handle type
8850  * @param handle HDBC or HSTMT
8851  * @param recno diag record number for which info to be retrieved
8852  * @param id diag id for which info to be retrieved
8853  * @param info output buffer for error message
8854  * @param buflen length of output buffer
8855  * @param stringlen output length
8856  * @result ODBC error code
8857  */
8858 
8859 static SQLRETURN
drvgetdiagfield(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8860 drvgetdiagfield(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8861 		SQLSMALLINT id, SQLPOINTER info,
8862 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8863 {
8864     DBC *d = NULL;
8865     STMT *s = NULL;
8866     int len, naterr, strbuf = 1;
8867     char *logmsg, *sqlst, *clrmsg = NULL;
8868     SQLRETURN ret = SQL_ERROR;
8869 
8870     if (handle == SQL_NULL_HANDLE) {
8871 	return SQL_INVALID_HANDLE;
8872     }
8873     if (stringlen) {
8874 	*stringlen = 0;
8875     }
8876     switch (htype) {
8877     case SQL_HANDLE_ENV:
8878     case SQL_HANDLE_DESC:
8879 	return SQL_NO_DATA;
8880     case SQL_HANDLE_DBC:
8881 	HDBC_LOCK((SQLHDBC) handle);
8882 	d = (DBC *) handle;
8883 	logmsg = (char *) d->logmsg;
8884 	sqlst = d->sqlstate;
8885 	naterr = d->naterr;
8886 	break;
8887     case SQL_HANDLE_STMT:
8888 	HSTMT_LOCK((SQLHSTMT) handle);
8889 	s = (STMT *) handle;
8890 	d = (DBC *) s->dbc;
8891 	logmsg = (char *) s->logmsg;
8892 	sqlst = s->sqlstate;
8893 	naterr = s->naterr;
8894 	break;
8895     default:
8896 	return SQL_INVALID_HANDLE;
8897     }
8898     if (buflen < 0) {
8899 	switch (buflen) {
8900 	case SQL_IS_POINTER:
8901 	case SQL_IS_UINTEGER:
8902 	case SQL_IS_INTEGER:
8903 	case SQL_IS_USMALLINT:
8904 	case SQL_IS_SMALLINT:
8905 	    strbuf = 0;
8906 	    break;
8907 	default:
8908 	    ret = SQL_ERROR;
8909 	    goto done;
8910 	}
8911     }
8912     if (recno > 1) {
8913 	ret = SQL_NO_DATA;
8914 	goto done;
8915     }
8916     switch (id) {
8917     case SQL_DIAG_CLASS_ORIGIN:
8918 	logmsg = "ISO 9075";
8919 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
8920 	    logmsg = "ODBC 3.0";
8921 	}
8922 	break;
8923     case SQL_DIAG_SUBCLASS_ORIGIN:
8924 	logmsg = "ISO 9075";
8925 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
8926 	    logmsg = "ODBC 3.0";
8927 	} else if (sqlst[0] == 'H' && sqlst[1] == 'Y') {
8928 	    logmsg = "ODBC 3.0";
8929 	} else if (sqlst[0] == '2' || sqlst[0] == '0' || sqlst[0] == '4') {
8930 	    logmsg = "ODBC 3.0";
8931 	}
8932 	break;
8933     case SQL_DIAG_CONNECTION_NAME:
8934     case SQL_DIAG_SERVER_NAME:
8935 	logmsg = d->dsn ? d->dsn : "No DSN";
8936 	break;
8937     case SQL_DIAG_SQLSTATE:
8938 	logmsg = sqlst;
8939 	break;
8940     case SQL_DIAG_MESSAGE_TEXT:
8941 	if (info) {
8942 	    clrmsg = logmsg;
8943 	}
8944 	break;
8945     case SQL_DIAG_NUMBER:
8946 	naterr = 1;
8947 	/* fall through */
8948     case SQL_DIAG_NATIVE:
8949 	len = strlen(logmsg);
8950 	if (len == 0) {
8951 	    ret = SQL_NO_DATA;
8952 	    goto done;
8953 	}
8954 	if (info) {
8955 	    *((SQLINTEGER *) info) = naterr;
8956 	}
8957 	ret = SQL_SUCCESS;
8958 	goto done;
8959     case SQL_DIAG_DYNAMIC_FUNCTION:
8960 	logmsg = "";
8961 	break;
8962     case SQL_DIAG_CURSOR_ROW_COUNT:
8963 	if (htype == SQL_HANDLE_STMT) {
8964 	    SQLULEN count;
8965 
8966 	    count = (s->isselect == 1 || s->isselect == -1) ? s->nrows : 0;
8967 	    *((SQLULEN *) info) = count;
8968 	    ret = SQL_SUCCESS;
8969 	}
8970 	goto done;
8971     case SQL_DIAG_ROW_COUNT:
8972 	if (htype == SQL_HANDLE_STMT) {
8973 	    SQLULEN count;
8974 
8975 	    count = s->isselect ? 0 : s->nrows;
8976 	    *((SQLULEN *) info) = count;
8977 	    ret = SQL_SUCCESS;
8978 	}
8979 	goto done;
8980     default:
8981 	goto done;
8982     }
8983     if (info && buflen > 0) {
8984 	((char *) info)[0] = '\0';
8985     }
8986     len = strlen(logmsg);
8987     if (len == 0) {
8988 	ret = SQL_NO_DATA;
8989 	goto done;
8990     }
8991     if (stringlen) {
8992 	*stringlen = len;
8993     }
8994     if (strbuf) {
8995 	if (len >= buflen) {
8996 	    if (info && buflen > 0) {
8997 		if (stringlen) {
8998 		    *stringlen = buflen - 1;
8999 		}
9000 		strncpy((char *) info, logmsg, buflen);
9001 		((char *) info)[buflen - 1] = '\0';
9002 	    }
9003 	} else if (info) {
9004 	    strcpy((char *) info, logmsg);
9005 	}
9006     }
9007     if (clrmsg) {
9008 	*clrmsg = '\0';
9009     }
9010     ret = SQL_SUCCESS;
9011 done:
9012     switch (htype) {
9013     case SQL_HANDLE_DBC:
9014 	HDBC_UNLOCK((SQLHDBC) handle);
9015 	break;
9016     case SQL_HANDLE_STMT:
9017 	HSTMT_UNLOCK((SQLHSTMT) handle);
9018 	break;
9019     }
9020     return ret;
9021 }
9022 
9023 #ifndef WINTERFACE
9024 /**
9025  * Get error record given handle (HDBC or HSTMT).
9026  * @param htype handle type
9027  * @param handle HDBC or HSTMT
9028  * @param recno diag record number for which info to be retrieved
9029  * @param id diag id for which info to be retrieved
9030  * @param info output buffer for error message
9031  * @param buflen length of output buffer
9032  * @param stringlen output length
9033  * @result ODBC error code
9034  */
9035 
9036 SQLRETURN SQL_API
SQLGetDiagField(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)9037 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
9038 		SQLSMALLINT id, SQLPOINTER info,
9039 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
9040 {
9041     return drvgetdiagfield(htype, handle, recno, id, info, buflen, stringlen);
9042 }
9043 #endif
9044 
9045 #ifdef WINTERFACE
9046 /**
9047  * Get error record given handle (HDBC or HSTMT).
9048  * @param htype handle type
9049  * @param handle HDBC or HSTMT
9050  * @param recno diag record number for which info to be retrieved
9051  * @param id diag id for which info to be retrieved
9052  * @param info output buffer for error message
9053  * @param buflen length of output buffer
9054  * @param stringlen output length
9055  * @result ODBC error code
9056  */
9057 
9058 SQLRETURN SQL_API
SQLGetDiagFieldW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)9059 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
9060 		 SQLSMALLINT id, SQLPOINTER info,
9061 		 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
9062 {
9063     SQLSMALLINT len;
9064     SQLRETURN ret;
9065 
9066     ret = drvgetdiagfield(htype, handle, recno, id, info, buflen, &len);
9067     if (ret == SQL_SUCCESS) {
9068 	if (info) {
9069 	    switch (id) {
9070 	    case SQL_DIAG_CLASS_ORIGIN:
9071 	    case SQL_DIAG_SUBCLASS_ORIGIN:
9072 	    case SQL_DIAG_CONNECTION_NAME:
9073 	    case SQL_DIAG_SERVER_NAME:
9074 	    case SQL_DIAG_SQLSTATE:
9075 	    case SQL_DIAG_MESSAGE_TEXT:
9076 	    case SQL_DIAG_DYNAMIC_FUNCTION:
9077 		if (len > 0) {
9078 		    SQLWCHAR *m = NULL;
9079 
9080 		    m = uc_from_utf((unsigned char *) info, len);
9081 		    if (m) {
9082 			if (buflen) {
9083 			    buflen /= sizeof (SQLWCHAR);
9084 			    uc_strncpy(info, m, buflen);
9085 			    m[len] = 0;
9086 			    len = min(buflen, uc_strlen(m));
9087 			} else {
9088 			    len = uc_strlen(m);
9089 			}
9090 			uc_free(m);
9091 			len *= sizeof (SQLWCHAR);
9092 		    } else {
9093 			len = 0;
9094 		    }
9095 		}
9096 		if (len <= 0) {
9097 		    len = 0;
9098 		    if (buflen > 0) {
9099 			((SQLWCHAR *) info)[0] = 0;
9100 		    }
9101 		}
9102 	    }
9103 	} else {
9104 	    switch (id) {
9105 	    case SQL_DIAG_CLASS_ORIGIN:
9106 	    case SQL_DIAG_SUBCLASS_ORIGIN:
9107 	    case SQL_DIAG_CONNECTION_NAME:
9108 	    case SQL_DIAG_SERVER_NAME:
9109 	    case SQL_DIAG_SQLSTATE:
9110 	    case SQL_DIAG_MESSAGE_TEXT:
9111 	    case SQL_DIAG_DYNAMIC_FUNCTION:
9112 		len *= sizeof (SQLWCHAR);
9113 		break;
9114 	    }
9115 	}
9116 	if (stringlen) {
9117 	    *stringlen = len;
9118 	}
9119     }
9120     return ret;
9121 }
9122 #endif
9123 
9124 /**
9125  * Internal get option of HSTMT.
9126  * @param stmt statement handle
9127  * @param attr attribute to be retrieved
9128  * @param val output buffer
9129  * @param bufmax length of output buffer
9130  * @param buflen output length
9131  * @result ODBC error code
9132  */
9133 
9134 static SQLRETURN
drvgetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)9135 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9136 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
9137 {
9138     STMT *s = (STMT *) stmt;
9139     SQLULEN *uval = (SQLULEN *) val;
9140     SQLINTEGER dummy;
9141     char dummybuf[16];
9142 
9143     if (!buflen) {
9144 	buflen = &dummy;
9145     }
9146     if (!uval) {
9147 	uval = (SQLPOINTER) dummybuf;
9148     }
9149     switch (attr) {
9150     case SQL_QUERY_TIMEOUT:
9151 	*uval = 0;
9152 	*buflen = sizeof (SQLULEN);
9153 	return SQL_SUCCESS;
9154     case SQL_ATTR_CURSOR_TYPE:
9155 	*uval = s->curtype;
9156 	*buflen = sizeof (SQLULEN);
9157 	return SQL_SUCCESS;
9158     case SQL_ATTR_CURSOR_SCROLLABLE:
9159 	*uval = (s->curtype != SQL_CURSOR_FORWARD_ONLY) ?
9160 	    SQL_SCROLLABLE : SQL_NONSCROLLABLE;
9161 	*buflen = sizeof (SQLULEN);
9162 	return SQL_SUCCESS;
9163 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
9164     case SQL_ATTR_CURSOR_SENSITIVITY:
9165 	*uval = SQL_UNSPECIFIED;
9166 	*buflen = sizeof (SQLULEN);
9167 	return SQL_SUCCESS;
9168 #endif
9169     case SQL_ATTR_ROW_NUMBER:
9170 	if (s->s3stmt) {
9171 	    *uval = (s->s3stmt_rownum < 0) ?
9172 		    SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
9173 	} else {
9174 	    *uval = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
9175 	}
9176 	*buflen = sizeof (SQLULEN);
9177 	return SQL_SUCCESS;
9178     case SQL_ATTR_ASYNC_ENABLE:
9179 	*uval = SQL_ASYNC_ENABLE_OFF;
9180 	*buflen = sizeof (SQLULEN);
9181 	return SQL_SUCCESS;
9182     case SQL_CONCURRENCY:
9183 	*uval = SQL_CONCUR_LOCK;
9184 	*buflen = sizeof (SQLULEN);
9185 	return SQL_SUCCESS;
9186     case SQL_ATTR_RETRIEVE_DATA:
9187 	*uval = s->retr_data;
9188 	*buflen = sizeof (SQLULEN);
9189 	return SQL_SUCCESS;
9190     case SQL_ROWSET_SIZE:
9191     case SQL_ATTR_ROW_ARRAY_SIZE:
9192 	*uval = s->rowset_size;
9193 	*buflen = sizeof (SQLULEN);
9194 	return SQL_SUCCESS;
9195     /* Needed for some driver managers, but dummies for now */
9196     case SQL_ATTR_IMP_ROW_DESC:
9197     case SQL_ATTR_APP_ROW_DESC:
9198     case SQL_ATTR_IMP_PARAM_DESC:
9199     case SQL_ATTR_APP_PARAM_DESC:
9200 	*((SQLHDESC *) uval) = (SQLHDESC) DEAD_MAGIC;
9201 	*buflen = sizeof (SQLHDESC);
9202 	return SQL_SUCCESS;
9203     case SQL_ATTR_ROW_STATUS_PTR:
9204 	*((SQLUSMALLINT **) uval) = s->row_status;
9205 	*buflen = sizeof (SQLUSMALLINT *);
9206 	return SQL_SUCCESS;
9207     case SQL_ATTR_ROWS_FETCHED_PTR:
9208 	*((SQLULEN **) uval) = s->row_count;
9209 	*buflen = sizeof (SQLULEN *);
9210 	return SQL_SUCCESS;
9211     case SQL_ATTR_USE_BOOKMARKS: {
9212 	STMT *s = (STMT *) stmt;
9213 
9214 	*(SQLUINTEGER *) uval = s->bkmrk;
9215 	*buflen = sizeof (SQLUINTEGER);
9216 	return SQL_SUCCESS;
9217     }
9218     case SQL_ATTR_FETCH_BOOKMARK_PTR:
9219 	*(SQLPOINTER *) uval = s->bkmrkptr;
9220 	*buflen = sizeof (SQLPOINTER);
9221 	return SQL_SUCCESS;
9222     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
9223 	*((SQLULEN **) uval) = s->parm_bind_offs;
9224 	*buflen = sizeof (SQLULEN *);
9225 	return SQL_SUCCESS;
9226     case SQL_ATTR_PARAM_BIND_TYPE:
9227 	*((SQLULEN *) uval) = s->parm_bind_type;
9228 	*buflen = sizeof (SQLULEN);
9229 	return SQL_SUCCESS;
9230     case SQL_ATTR_PARAM_OPERATION_PTR:
9231 	*((SQLUSMALLINT **) uval) = s->parm_oper;
9232 	*buflen = sizeof (SQLUSMALLINT *);
9233 	return SQL_SUCCESS;
9234     case SQL_ATTR_PARAM_STATUS_PTR:
9235 	*((SQLUSMALLINT **) uval) = s->parm_status;
9236 	*buflen = sizeof (SQLUSMALLINT *);
9237 	return SQL_SUCCESS;
9238     case SQL_ATTR_PARAMS_PROCESSED_PTR:
9239 	*((SQLULEN **) uval) = s->parm_proc;
9240 	*buflen = sizeof (SQLULEN *);
9241 	return SQL_SUCCESS;
9242     case SQL_ATTR_PARAMSET_SIZE:
9243 	*((SQLULEN *) uval) = s->paramset_size;
9244 	*buflen = sizeof (SQLULEN);
9245 	return SQL_SUCCESS;
9246     case SQL_ATTR_ROW_BIND_TYPE:
9247 	*(SQLULEN *) uval = s->bind_type;
9248 	*buflen = sizeof (SQLULEN);
9249 	return SQL_SUCCESS;
9250     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
9251 	*((SQLULEN **) uval) = s->bind_offs;
9252 	*buflen = sizeof (SQLULEN *);
9253 	return SQL_SUCCESS;
9254     case SQL_ATTR_MAX_ROWS:
9255 	*((SQLULEN *) uval) = s->max_rows;
9256 	*buflen = sizeof (SQLULEN);
9257 	return SQL_SUCCESS;
9258     case SQL_ATTR_MAX_LENGTH:
9259 	*((SQLULEN *) uval) = 1000000000;
9260 	*buflen = sizeof (SQLULEN);
9261 	return SQL_SUCCESS;
9262 #ifdef SQL_ATTR_METADATA_ID
9263     case SQL_ATTR_METADATA_ID:
9264 	*((SQLULEN *) uval) = SQL_FALSE;
9265 	*buflen = sizeof (SQLULEN);
9266 	return SQL_SUCCESS;
9267 #endif
9268     }
9269     return drvunimplstmt(stmt);
9270 }
9271 
9272 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
9273 /**
9274  * Get option of HSTMT.
9275  * @param stmt statement handle
9276  * @param attr attribute to be retrieved
9277  * @param val output buffer
9278  * @param bufmax length of output buffer
9279  * @param buflen output length
9280  * @result ODBC error code
9281  */
9282 
9283 SQLRETURN SQL_API
SQLGetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)9284 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9285 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
9286 {
9287     SQLRETURN ret;
9288 
9289     HSTMT_LOCK(stmt);
9290     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
9291     HSTMT_UNLOCK(stmt);
9292     return ret;
9293 }
9294 #endif
9295 
9296 #ifdef WINTERFACE
9297 /**
9298  * Get option of HSTMT (UNICODE version).
9299  * @param stmt statement handle
9300  * @param attr attribute to be retrieved
9301  * @param val output buffer
9302  * @param bufmax length of output buffer
9303  * @param buflen output length
9304  * @result ODBC error code
9305  */
9306 
9307 SQLRETURN SQL_API
SQLGetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)9308 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9309 		SQLINTEGER bufmax, SQLINTEGER *buflen)
9310 {
9311     SQLRETURN ret;
9312 
9313     HSTMT_LOCK(stmt);
9314     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
9315     HSTMT_UNLOCK(stmt);
9316     return ret;
9317 }
9318 #endif
9319 
9320 /**
9321  * Internal set option on HSTMT.
9322  * @param stmt statement handle
9323  * @param attr attribute to be set
9324  * @param val input buffer (attribute value)
9325  * @param buflen length of input buffer
9326  * @result ODBC error code
9327  */
9328 
9329 static SQLRETURN
drvsetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)9330 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9331 	       SQLINTEGER buflen)
9332 {
9333     STMT *s = (STMT *) stmt;
9334 #if defined(SQL_BIGINT) && defined(__WORDSIZE) && (__WORDSIZE == 64)
9335     SQLBIGINT uval;
9336 
9337     uval = (SQLBIGINT) val;
9338 #else
9339     SQLULEN uval;
9340 
9341     uval = (SQLULEN) val;
9342 #endif
9343     switch (attr) {
9344     case SQL_ATTR_CURSOR_TYPE:
9345 	if (val == (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY) {
9346 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
9347 	} else {
9348 	    s->curtype = SQL_CURSOR_STATIC;
9349 	}
9350 	if (val != (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY &&
9351 	    val != (SQLPOINTER) SQL_CURSOR_STATIC) {
9352 	    goto e01s02;
9353 	}
9354 	return SQL_SUCCESS;
9355     case SQL_ATTR_CURSOR_SCROLLABLE:
9356 	if (val == (SQLPOINTER) SQL_NONSCROLLABLE) {
9357 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
9358 	} else {
9359 	    s->curtype = SQL_CURSOR_STATIC;
9360 	}
9361 	return SQL_SUCCESS;
9362     case SQL_ATTR_ASYNC_ENABLE:
9363 	if (val != (SQLPOINTER) SQL_ASYNC_ENABLE_OFF) {
9364     e01s02:
9365 	    setstat(s, -1, "option value changed", "01S02");
9366 	    return SQL_SUCCESS_WITH_INFO;
9367 	}
9368 	return SQL_SUCCESS;
9369     case SQL_CONCURRENCY:
9370 	if (val != (SQLPOINTER) SQL_CONCUR_LOCK) {
9371 	    goto e01s02;
9372 	}
9373 	return SQL_SUCCESS;
9374 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
9375     case SQL_ATTR_CURSOR_SENSITIVITY:
9376 	if (val != (SQLPOINTER) SQL_UNSPECIFIED) {
9377 	    goto e01s02;
9378 	}
9379 	return SQL_SUCCESS;
9380 #endif
9381     case SQL_ATTR_QUERY_TIMEOUT:
9382 	return SQL_SUCCESS;
9383     case SQL_ATTR_RETRIEVE_DATA:
9384 	if (val != (SQLPOINTER) SQL_RD_ON &&
9385 	    val != (SQLPOINTER) SQL_RD_OFF) {
9386 	    goto e01s02;
9387 	}
9388 	s->retr_data = uval;
9389 	return SQL_SUCCESS;
9390     case SQL_ROWSET_SIZE:
9391     case SQL_ATTR_ROW_ARRAY_SIZE:
9392 	if (uval < 1) {
9393 	    setstat(s, -1, "invalid rowset size", "HY000");
9394 	    return SQL_ERROR;
9395 	} else {
9396 	    SQLUSMALLINT *rst = &s->row_status1;
9397 
9398 	    if (uval > 1) {
9399 		rst = xmalloc(sizeof (SQLUSMALLINT) * uval);
9400 		if (!rst) {
9401 		    return nomem(s);
9402 		}
9403 	    }
9404 	    if (s->row_status0 != &s->row_status1) {
9405 		freep(&s->row_status0);
9406 	    }
9407 	    s->row_status0 = rst;
9408 	    s->rowset_size = uval;
9409 	}
9410 	return SQL_SUCCESS;
9411     case SQL_ATTR_ROW_STATUS_PTR:
9412 	s->row_status = (SQLUSMALLINT *) val;
9413 	return SQL_SUCCESS;
9414     case SQL_ATTR_ROWS_FETCHED_PTR:
9415 	s->row_count = (SQLULEN *) val;
9416 	return SQL_SUCCESS;
9417     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
9418 	s->parm_bind_offs = (SQLULEN *) val;
9419 	return SQL_SUCCESS;
9420     case SQL_ATTR_PARAM_BIND_TYPE:
9421 	s->parm_bind_type = uval;
9422 	return SQL_SUCCESS;
9423     case SQL_ATTR_PARAM_OPERATION_PTR:
9424 	s->parm_oper = (SQLUSMALLINT *) val;
9425 	return SQL_SUCCESS;
9426     case SQL_ATTR_PARAM_STATUS_PTR:
9427 	s->parm_status = (SQLUSMALLINT *) val;
9428 	return SQL_SUCCESS;
9429     case SQL_ATTR_PARAMS_PROCESSED_PTR:
9430 	s->parm_proc = (SQLULEN *) val;
9431 	return SQL_SUCCESS;
9432     case SQL_ATTR_PARAMSET_SIZE:
9433 	if (uval < 1) {
9434 	    goto e01s02;
9435 	}
9436 	s->paramset_size = uval;
9437 	s->paramset_count = 0;
9438 	return SQL_SUCCESS;
9439     case SQL_ATTR_ROW_BIND_TYPE:
9440 	s->bind_type = uval;
9441 	return SQL_SUCCESS;
9442     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
9443 	s->bind_offs = (SQLULEN *) val;
9444 	return SQL_SUCCESS;
9445     case SQL_ATTR_USE_BOOKMARKS:
9446 	if (val != (SQLPOINTER) SQL_UB_OFF &&
9447 	    val != (SQLPOINTER) SQL_UB_ON &&
9448 	    val != (SQLPOINTER) SQL_UB_VARIABLE) {
9449 	    goto e01s02;
9450 	}
9451 	if (*s->ov3 && val == (SQLPOINTER) SQL_UB_VARIABLE) {
9452 	    s->bkmrk = SQL_UB_VARIABLE;
9453 	    return SQL_SUCCESS;
9454 	}
9455 	if (val == (SQLPOINTER) SQL_UB_VARIABLE) {
9456 	    s->bkmrk = SQL_UB_ON;
9457 	    goto e01s02;
9458 	}
9459 	s->bkmrk = (val == (SQLPOINTER) SQL_UB_ON) ? SQL_UB_ON : SQL_UB_OFF;
9460 	return SQL_SUCCESS;
9461     case SQL_ATTR_FETCH_BOOKMARK_PTR:
9462 	s->bkmrkptr = (SQLINTEGER *) val;
9463 	return SQL_SUCCESS;
9464     case SQL_ATTR_MAX_ROWS:
9465 	s->max_rows = uval;
9466 	return SQL_SUCCESS;
9467     case SQL_ATTR_MAX_LENGTH:
9468 	if (val != (SQLPOINTER) 1000000000) {
9469 	    goto e01s02;
9470 	}
9471 	return SQL_SUCCESS;
9472 #ifdef SQL_ATTR_METADATA_ID
9473     case SQL_ATTR_METADATA_ID:
9474 	if (val != (SQLPOINTER) SQL_FALSE) {
9475 	    goto e01s02;
9476 	}
9477 	return SQL_SUCCESS;
9478 #endif
9479     }
9480     return drvunimplstmt(stmt);
9481 }
9482 
9483 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
9484 /**
9485  * Set option on HSTMT.
9486  * @param stmt statement handle
9487  * @param attr attribute to be set
9488  * @param val input buffer (attribute value)
9489  * @param buflen length of input buffer
9490  * @result ODBC error code
9491  */
9492 
9493 SQLRETURN SQL_API
SQLSetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)9494 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9495 	       SQLINTEGER buflen)
9496 {
9497     SQLRETURN ret;
9498 
9499     HSTMT_LOCK(stmt);
9500     ret = drvsetstmtattr(stmt, attr, val, buflen);
9501     HSTMT_UNLOCK(stmt);
9502     return ret;
9503 }
9504 #endif
9505 
9506 #ifdef WINTERFACE
9507 /**
9508  * Set option on HSTMT (UNICODE version).
9509  * @param stmt statement handle
9510  * @param attr attribute to be set
9511  * @param val input buffer (attribute value)
9512  * @param buflen length of input buffer
9513  * @result ODBC error code
9514  */
9515 
9516 SQLRETURN SQL_API
SQLSetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)9517 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9518 		SQLINTEGER buflen)
9519 {
9520     SQLRETURN ret;
9521 
9522     HSTMT_LOCK(stmt);
9523     ret = drvsetstmtattr(stmt, attr, val, buflen);
9524     HSTMT_UNLOCK(stmt);
9525     return ret;
9526 }
9527 #endif
9528 
9529 /**
9530  * Internal get option of HSTMT.
9531  * @param stmt statement handle
9532  * @param opt option to be retrieved
9533  * @param param output buffer
9534  * @result ODBC error code
9535  */
9536 
9537 static SQLRETURN
drvgetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)9538 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
9539 {
9540     STMT *s = (STMT *) stmt;
9541     SQLUINTEGER *ret = (SQLUINTEGER *) param;
9542 
9543     switch (opt) {
9544     case SQL_QUERY_TIMEOUT:
9545 	*ret = 0;
9546 	return SQL_SUCCESS;
9547     case SQL_CURSOR_TYPE:
9548 	*ret = s->curtype;
9549 	return SQL_SUCCESS;
9550     case SQL_ROW_NUMBER:
9551 	if (s->s3stmt) {
9552 	    *ret = (s->s3stmt_rownum < 0) ?
9553 		   SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
9554 	} else {
9555 	    *ret = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
9556 	}
9557 	return SQL_SUCCESS;
9558     case SQL_ASYNC_ENABLE:
9559 	*ret = SQL_ASYNC_ENABLE_OFF;
9560 	return SQL_SUCCESS;
9561     case SQL_CONCURRENCY:
9562 	*ret = SQL_CONCUR_LOCK;
9563 	return SQL_SUCCESS;
9564     case SQL_ATTR_RETRIEVE_DATA:
9565 	*ret = s->retr_data;
9566 	return SQL_SUCCESS;
9567     case SQL_ROWSET_SIZE:
9568     case SQL_ATTR_ROW_ARRAY_SIZE:
9569 	*ret = s->rowset_size;
9570 	return SQL_SUCCESS;
9571     case SQL_ATTR_MAX_ROWS:
9572 	*ret = s->max_rows;
9573 	return SQL_SUCCESS;
9574     case SQL_ATTR_MAX_LENGTH:
9575 	*ret = 1000000000;
9576 	return SQL_SUCCESS;
9577     }
9578     return drvunimplstmt(stmt);
9579 }
9580 
9581 /**
9582  * Get option of HSTMT.
9583  * @param stmt statement handle
9584  * @param opt option to be retrieved
9585  * @param param output buffer
9586  * @result ODBC error code
9587  */
9588 
9589 SQLRETURN SQL_API
SQLGetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)9590 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
9591 {
9592     SQLRETURN ret;
9593 
9594     HSTMT_LOCK(stmt);
9595     ret = drvgetstmtoption(stmt, opt, param);
9596     HSTMT_UNLOCK(stmt);
9597     return ret;
9598 }
9599 
9600 #ifdef WINTERFACE
9601 /**
9602  * Get option of HSTMT (UNICODE version).
9603  * @param stmt statement handle
9604  * @param opt option to be retrieved
9605  * @param param output buffer
9606  * @result ODBC error code
9607  */
9608 
9609 SQLRETURN SQL_API
SQLGetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)9610 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
9611 {
9612     SQLRETURN ret;
9613 
9614     HSTMT_LOCK(stmt);
9615     ret = drvgetstmtoption(stmt, opt, param);
9616     HSTMT_UNLOCK(stmt);
9617     return ret;
9618 }
9619 #endif
9620 
9621 /**
9622  * Internal set option on HSTMT.
9623  * @param stmt statement handle
9624  * @param opt option to be set
9625  * @param param input buffer (option value)
9626  * @result ODBC error code
9627  */
9628 
9629 static SQLRETURN
drvsetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLUINTEGER param)9630 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
9631 {
9632     STMT *s = (STMT *) stmt;
9633 
9634     switch (opt) {
9635     case SQL_CURSOR_TYPE:
9636 	if (param == SQL_CURSOR_FORWARD_ONLY) {
9637 	    s->curtype = param;
9638 	} else {
9639 	    s->curtype = SQL_CURSOR_STATIC;
9640 	}
9641 	if (param != SQL_CURSOR_FORWARD_ONLY &&
9642 	    param != SQL_CURSOR_STATIC) {
9643 	    goto e01s02;
9644 	}
9645 	return SQL_SUCCESS;
9646     case SQL_ASYNC_ENABLE:
9647 	if (param != SQL_ASYNC_ENABLE_OFF) {
9648 	    goto e01s02;
9649 	}
9650 	return SQL_SUCCESS;
9651     case SQL_CONCURRENCY:
9652 	if (param != SQL_CONCUR_LOCK) {
9653 	    goto e01s02;
9654 	}
9655 	return SQL_SUCCESS;
9656     case SQL_QUERY_TIMEOUT:
9657 	return SQL_SUCCESS;
9658     case SQL_RETRIEVE_DATA:
9659 	if (param != SQL_RD_ON && param != SQL_RD_OFF) {
9660     e01s02:
9661 	    setstat(s, -1, "option value changed", "01S02");
9662 	    return SQL_SUCCESS_WITH_INFO;
9663 	}
9664 	s->retr_data = (int) param;
9665 	return SQL_SUCCESS;
9666     case SQL_ROWSET_SIZE:
9667     case SQL_ATTR_ROW_ARRAY_SIZE:
9668 	if (param < 1) {
9669 	    setstat(s, -1, "invalid rowset size", "HY000");
9670 	    return SQL_ERROR;
9671 	} else {
9672 	    SQLUSMALLINT *rst = &s->row_status1;
9673 
9674 	    if (param > 1) {
9675 		rst = xmalloc(sizeof (SQLUSMALLINT) * param);
9676 		if (!rst) {
9677 		    return nomem(s);
9678 		}
9679 	    }
9680 	    if (s->row_status0 != &s->row_status1) {
9681 		freep(&s->row_status0);
9682 	    }
9683 	    s->row_status0 = rst;
9684 	    s->rowset_size = param;
9685 	}
9686 	return SQL_SUCCESS;
9687     case SQL_ATTR_MAX_ROWS:
9688 	s->max_rows = param;
9689 	return SQL_SUCCESS;
9690     case SQL_ATTR_MAX_LENGTH:
9691 	if (param != 1000000000) {
9692 	    goto e01s02;
9693 	}
9694 	return SQL_SUCCESS;
9695     }
9696     return drvunimplstmt(stmt);
9697 }
9698 
9699 /**
9700  * Set option on HSTMT.
9701  * @param stmt statement handle
9702  * @param opt option to be set
9703  * @param param input buffer (option value)
9704  * @result ODBC error code
9705  */
9706 
9707 SQLRETURN SQL_API
SQLSetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)9708 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt,
9709 		 SETSTMTOPTION_LAST_ARG_TYPE param)
9710 {
9711     SQLRETURN ret;
9712 
9713     HSTMT_LOCK(stmt);
9714     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
9715     HSTMT_UNLOCK(stmt);
9716     return ret;
9717 }
9718 
9719 #ifdef WINTERFACE
9720 /**
9721  * Set option on HSTMT (UNICODE version).
9722  * @param stmt statement handle
9723  * @param opt option to be set
9724  * @param param input buffer (option value)
9725  * @result ODBC error code
9726  */
9727 
9728 SQLRETURN SQL_API
SQLSetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)9729 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt,
9730 		  SETSTMTOPTION_LAST_ARG_TYPE param)
9731 {
9732     SQLRETURN ret;
9733 
9734     HSTMT_LOCK(stmt);
9735     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
9736     HSTMT_UNLOCK(stmt);
9737     return ret;
9738 }
9739 #endif
9740 
9741 /**
9742  * Check for unbound result columns.
9743  * @param s statement handle
9744  * @result ODBC error code
9745  */
9746 
9747 static SQLRETURN
chkunbound(STMT * s)9748 chkunbound(STMT *s)
9749 {
9750     int i;
9751 
9752     if (!s->bindcols || s->nbindcols < s->ncols) {
9753 unbound:
9754 	setstat(s, -1, "unbound columns", (*s->ov3) ? "HY000" : "S1000");
9755 	return SQL_ERROR;
9756     }
9757     for (i = 0; i < s->ncols; i++) {
9758 	BINDCOL *b = &s->bindcols[i];
9759 
9760 	if (b->type == SQL_UNKNOWN_TYPE || !b->valp) {
9761 	    goto unbound;
9762 	}
9763     }
9764     return SQL_SUCCESS;
9765 }
9766 
9767 /**
9768  * Internal handler to setup parameters for positional updates
9769  * from bound user buffers.
9770  * @param s statement handle
9771  * @param stmt SQLite3 statement pointer
9772  * @param i result set column index
9773  * @param si SQLite3 parameter index
9774  * @param rsi result set row index
9775  * @result ODBC error code
9776  */
9777 
9778 static SQLRETURN
setposbind(STMT * s,sqlite3_stmt * stmt,int i,int si,int rsi)9779 setposbind(STMT *s, sqlite3_stmt *stmt, int i, int si, int rsi)
9780 {
9781     DBC *d = (DBC *) s->dbc;
9782     SQLPOINTER dp = 0;
9783     SQLLEN *lp = 0;
9784     BINDCOL *b = &s->bindcols[i];
9785     COL *c = &s->cols[i];
9786     char strbuf[128], *cp;
9787 
9788     if (b->valp) {
9789 	if (s->bind_type != SQL_BIND_BY_COLUMN) {
9790 	    dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
9791 	} else {
9792 	    dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
9793 	}
9794 	if (s->bind_offs) {
9795 	    dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
9796 	}
9797     }
9798     if (b->lenp) {
9799 	if (s->bind_type != SQL_BIND_BY_COLUMN) {
9800 	    lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
9801 	} else {
9802 	    lp = b->lenp + rsi;
9803 	}
9804 	if (s->bind_offs) {
9805 	    lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
9806 	}
9807     }
9808     if (!dp || !lp) {
9809 	setstat(s, -1, "unbound column in positional update",
9810 		(*s->ov3) ? "HY000" : "S1000");
9811 	return SQL_ERROR;
9812     }
9813     if (*lp == SQL_NULL_DATA) {
9814 	sqlite3_bind_null(stmt, si);
9815 	if (d->trace) {
9816 	    fprintf(d->trace, "-- parameter %d: NULL\n", si);
9817 	    fflush(d->trace);
9818 	}
9819 	return SQL_SUCCESS;
9820     }
9821     switch (b->type) {
9822     case SQL_C_UTINYINT:
9823     case SQL_C_TINYINT:
9824     case SQL_C_STINYINT:
9825 	sqlite3_bind_int(stmt, si, *(SQLCHAR *) dp);
9826 	if (d->trace) {
9827 	    fprintf(d->trace, "-- parameter %d: %d\n", si, *(SQLCHAR *) dp);
9828 	    fflush(d->trace);
9829 	}
9830 	break;
9831 #ifdef SQL_BIT
9832     case SQL_C_BIT:
9833 	sqlite3_bind_int(stmt, si, (*(SQLCHAR *) dp) ? 1 : 0);
9834 	if (d->trace) {
9835 	    fprintf(d->trace, "-- parameter %d: %d\n", si,
9836 		    (*(SQLCHAR *) dp) ? 1 : 0);
9837 	    fflush(d->trace);
9838 	}
9839 	break;
9840 #endif
9841     case SQL_C_USHORT:
9842 	sqlite3_bind_int(stmt, si, *(SQLUSMALLINT *) dp);
9843 	if (d->trace) {
9844 	    fprintf(d->trace, "-- parameter %d: %d\n", si,
9845 		    *(SQLUSMALLINT *) dp);
9846 	    fflush(d->trace);
9847 	}
9848 	break;
9849     case SQL_C_SHORT:
9850     case SQL_C_SSHORT:
9851 	sqlite3_bind_int(stmt, si, *(SQLSMALLINT *) dp);
9852 	if (d->trace) {
9853 	    fprintf(d->trace, "-- parameter %d: %d\n", si,
9854 		    *(SQLSMALLINT *) dp);
9855 	    fflush(d->trace);
9856 	}
9857 	break;
9858     case SQL_C_ULONG:
9859 	sqlite3_bind_int(stmt, si, *(SQLUINTEGER *) dp);
9860 	if (d->trace) {
9861 	    fprintf(d->trace, "-- parameter %d: %ld\n", si,
9862 		    (long) *(SQLUINTEGER *) dp);
9863 	    fflush(d->trace);
9864 	}
9865 	break;
9866     case SQL_C_LONG:
9867     case SQL_C_SLONG:
9868 	sqlite3_bind_int(stmt, si, *(SQLINTEGER *) dp);
9869 	if (d->trace) {
9870 	    fprintf(d->trace, "-- parameter %d: %ld\n", si,
9871 		    (long) *(SQLINTEGER *) dp);
9872 	    fflush(d->trace);
9873 	}
9874 	break;
9875 #ifdef SQL_BIGINT
9876     case SQL_C_UBIGINT:
9877     case SQL_C_SBIGINT:
9878 	sqlite3_bind_int64(stmt, si, *(SQLBIGINT *) dp);
9879 	if (d->trace) {
9880 	    fprintf(d->trace,
9881 #ifdef _WIN32
9882 		    "-- parameter %d: %I64d\n",
9883 #else
9884 		    "-- parameter %d: %lld\n",
9885 #endif
9886 		    si, (sqlite_int64) *(SQLBIGINT *) dp);
9887 	    fflush(d->trace);
9888 	}
9889 	break;
9890 #endif
9891     case SQL_C_FLOAT:
9892 	sqlite3_bind_double(stmt, si, *(float *) dp);
9893 	if (d->trace) {
9894 	    fprintf(d->trace, "-- parameter %d: %g\n", si,
9895 		    *(float *) dp);
9896 	    fflush(d->trace);
9897 	}
9898 	break;
9899     case SQL_C_DOUBLE:
9900 	sqlite3_bind_double(stmt, si, *(double *) dp);
9901 	if (d->trace) {
9902 	    fprintf(d->trace, "-- parameter %d: %g\n", si,
9903 		    *(double *) dp);
9904 	    fflush(d->trace);
9905 	}
9906 	break;
9907     case SQL_C_BINARY:
9908 	sqlite3_bind_blob(stmt, si, (char *) dp, *lp, SQLITE_STATIC);
9909 	if (d->trace) {
9910 	    fprintf(d->trace, "-- parameter %d: [BLOB]\n", si);
9911 	    fflush(d->trace);
9912 	}
9913 	break;
9914 #ifdef WCHARSUPPORT
9915     case SQL_C_WCHAR:
9916 	cp = uc_to_utf((SQLWCHAR *) dp, *lp);
9917 	if (!cp) {
9918 	    return nomem(s);
9919 	}
9920 	sqlite3_bind_text(stmt, si, cp, -1, SQLITE_TRANSIENT);
9921 	if (d->trace) {
9922 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, cp);
9923 	    fflush(d->trace);
9924 	}
9925 	uc_free(cp);
9926 	break;
9927 #endif
9928     case SQL_C_CHAR:
9929 #if defined(_WIN32) || defined(_WIN64)
9930 	if (*s->oemcp) {
9931 	    cp = wmb_to_utf((char *) dp, *lp);
9932 	    if (!cp) {
9933 		return nomem(s);
9934 	    }
9935 	    sqlite3_bind_text(stmt, si, cp, -1, SQLITE_TRANSIENT);
9936 	    if (d->trace) {
9937 		fprintf(d->trace, "-- parameter %d: '%s'\n", si, cp);
9938 		fflush(d->trace);
9939 	    }
9940 	    uc_free(cp);
9941 	} else
9942 #endif
9943 	{
9944 	    if (*lp == SQL_NTS) {
9945 		sqlite3_bind_text(stmt, si, (char *) dp, -1,
9946 				  SQLITE_STATIC);
9947 		if (d->trace) {
9948 		    fprintf(d->trace, "-- parameter %d: '%s'\n", si,
9949 			    (char *) dp);
9950 		    fflush(d->trace);
9951 		}
9952 	    } else {
9953 		sqlite3_bind_text(stmt, si, (char *) dp, *lp,
9954 				  SQLITE_STATIC);
9955 		if (d->trace) {
9956 		    fprintf(d->trace, "-- parameter %d: '%*s'\n", si,
9957 			    (int) *lp, (char *) dp);
9958 		    fflush(d->trace);
9959 		}
9960 	    }
9961 	}
9962 	break;
9963 #ifdef SQL_C_TYPE_DATE
9964     case SQL_C_TYPE_DATE:
9965 #endif
9966     case SQL_C_DATE:
9967 	if (*s->jdconv) {
9968 	    int a, b, x1, x2, y, m, dd;
9969 	    double v;
9970 
9971 	    y = ((DATE_STRUCT *) dp)->year;
9972 	    m = ((DATE_STRUCT *) dp)->month;
9973 	    dd = ((DATE_STRUCT *) dp)->day;
9974 	    if (m <= 2) {
9975 		y--;
9976 		m += 12;
9977 	    }
9978 	    a = y / 100;
9979 	    b = 2 - a + (a / 4);
9980 	    x1 = 36525 * (y + 4716) / 100;
9981 	    x2 = 306001 * (m + 1) / 10000;
9982 	    v = x1 + x2 + dd + b - 1524.5;
9983 	    sqlite3_bind_double(stmt, si, v);
9984 	    if (d->trace) {
9985 		fprintf(d->trace, "-- parameter %d: %g\n", si, v);
9986 		fflush(d->trace);
9987 	    }
9988 	} else {
9989 	    sprintf(strbuf, "%04d-%02d-%02d",
9990 		    ((DATE_STRUCT *) dp)->year,
9991 		    ((DATE_STRUCT *) dp)->month,
9992 		    ((DATE_STRUCT *) dp)->day);
9993 	    sqlite3_bind_text(stmt, si, strbuf, -1, SQLITE_TRANSIENT);
9994 	    if (d->trace) {
9995 		fprintf(d->trace, "-- parameter %d: '%s'\n", si, strbuf);
9996 		fflush(d->trace);
9997 	    }
9998 	}
9999 	break;
10000 #ifdef SQL_C_TYPE_TIME
10001     case SQL_C_TYPE_TIME:
10002 #endif
10003     case SQL_C_TIME:
10004 	if (*s->jdconv) {
10005 	    double v;
10006 
10007 	    v = 2451544.5 +
10008 	       (((TIME_STRUCT *) dp)->hour * 3600000.0 +
10009 		((TIME_STRUCT *) dp)->minute * 60000.0 +
10010 		((TIME_STRUCT *) dp)->second * 1000.0) / 86400000.0;
10011 	    sqlite3_bind_double(stmt, si, v);
10012 	    if (d->trace) {
10013 		fprintf(d->trace, "-- parameter %d: %g\n", si, v);
10014 		fflush(d->trace);
10015 	    }
10016 	} else {
10017 	    sprintf(strbuf, "%02d:%02d:%02d",
10018 		    ((TIME_STRUCT *) dp)->hour,
10019 		    ((TIME_STRUCT *) dp)->minute,
10020 		    ((TIME_STRUCT *) dp)->second);
10021 	    sqlite3_bind_text(stmt, si, strbuf, -1, SQLITE_TRANSIENT);
10022 	    if (d->trace) {
10023 		fprintf(d->trace, "-- parameter %d: '%s'\n", si, strbuf);
10024 		fflush(d->trace);
10025 	    }
10026 	}
10027 	break;
10028 #ifdef SQL_C_TYPE_TIMESTAMP
10029     case SQL_C_TYPE_TIMESTAMP:
10030 #endif
10031     case SQL_C_TIMESTAMP:
10032 	if (*s->jdconv) {
10033 	    int a, b, x1, x2, y, m, dd;
10034 	    double v;
10035 
10036 	    y = ((TIMESTAMP_STRUCT *) dp)->year;
10037 	    m = ((TIMESTAMP_STRUCT *) dp)->month;
10038 	    dd = ((TIMESTAMP_STRUCT *) dp)->day;
10039 	    if (m <= 2) {
10040 		y--;
10041 		m += 12;
10042 	    }
10043 	    a = y / 100;
10044 	    b = 2 - a + (a / 4);
10045 	    x1 = 36525 * (y + 4716) / 100;
10046 	    x2 = 306001 * (m + 1) / 10000;
10047 	    v = x1 + x2 + dd + b - 1524.5 +
10048 	       (((TIMESTAMP_STRUCT *) dp)->hour * 3600000.0 +
10049 		((TIMESTAMP_STRUCT *) dp)->minute * 60000.0 +
10050 		((TIMESTAMP_STRUCT *) dp)->second * 1000.0 +
10051 		((TIMESTAMP_STRUCT *) dp)->fraction / 1.0E6)
10052 	       / 86400000.0;
10053 	    sqlite3_bind_double(stmt, si, v);
10054 	    if (d->trace) {
10055 		fprintf(d->trace, "-- parameter %d: %g\n", si, v);
10056 		fflush(d->trace);
10057 	    }
10058 	} else {
10059 	    int frac;
10060 
10061 	    frac = (int) ((TIMESTAMP_STRUCT *) dp)->fraction;
10062 	    frac /= 1000000;
10063 	    frac = frac % 1000;
10064 	    if (frac < 0) {
10065 		frac = 0;
10066 	    }
10067 	    if (c->prec && c->prec <= 16) {
10068 		sprintf(strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
10069 			((TIMESTAMP_STRUCT *) dp)->year,
10070 			((TIMESTAMP_STRUCT *) dp)->month,
10071 			((TIMESTAMP_STRUCT *) dp)->day,
10072 			((TIMESTAMP_STRUCT *) dp)->hour,
10073 			((TIMESTAMP_STRUCT *) dp)->minute);
10074 	    } else if (c->prec && c->prec <= 19) {
10075 		sprintf(strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
10076 			((TIMESTAMP_STRUCT *) dp)->year,
10077 			((TIMESTAMP_STRUCT *) dp)->month,
10078 			((TIMESTAMP_STRUCT *) dp)->day,
10079 			((TIMESTAMP_STRUCT *) dp)->hour,
10080 			((TIMESTAMP_STRUCT *) dp)->minute,
10081 			((TIMESTAMP_STRUCT *) dp)->second);
10082 	    } else {
10083 		sprintf(strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
10084 			((TIMESTAMP_STRUCT *) dp)->year,
10085 			((TIMESTAMP_STRUCT *) dp)->month,
10086 			((TIMESTAMP_STRUCT *) dp)->day,
10087 			((TIMESTAMP_STRUCT *) dp)->hour,
10088 			((TIMESTAMP_STRUCT *) dp)->minute,
10089 			((TIMESTAMP_STRUCT *) dp)->second,
10090 			frac);
10091 	    }
10092 	    sqlite3_bind_text(stmt, si, strbuf, -1, SQLITE_TRANSIENT);
10093 	    if (d->trace) {
10094 		fprintf(d->trace, "-- parameter %d: '%s'\n", si, strbuf);
10095 		fflush(d->trace);
10096 	    }
10097 	}
10098 	break;
10099     default:
10100 	setstat(s, -1, "unsupported column type in positional update",
10101 		(*s->ov3) ? "HY000" : "S1000");
10102 	return SQL_ERROR;
10103     }
10104     return SQL_SUCCESS;
10105 }
10106 
10107 /**
10108  * Internal handler to setup parameters for positional updates
10109  * from driver side result set.
10110  * @param s statement handle
10111  * @param stmt SQLite3 statement pointer
10112  * @param i result set column index
10113  * @param si SQLite3 parameter index
10114  * @param rsi result set row index
10115  * @result ODBC error code
10116  */
10117 
10118 static SQLRETURN
setposibind(STMT * s,sqlite3_stmt * stmt,int i,int si,int rsi)10119 setposibind(STMT *s, sqlite3_stmt *stmt, int i, int si, int rsi)
10120 {
10121     DBC *d = (DBC *) s->dbc;
10122     char **data;
10123     int pos;
10124 
10125     pos = s->rowprs;
10126     if (pos < 0) {
10127 	setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
10128 	return SQL_ERROR;
10129     }
10130     pos += rsi;
10131     data = s->rows + s->ncols + (pos * s->ncols) + i;
10132     if (*data == NULL) {
10133 	sqlite3_bind_null(stmt, si);
10134 	if (d->trace) {
10135 	    fprintf(d->trace, "-- parameter %d: NULL\n", si);
10136 	    fflush(d->trace);
10137 	}
10138     } else {
10139 	sqlite3_bind_text(stmt, si, *data, -1, SQLITE_STATIC);
10140 	if (d->trace) {
10141 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, *data);
10142 	    fflush(d->trace);
10143 	}
10144     }
10145     return SQL_SUCCESS;
10146 }
10147 
10148 /**
10149  * Internal handler to refresh user buffers from driver side result set.
10150  * @param s statement handle
10151  * @param rsi result set row index
10152  * @result ODBC error code
10153  */
10154 
10155 static SQLRETURN
setposrefr(STMT * s,int rsi)10156 setposrefr(STMT *s, int rsi)
10157 {
10158     int i, withinfo = 0;
10159     SQLRETURN ret = SQL_SUCCESS;
10160 
10161     for (i = 0; s->bindcols && i < s->ncols; i++) {
10162 	BINDCOL *b = &s->bindcols[i];
10163 	SQLPOINTER dp = 0;
10164 	SQLLEN *lp = 0;
10165 
10166 	b->offs = 0;
10167 	if (b->valp) {
10168 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10169 		dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
10170 	    } else {
10171 		dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
10172 	    }
10173 	    if (s->bind_offs) {
10174 		dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
10175 	    }
10176 	}
10177 	if (b->lenp) {
10178 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10179 		lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
10180 	    } else {
10181 		lp = b->lenp + rsi;
10182 	    }
10183 	    if (s->bind_offs) {
10184 		lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
10185 	    }
10186 	}
10187 	if (dp || lp) {
10188 	    int rowp = s->rowp;
10189 
10190 	    s->rowp = s->rowprs + rsi;
10191 	    ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp,
10192 			     b->max, lp, 0);
10193 	    s->rowp = rowp;
10194 	    if (!SQL_SUCCEEDED(ret)) {
10195 		s->row_status0[rsi] = SQL_ROW_ERROR;
10196 		break;
10197 	    }
10198 	    if (ret != SQL_SUCCESS) {
10199 		withinfo = 1;
10200 #ifdef SQL_ROW_SUCCESS_WITH_INFO
10201 		s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
10202 #endif
10203 	    }
10204 	}
10205     }
10206     if (SQL_SUCCEEDED(ret)) {
10207 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
10208     }
10209     return ret;
10210 }
10211 
10212 /**
10213  * Internal set position on result in HSTMT.
10214  * @param stmt statement handle
10215  * @param row row to be positioned
10216  * @param op operation code
10217  * @param lock locking type
10218  * @result ODBC error code
10219  */
10220 
10221 static SQLRETURN
drvsetpos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)10222 drvsetpos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
10223 {
10224     STMT *s = (STMT *) stmt;
10225     DBC *d = (DBC *) s->dbc;
10226     int rowp, i, k, rc, nretry = 0;
10227     dstr *sql = 0;
10228     const char *endp;
10229     sqlite3_stmt *s3stmt = NULL;
10230     SQLRETURN ret;
10231 
10232     if (lock != SQL_LOCK_NO_CHANGE) {
10233 	setstat(s, -1, "unsupported locking mode",
10234 		(*s->ov3) ? "HY000" : "S1000");
10235 	return SQL_ERROR;
10236     }
10237     if (s->isselect != 1 || s->curtype != SQL_CURSOR_STATIC) {
10238 	setstat(s, -1, "incompatible statement",
10239 		(*s->ov3) ? "HY000" : "S1000");
10240 	return SQL_ERROR;
10241     }
10242     if (op == SQL_ADD) {
10243 	if (s->one_tbl <= 0) {
10244 	    setstat(s, -1, "incompatible rowset",
10245 		    (*s->ov3) ? "HY000" : "S1000");
10246 	    return SQL_ERROR;
10247 	}
10248 	if (row == 0 || row > s->rowset_size + 1) {
10249 	    goto rowoor;
10250 	}
10251 	ret = chkunbound(s);
10252 	if (ret != SQL_SUCCESS) {
10253 	    return ret;
10254 	}
10255 	sql = dsappend(sql, "INSERT INTO ");
10256 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10257 	    sql = dsappendq(sql, s->dyncols[0].db);
10258 	    sql = dsappend(sql, ".");
10259 	}
10260 	sql = dsappendq(sql, s->dyncols[0].table);
10261 	for (i = 0; i < s->ncols; i++) {
10262 	    sql = dsappend(sql, (i > 0) ? "," : "(");
10263 	    sql = dsappendq(sql, s->dyncols[i].column);
10264 	}
10265 	sql = dsappend(sql, ") VALUES ");
10266 	for (i = 0; i < s->ncols; i++) {
10267 	    sql = dsappend(sql, (i > 0) ? ",?" : "(?");
10268 	}
10269 	sql = dsappend(sql, ")");
10270 	if (dserr(sql)) {
10271 	    dsfree(sql);
10272 	    return nomem(s);
10273 	}
10274 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10275 	dbtraceapi(d, "sqlite3_prepare_v2", dsval(sql));
10276 #else
10277 	dbtraceapi(d, "sqlite3_prepare", dsval(sql));
10278 #endif
10279 	do {
10280 	    s3stmt = NULL;
10281 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10282 	    rc = sqlite3_prepare_v2(d->sqlite, dsval(sql), -1,
10283 				    &s3stmt, &endp);
10284 #else
10285 	    rc = sqlite3_prepare(d->sqlite, dsval(sql), -1,
10286 				 &s3stmt, &endp);
10287 #endif
10288 	    if (rc != SQLITE_OK) {
10289 		if (s3stmt) {
10290 		    sqlite3_finalize(s3stmt);
10291 		    s3stmt = NULL;
10292 		}
10293 	    }
10294 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
10295 	dbtracerc(d, rc, NULL);
10296 	dsfree(sql);
10297 	if (rc != SQLITE_OK) {
10298 istmterr:
10299 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10300 		    sqlite3_errmsg(d->sqlite), rc);
10301 	    if (s3stmt) {
10302 		dbtraceapi(d, "sqlite3_finalize", NULL);
10303 		sqlite3_finalize(s3stmt);
10304 	    }
10305 	    return SQL_ERROR;
10306 	}
10307 	for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10308 	    ret = setposbind(s, s3stmt, i, k, row - 1);
10309 	    if (ret != SQL_SUCCESS) {
10310 		dbtraceapi(d, "sqlite3_finalize", NULL);
10311 		sqlite3_finalize(s3stmt);
10312 		return ret;
10313 	    }
10314 	    k++;
10315 	}
10316 	rc = sqlite3_step(s3stmt);
10317 	if (rc != SQLITE_DONE) {
10318 	    goto istmterr;
10319 	}
10320 	sqlite3_finalize(s3stmt);
10321 	if (sqlite3_changes(d->sqlite) > 0 && row <= s->rowset_size) {
10322 	    if (s->row_status0) {
10323 		s->row_status0[row - 1] = SQL_ROW_ADDED;
10324 	    }
10325 	    if (s->row_status) {
10326 		s->row_status[row - 1] = SQL_ROW_ADDED;
10327 	    }
10328 	}
10329 	return SQL_SUCCESS;
10330     } else if (op == SQL_UPDATE || op == SQL_DELETE) {
10331 	if (s->one_tbl <= 0 || s->has_pk <= 0) {
10332 	    setstat(s, -1, "incompatible rowset",
10333 		    (*s->ov3) ? "HY000" : "S1000");
10334 	    return SQL_ERROR;
10335 	}
10336 	if (row == 0) {
10337 	    ret = SQL_SUCCESS;
10338 	    for (i = 1; i <= s->rowset_size; i++) {
10339 		ret = drvsetpos(stmt, i, op, lock);
10340 		if (!SQL_SUCCEEDED(ret)) {
10341 		    break;
10342 		}
10343 	    }
10344 	    return ret;
10345 	}
10346 	if (row > s->rowset_size) {
10347 	    goto rowoor;
10348 	}
10349     }
10350     if (op != SQL_POSITION && op != SQL_REFRESH &&
10351 	op != SQL_DELETE && op != SQL_UPDATE) {
10352 	return drvunimplstmt(stmt);
10353     }
10354     if (op == SQL_POSITION) {
10355 	rowp = s->rowp + row - 1;
10356 	if (!s->rows || row == 0 || rowp < -1 || rowp >= s->nrows) {
10357 rowoor:
10358 	    setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
10359 	    return SQL_ERROR;
10360 	}
10361 	s->rowp = rowp;
10362     } else if (op == SQL_REFRESH) {
10363 	if (row > s->rowset_size) {
10364 	    goto rowoor;
10365 	}
10366 	if (row == 0) {
10367 	    ret = SQL_SUCCESS;
10368 	    for (i = 0; i < s->rowset_size; i++) {
10369 		ret = setposrefr(s, i);
10370 		if (!SQL_SUCCEEDED(ret)) {
10371 		    break;
10372 		}
10373 	    }
10374 	    return ret;
10375 	}
10376 	return setposrefr(s, row - 1);
10377     } else if (op == SQL_DELETE) {
10378 	sql = dsappend(sql, "DELETE FROM ");
10379 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10380 	    sql = dsappendq(sql, s->dyncols[0].db);
10381 	    sql = dsappend(sql, ".");
10382 	}
10383 	sql = dsappendq(sql, s->dyncols[0].table);
10384 	for (i = k = 0; i < s->ncols; i++) {
10385 	    if (s->dyncols[i].ispk <= 0) {
10386 		continue;
10387 	    }
10388 	    sql = dsappend(sql, (k > 0) ? " AND " : " WHERE ");
10389 	    sql = dsappendq(sql, s->dyncols[i].column);
10390 	    sql = dsappend(sql, " = ?");
10391 	    k++;
10392 	}
10393 	if (dserr(sql)) {
10394 	    dsfree(sql);
10395 	    return nomem(s);
10396 	}
10397 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10398 	dbtraceapi(d, "sqlite3_prepare_v2", dsval(sql));
10399 #else
10400 	dbtraceapi(d, "sqlite3_prepare", dsval(sql));
10401 #endif
10402 	do {
10403 	    s3stmt = NULL;
10404 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10405 	    rc = sqlite3_prepare_v2(d->sqlite, dsval(sql), -1,
10406 				    &s3stmt, &endp);
10407 #else
10408 	    rc = sqlite3_prepare(d->sqlite, dsval(sql), -1,
10409 				 &s3stmt, &endp);
10410 #endif
10411 	    if (rc != SQLITE_OK) {
10412 		if (s3stmt) {
10413 		    sqlite3_finalize(s3stmt);
10414 		    s3stmt = NULL;
10415 		}
10416 	    }
10417 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
10418 	dbtracerc(d, rc, NULL);
10419 	dsfree(sql);
10420 	if (rc != SQLITE_OK) {
10421 dstmterr:
10422 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10423 		    sqlite3_errmsg(d->sqlite), rc);
10424 	    if (s3stmt) {
10425 		dbtraceapi(d, "sqlite3_finalize", NULL);
10426 		sqlite3_finalize(s3stmt);
10427 	    }
10428 	    return SQL_ERROR;
10429 	}
10430 	for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10431 	    if (s->dyncols[i].ispk <= 0) {
10432 		continue;
10433 	    }
10434 	    ret = setposibind(s, s3stmt, i, k, row - 1);
10435 	    if (ret != SQL_SUCCESS) {
10436 		dbtraceapi(d, "sqlite3_finalize", NULL);
10437 		sqlite3_finalize(s3stmt);
10438 		return ret;
10439 	    }
10440 	    k++;
10441 	}
10442 	rc = sqlite3_step(s3stmt);
10443 	if (rc != SQLITE_DONE) {
10444 	    goto dstmterr;
10445 	}
10446 	sqlite3_finalize(s3stmt);
10447 	if (sqlite3_changes(d->sqlite) > 0) {
10448 	    if (s->row_status0) {
10449 		s->row_status0[row - 1] = SQL_ROW_DELETED;
10450 	    }
10451 	    if (s->row_status) {
10452 		s->row_status[row - 1] = SQL_ROW_DELETED;
10453 	    }
10454 	}
10455 	return SQL_SUCCESS;
10456     } else if (op == SQL_UPDATE) {
10457 	ret = chkunbound(s);
10458 	if (ret != SQL_SUCCESS) {
10459 	    return ret;
10460 	}
10461 	sql = dsappend(sql, "UPDATE ");
10462 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10463 	    sql = dsappendq(sql, s->dyncols[0].db);
10464 	    sql = dsappend(sql, ".");
10465 	}
10466 	sql = dsappendq(sql, s->dyncols[0].table);
10467 	for (i = 0; i < s->ncols; i++) {
10468 	    sql = dsappend(sql, (i > 0) ? ", " : " SET ");
10469 	    sql = dsappendq(sql, s->dyncols[i].column);
10470 	    sql = dsappend(sql, " = ?");
10471 	}
10472 	for (i = k = 0; i < s->ncols; i++) {
10473 	    if (s->dyncols[i].ispk <= 0) {
10474 		continue;
10475 	    }
10476 	    sql = dsappend(sql, (k > 0) ? " AND " : " WHERE ");
10477 	    sql = dsappendq(sql, s->dyncols[i].column);
10478 	    sql = dsappend(sql, " = ?");
10479 	    k++;
10480 	}
10481 	if (dserr(sql)) {
10482 	    dsfree(sql);
10483 	    return nomem(s);
10484 	}
10485 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10486 	dbtraceapi(d, "sqlite3_prepare_v2", dsval(sql));
10487 #else
10488 	dbtraceapi(d, "sqlite3_prepare", dsval(sql));
10489 #endif
10490 	do {
10491 	    s3stmt = NULL;
10492 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10493 	    rc = sqlite3_prepare_v2(d->sqlite, dsval(sql), -1,
10494 				    &s3stmt, &endp);
10495 #else
10496 	    rc = sqlite3_prepare(d->sqlite, dsval(sql), -1,
10497 				 &s3stmt, &endp);
10498 #endif
10499 	    if (rc != SQLITE_OK) {
10500 		if (s3stmt) {
10501 		    sqlite3_finalize(s3stmt);
10502 		    s3stmt = NULL;
10503 		}
10504 	    }
10505 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
10506 	dbtracerc(d, rc, NULL);
10507 	dsfree(sql);
10508 	if (rc != SQLITE_OK) {
10509 ustmterr:
10510 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10511 		    sqlite3_errmsg(d->sqlite), rc);
10512 	    if (s3stmt) {
10513 		dbtraceapi(d, "sqlite3_finalize", NULL);
10514 		sqlite3_finalize(s3stmt);
10515 	    }
10516 	    return SQL_ERROR;
10517 	}
10518 	for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10519 	    ret = setposbind(s, s3stmt, i, k, row - 1);
10520 	    if (ret != SQL_SUCCESS) {
10521 		dbtraceapi(d, "sqlite3_finalize", NULL);
10522 		sqlite3_finalize(s3stmt);
10523 		return ret;
10524 	    }
10525 	    k++;
10526 	}
10527 	for (i = 0; s->bindcols && i < s->ncols; i++) {
10528 	    if (s->dyncols[i].ispk <= 0) {
10529 		continue;
10530 	    }
10531 	    ret = setposibind(s, s3stmt, i, k, row - 1);
10532 	    if (ret != SQL_SUCCESS) {
10533 		dbtraceapi(d, "sqlite3_finalize", NULL);
10534 		sqlite3_finalize(s3stmt);
10535 		return ret;
10536 	    }
10537 	    k++;
10538 	}
10539 	rc = sqlite3_step(s3stmt);
10540 	if (rc != SQLITE_DONE) {
10541 	    goto ustmterr;
10542 	}
10543 	sqlite3_finalize(s3stmt);
10544 	if (sqlite3_changes(d->sqlite) > 0) {
10545 	    if (s->row_status0) {
10546 		s->row_status0[row - 1] = SQL_ROW_UPDATED;
10547 	    }
10548 	    if (s->row_status) {
10549 		s->row_status[row - 1] = SQL_ROW_UPDATED;
10550 	    }
10551 	}
10552 	return SQL_SUCCESS;
10553     }
10554     return SQL_SUCCESS;
10555 }
10556 
10557 /**
10558  * Set position on result in HSTMT.
10559  * @param stmt statement handle
10560  * @param row row to be positioned
10561  * @param op operation code
10562  * @param lock locking type
10563  * @result ODBC error code
10564  */
10565 
10566 SQLRETURN SQL_API
SQLSetPos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)10567 SQLSetPos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
10568 {
10569     SQLRETURN ret;
10570 
10571     HSTMT_LOCK(stmt);
10572     ret = drvsetpos(stmt, row, op, lock);
10573     HSTMT_UNLOCK(stmt);
10574     return ret;
10575 }
10576 
10577 /**
10578  * Internal perform bulk operation on HSTMT.
10579  * @param stmt statement handle
10580  * @param op operation to be performed
10581  * @result ODBC error code
10582  */
10583 
10584 static SQLRETURN
drvbulkoperations(SQLHSTMT stmt,SQLSMALLINT op)10585 drvbulkoperations(SQLHSTMT stmt, SQLSMALLINT op)
10586 {
10587     STMT *s = (STMT *) stmt;
10588     DBC *d = (DBC *) s->dbc;
10589     int row, i, k, rc, nretry = 0;
10590     dstr *sql = 0;
10591     const char *endp;
10592     sqlite3_stmt *s3stmt = NULL;
10593     SQLRETURN ret;
10594 
10595     if (s->isselect != 1 || s->curtype != SQL_CURSOR_STATIC) {
10596 	setstat(s, -1, "incompatible statement",
10597 		(*s->ov3) ? "HY000" : "S1000");
10598 	return SQL_ERROR;
10599     }
10600     if (op == SQL_ADD) {
10601 	if (s->one_tbl <= 0) {
10602 	    setstat(s, -1, "incompatible rowset",
10603 		    (*s->ov3) ? "HY000" : "S1000");
10604 	    return SQL_ERROR;
10605 	}
10606 	ret = chkunbound(s);
10607 	if (ret != SQL_SUCCESS) {
10608 	    return ret;
10609 	}
10610 	sql = dsappend(sql, "INSERT INTO ");
10611 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10612 	    sql = dsappendq(sql, s->dyncols[0].db);
10613 	    sql = dsappend(sql, ".");
10614 	}
10615 	sql = dsappendq(sql, s->dyncols[0].table);
10616 	for (i = 0; i < s->ncols; i++) {
10617 	    sql = dsappend(sql, (i > 0) ? "," : "(");
10618 	    sql = dsappendq(sql, s->dyncols[i].column);
10619 	}
10620 	sql = dsappend(sql, ") VALUES ");
10621 	for (i = 0; i < s->ncols; i++) {
10622 	    sql = dsappend(sql, (i > 0) ? ",?" : "(?");
10623 	}
10624 	sql = dsappend(sql, ")");
10625 	if (dserr(sql)) {
10626 	    dsfree(sql);
10627 	    return nomem(s);
10628 	}
10629 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10630 	dbtraceapi(d, "sqlite3_prepare_v2", dsval(sql));
10631 #else
10632 	dbtraceapi(d, "sqlite3_prepare", dsval(sql));
10633 #endif
10634 	do {
10635 	    s3stmt = NULL;
10636 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10637 	    rc = sqlite3_prepare_v2(d->sqlite, dsval(sql), -1,
10638 				    &s3stmt, &endp);
10639 #else
10640 	    rc = sqlite3_prepare(d->sqlite, dsval(sql), -1,
10641 				 &s3stmt, &endp);
10642 #endif
10643 	    if (rc != SQLITE_OK) {
10644 		if (s3stmt) {
10645 		    sqlite3_finalize(s3stmt);
10646 		    s3stmt = NULL;
10647 		}
10648 	    }
10649 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
10650 	dbtracerc(d, rc, NULL);
10651 	dsfree(sql);
10652 	if (rc != SQLITE_OK) {
10653 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10654 		    sqlite3_errmsg(d->sqlite), rc);
10655 	    if (s3stmt) {
10656 		dbtraceapi(d, "sqlite3_finalize", NULL);
10657 		sqlite3_finalize(s3stmt);
10658 	    }
10659 	    return SQL_ERROR;
10660 	}
10661 	for (row = 0; row < s->rowset_size; row++) {
10662 	    for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10663 		ret = setposbind(s, s3stmt, i, k, row);
10664 		if (ret != SQL_SUCCESS) {
10665 istmterr:
10666 		    if (s->row_status0) {
10667 			s->row_status0[row] = SQL_ROW_ERROR;
10668 		    }
10669 		    if (s->row_status) {
10670 			s->row_status[row] = SQL_ROW_ERROR;
10671 		    }
10672 		    dbtraceapi(d, "sqlite3_finalize", NULL);
10673 		    sqlite3_finalize(s3stmt);
10674 		    return ret;
10675 		}
10676 		k++;
10677 	    }
10678 	    rc = sqlite3_step(s3stmt);
10679 	    if (rc != SQLITE_DONE) {
10680 		setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10681 			sqlite3_errmsg(d->sqlite), rc);
10682 		ret = SQL_ERROR;
10683 		goto istmterr;
10684 	    }
10685 	    if (sqlite3_changes(d->sqlite) > 0) {
10686 		if (s->row_status0) {
10687 		    s->row_status0[row] = SQL_ROW_ADDED;
10688 		}
10689 		if (s->row_status) {
10690 		    s->row_status[row] = SQL_ROW_ADDED;
10691 		}
10692 	    }
10693 	    if (s->bkmrk == SQL_UB_VARIABLE &&
10694 		s->bkmrkcol.type == SQL_C_VARBOOKMARK &&
10695 		s->bkmrkcol.valp) {
10696 		SQLPOINTER *val;
10697 
10698 		if (s->bind_type != SQL_BIND_BY_COLUMN) {
10699 		    val = (SQLPOINTER)
10700 			((char *) s->bkmrkcol.valp + s->bind_type * row);
10701 		} else {
10702 		    val = (SQLPOINTER)
10703 			((char *) s->bkmrkcol.valp + s->bkmrkcol.max * row);
10704 		}
10705 		if (s->bind_offs) {
10706 		    val = (SQLPOINTER) ((char *) val + *s->bind_offs);
10707 		}
10708 		*(sqlite_int64 *) val = sqlite3_last_insert_rowid(d->sqlite);
10709 		if (s->bkmrkcol.lenp) {
10710 		    SQLLEN *ival;
10711 
10712 		    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10713 			ival = (SQLLEN *)
10714 			    ((char *) s->bkmrkcol.lenp + s->bind_type * row);
10715 		    } else {
10716 			ival = &s->bkmrkcol.lenp[row];
10717 		    }
10718 		    if (s->bind_offs) {
10719 			ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
10720 		    }
10721 		    *ival = sizeof (sqlite_int64);
10722 		}
10723 	    }
10724 	    dbtraceapi(d, "sqlite3_reset", NULL);
10725 	    sqlite3_reset(s3stmt);
10726 	}
10727 	dbtraceapi(d, "sqlite3_finalize", NULL);
10728 	sqlite3_finalize(s3stmt);
10729 	return SQL_SUCCESS;
10730     } else if (op == SQL_DELETE_BY_BOOKMARK) {
10731 	if (s->has_rowid < 0 ||
10732 	    s->bkmrk != SQL_UB_VARIABLE ||
10733 	    s->bkmrkcol.type != SQL_C_VARBOOKMARK ||
10734 	    !s->bkmrkcol.valp) {
10735 	    setstat(s, -1, "incompatible rowset",
10736 		    (*s->ov3) ? "HY000" : "S1000");
10737 	    return SQL_ERROR;
10738 	}
10739 	sql = dsappend(sql, "DELETE FROM ");
10740 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10741 	    sql = dsappendq(sql, s->dyncols[0].db);
10742 	    sql = dsappend(sql, ".");
10743 	}
10744 	sql = dsappendq(sql, s->dyncols[0].table);
10745 	sql = dsappend(sql, " WHERE ");
10746 	sql = dsappendq(sql, s->dyncols[0].column);
10747 	sql = dsappend(sql, " = ?");
10748 	if (dserr(sql)) {
10749 	    dsfree(sql);
10750 	    return nomem(s);
10751 	}
10752 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10753 	dbtraceapi(d, "sqlite3_prepare_v2", dsval(sql));
10754 #else
10755 	dbtraceapi(d, "sqlite3_prepare", dsval(sql));
10756 #endif
10757 	do {
10758 	    s3stmt = NULL;
10759 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10760 	    rc = sqlite3_prepare_v2(d->sqlite, dsval(sql), -1,
10761 				    &s3stmt, &endp);
10762 #else
10763 	    rc = sqlite3_prepare(d->sqlite, dsval(sql), -1,
10764 				 &s3stmt, &endp);
10765 #endif
10766 	    if (rc != SQLITE_OK) {
10767 		if (s3stmt) {
10768 		    sqlite3_finalize(s3stmt);
10769 		    s3stmt = NULL;
10770 		}
10771 	    }
10772 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
10773 	dbtracerc(d, rc, NULL);
10774 	dsfree(sql);
10775 	if (rc != SQLITE_OK) {
10776 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10777 		    sqlite3_errmsg(d->sqlite), rc);
10778 	    if (s3stmt) {
10779 		dbtraceapi(d, "sqlite3_finalize", NULL);
10780 		sqlite3_finalize(s3stmt);
10781 	    }
10782 	    return SQL_ERROR;
10783 	}
10784 	for (row = 0; row < s->rowset_size; row++) {
10785 	    SQLPOINTER *val;
10786 	    sqlite_int64 rowid;
10787 
10788 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10789 		val = (SQLPOINTER)
10790 		    ((char *) s->bkmrkcol.valp + s->bind_type * row);
10791 	    } else {
10792 		val = (SQLPOINTER)
10793 		    ((char *) s->bkmrkcol.valp + s->bkmrkcol.max * row);
10794 	    }
10795 	    if (s->bind_offs) {
10796 		val = (SQLPOINTER) ((char *) val + *s->bind_offs);
10797 	    }
10798 	    if (s->bkmrkcol.lenp) {
10799 		SQLLEN *ival;
10800 
10801 		if (s->bind_type != SQL_BIND_BY_COLUMN) {
10802 		    ival = (SQLLEN *)
10803 			((char *) s->bkmrkcol.lenp + s->bind_type * row);
10804 		} else {
10805 		    ival = &s->bkmrkcol.lenp[row];
10806 		}
10807 		if (s->bind_offs) {
10808 		    ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
10809 		}
10810 		if (*ival != sizeof (sqlite_int64)) {
10811 		    continue;
10812 		}
10813 	    }
10814 	    rowid = *(sqlite_int64 *) val;
10815 	    sqlite3_bind_int64(s3stmt, 1, rowid);
10816 	    if (d->trace) {
10817 		fprintf(d->trace,
10818 #ifdef _WIN32
10819 			"-- parameter 1: %I64d\n",
10820 #else
10821 			"-- parameter 1: %lld\n",
10822 #endif
10823 			rowid);
10824 		fflush(d->trace);
10825 	    }
10826 	    rc = sqlite3_step(s3stmt);
10827 	    if (rc != SQLITE_DONE) {
10828 		setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10829 			sqlite3_errmsg(d->sqlite), rc);
10830 		if (s->row_status0) {
10831 		    s->row_status0[row] = SQL_ROW_ERROR;
10832 		}
10833 		if (s->row_status) {
10834 		    s->row_status[row] = SQL_ROW_ERROR;
10835 		}
10836 		dbtraceapi(d, "sqlite3_finalize", NULL);
10837 		sqlite3_finalize(s3stmt);
10838 		return SQL_ERROR;
10839 	    }
10840 	    if (sqlite3_changes(d->sqlite) > 0) {
10841 		if (s->row_status0) {
10842 		    s->row_status0[row] = SQL_ROW_DELETED;
10843 		}
10844 		if (s->row_status) {
10845 		    s->row_status[row] = SQL_ROW_DELETED;
10846 		}
10847 	    }
10848 	    dbtraceapi(d, "sqlite3_reset", NULL);
10849 	    sqlite3_reset(s3stmt);
10850 	}
10851 	dbtraceapi(d, "sqlite3_finalize", NULL);
10852 	sqlite3_finalize(s3stmt);
10853 	return SQL_SUCCESS;
10854     } else if (op == SQL_UPDATE_BY_BOOKMARK) {
10855 	if (s->has_rowid < 0 ||
10856 	    s->bkmrk != SQL_UB_VARIABLE ||
10857 	    s->bkmrkcol.type != SQL_C_VARBOOKMARK ||
10858 	    !s->bkmrkcol.valp) {
10859 	    setstat(s, -1, "incompatible rowset",
10860 		    (*s->ov3) ? "HY000" : "S1000");
10861 	    return SQL_ERROR;
10862 	}
10863 	ret = chkunbound(s);
10864 	if (ret != SQL_SUCCESS) {
10865 	    return ret;
10866 	}
10867 	sql = dsappend(sql, "UPDATE ");
10868 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10869 	    sql = dsappendq(sql, s->dyncols[0].db);
10870 	    sql = dsappend(sql, ".");
10871 	}
10872 	sql = dsappendq(sql, s->dyncols[0].table);
10873 	for (i = 0, k = 0; i < s->ncols; i++) {
10874 	    sql = dsappend(sql, (k > 0) ? ", " : " SET ");
10875 	    sql = dsappendq(sql, s->dyncols[i].column);
10876 	    sql = dsappend(sql, " = ?");
10877 	    k++;
10878 	}
10879 	sql = dsappend(sql, " WHERE ");
10880 	sql = dsappendq(sql, s->dyncols[s->has_rowid].column);
10881 	sql = dsappend(sql, " = ?");
10882 	if (dserr(sql)) {
10883 	    dsfree(sql);
10884 	    return nomem(s);
10885 	}
10886 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10887 	dbtraceapi(d, "sqlite3_prepare_v2", dsval(sql));
10888 #else
10889 	dbtraceapi(d, "sqlite3_prepare", dsval(sql));
10890 #endif
10891 	do {
10892 	    s3stmt = NULL;
10893 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
10894 	    rc = sqlite3_prepare_v2(d->sqlite, dsval(sql), -1,
10895 				    &s3stmt, &endp);
10896 #else
10897 	    rc = sqlite3_prepare(d->sqlite, dsval(sql), -1,
10898 				 &s3stmt, &endp);
10899 #endif
10900 	    if (rc != SQLITE_OK) {
10901 		if (s3stmt) {
10902 		    sqlite3_finalize(s3stmt);
10903 		    s3stmt = NULL;
10904 		}
10905 	    }
10906 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
10907 	dbtracerc(d, rc, NULL);
10908 	dsfree(sql);
10909 	if (rc != SQLITE_OK) {
10910 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10911 		    sqlite3_errmsg(d->sqlite), rc);
10912 	    if (s3stmt) {
10913 		dbtraceapi(d, "sqlite3_finalize", NULL);
10914 		sqlite3_finalize(s3stmt);
10915 	    }
10916 	    return SQL_ERROR;
10917 	}
10918 	for (row = 0; row < s->rowset_size; row++) {
10919 	    SQLPOINTER *val;
10920 	    sqlite_int64 rowid;
10921 
10922 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10923 		val = (SQLPOINTER)
10924 		    ((char *) s->bkmrkcol.valp + s->bind_type * row);
10925 	    } else {
10926 		val = (SQLPOINTER)
10927 		    ((char *) s->bkmrkcol.valp + s->bkmrkcol.max * row);
10928 	    }
10929 	    if (s->bind_offs) {
10930 		val = (SQLPOINTER) ((char *) val + *s->bind_offs);
10931 	    }
10932 	    if (s->bkmrkcol.lenp) {
10933 		SQLLEN *ival;
10934 
10935 		if (s->bind_type != SQL_BIND_BY_COLUMN) {
10936 		    ival = (SQLLEN *)
10937 			((char *) s->bkmrkcol.lenp + s->bind_type * row);
10938 		} else {
10939 		    ival = &s->bkmrkcol.lenp[row];
10940 		}
10941 		if (s->bind_offs) {
10942 		    ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
10943 		}
10944 		if (*ival != sizeof (sqlite_int64)) {
10945 		    continue;
10946 		}
10947 	    }
10948 	    for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10949 		ret = setposbind(s, s3stmt, i, k, row);
10950 		if (ret != SQL_SUCCESS) {
10951 ustmterr:
10952 		    if (s->row_status0) {
10953 			s->row_status0[row] = SQL_ROW_ERROR;
10954 		    }
10955 		    if (s->row_status) {
10956 			s->row_status[row] = SQL_ROW_ERROR;
10957 		    }
10958 		    dbtraceapi(d, "sqlite3_finalize", NULL);
10959 		    sqlite3_finalize(s3stmt);
10960 		    return ret;
10961 		}
10962 		k++;
10963 	    }
10964 	    rowid = *(sqlite_int64 *) val;
10965 	    sqlite3_bind_int64(s3stmt, k, rowid);
10966 	    if (d->trace) {
10967 		fprintf(d->trace,
10968 #ifdef _WIN32
10969 			"-- parameter %d: %I64d\n",
10970 #else
10971 			"-- parameter %d: %lld\n",
10972 #endif
10973 			k, rowid);
10974 		fflush(d->trace);
10975 	    }
10976 	    rc = sqlite3_step(s3stmt);
10977 	    if (rc != SQLITE_DONE) {
10978 		setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10979 			sqlite3_errmsg(d->sqlite), rc);
10980 		ret = SQL_ERROR;
10981 		goto ustmterr;
10982 	    }
10983 	    if (sqlite3_changes(d->sqlite) > 0) {
10984 		if (s->row_status0) {
10985 		    s->row_status0[row] = SQL_ROW_UPDATED;
10986 		}
10987 		if (s->row_status) {
10988 		    s->row_status[row] = SQL_ROW_UPDATED;
10989 		}
10990 	    }
10991 	    dbtraceapi(d, "sqlite3_reset", NULL);
10992 	    sqlite3_reset(s3stmt);
10993 	}
10994 	dbtraceapi(d, "sqlite3_finalize", NULL);
10995 	sqlite3_finalize(s3stmt);
10996 	return SQL_SUCCESS;
10997     }
10998     setstat(s, -1, "unsupported operation", (*s->ov3) ? "HY000" : "S1000");
10999     return SQL_ERROR;
11000 }
11001 
11002 /**
11003  * Perform bulk operation on HSTMT.
11004  * @param stmt statement handle
11005  * @param oper operation to be performed
11006  * @result ODBC error code
11007  */
11008 
11009 SQLRETURN SQL_API
SQLBulkOperations(SQLHSTMT stmt,SQLSMALLINT oper)11010 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
11011 {
11012     SQLRETURN ret;
11013 
11014     HSTMT_LOCK(stmt);
11015     ret = drvbulkoperations(stmt, oper);
11016     HSTMT_UNLOCK(stmt);
11017     return ret;
11018 }
11019 
11020 
11021 /**
11022  * Function not implemented.
11023  */
11024 
11025 SQLRETURN SQL_API
SQLSetScrollOptions(SQLHSTMT stmt,SQLUSMALLINT concur,SQLLEN rowkeyset,SQLUSMALLINT rowset)11026 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
11027 		    SQLUSMALLINT rowset)
11028 {
11029     SQLRETURN ret;
11030 
11031     HSTMT_LOCK(stmt);
11032     ret = drvunimplstmt(stmt);
11033     HSTMT_UNLOCK(stmt);
11034     return ret;
11035 }
11036 
11037 #define strmak(dst, src, max, lenp) { \
11038     int len = strlen(src); \
11039     int cnt = min(len + 1, max); \
11040     strncpy(dst, src, cnt); \
11041     *lenp = (cnt > len) ? len : cnt; \
11042 }
11043 
11044 /**
11045  * Internal return information about what this ODBC driver supports.
11046  * @param dbc database connection handle
11047  * @param type type of information to be retrieved
11048  * @param val output buffer
11049  * @param valMax length of output buffer
11050  * @param valLen output length
11051  * @result ODBC error code
11052  */
11053 
11054 static SQLRETURN
drvgetinfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)11055 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
11056 	   SQLSMALLINT *valLen)
11057 {
11058     DBC *d;
11059     char dummyc[301];
11060     SQLSMALLINT dummy;
11061 #if defined(_WIN32) || defined(_WIN64)
11062     char pathbuf[301], *drvname;
11063 #else
11064     static char drvname[] = "sqlite3odbc.so";
11065 #endif
11066 
11067     if (dbc == SQL_NULL_HDBC) {
11068 	return SQL_INVALID_HANDLE;
11069     }
11070     d = (DBC *) dbc;
11071     if (valMax) {
11072 	valMax--;
11073     }
11074     if (!valLen) {
11075 	valLen = &dummy;
11076     }
11077     if (!val) {
11078 	val = dummyc;
11079 	valMax = sizeof (dummyc) - 1;
11080     }
11081     switch (type) {
11082     case SQL_MAX_USER_NAME_LEN:
11083 	*((SQLSMALLINT *) val) = 16;
11084 	*valLen = sizeof (SQLSMALLINT);
11085 	break;
11086     case SQL_USER_NAME:
11087 	strmak(val, "", valMax, valLen);
11088 	break;
11089     case SQL_DRIVER_ODBC_VER:
11090 #if 0
11091 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
11092 #else
11093 	strmak(val, "03.00", valMax, valLen);
11094 #endif
11095 	break;
11096     case SQL_ACTIVE_CONNECTIONS:
11097     case SQL_ACTIVE_STATEMENTS:
11098 	*((SQLSMALLINT *) val) = 0;
11099 	*valLen = sizeof (SQLSMALLINT);
11100 	break;
11101 #ifdef SQL_ASYNC_MODE
11102     case SQL_ASYNC_MODE:
11103 	*((SQLUINTEGER *) val) = SQL_AM_NONE;
11104 	*valLen = sizeof (SQLUINTEGER);
11105 	break;
11106 #endif
11107 #ifdef SQL_CREATE_TABLE
11108     case SQL_CREATE_TABLE:
11109 	*((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
11110 				 SQL_CT_COLUMN_DEFAULT |
11111 				 SQL_CT_COLUMN_CONSTRAINT |
11112 				 SQL_CT_CONSTRAINT_NON_DEFERRABLE;
11113 	*valLen = sizeof (SQLUINTEGER);
11114 	break;
11115 #endif
11116 #ifdef SQL_CREATE_VIEW
11117     case SQL_CREATE_VIEW:
11118 	*((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
11119 	*valLen = sizeof (SQLUINTEGER);
11120 	break;
11121 #endif
11122 #ifdef SQL_DDL_INDEX
11123     case SQL_DDL_INDEX:
11124 	*((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
11125 	*valLen = sizeof (SQLUINTEGER);
11126 	break;
11127 #endif
11128 #ifdef SQL_DROP_TABLE
11129     case SQL_DROP_TABLE:
11130 	*((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
11131 	*valLen = sizeof (SQLUINTEGER);
11132 	break;
11133 #endif
11134 #ifdef SQL_DROP_VIEW
11135     case SQL_DROP_VIEW:
11136 	*((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
11137 	*valLen = sizeof (SQLUINTEGER);
11138 	break;
11139 #endif
11140 #ifdef SQL_INDEX_KEYWORDS
11141     case SQL_INDEX_KEYWORDS:
11142 	*((SQLUINTEGER *) val) = SQL_IK_ALL;
11143 	*valLen = sizeof (SQLUINTEGER);
11144 	break;
11145 #endif
11146     case SQL_DATA_SOURCE_NAME:
11147 	strmak(val, d->dsn ? d->dsn : "", valMax, valLen);
11148 	break;
11149     case SQL_DRIVER_NAME:
11150 #if defined(_WIN32) || defined(_WIN64)
11151 	GetModuleFileName(hModule, pathbuf, sizeof (pathbuf));
11152 	drvname = strrchr(pathbuf, '\\');
11153 	if (drvname == NULL) {
11154 	    drvname = strrchr(pathbuf, '/');
11155 	}
11156 	if (drvname == NULL) {
11157 	    drvname = pathbuf;
11158 	} else {
11159 	    drvname++;
11160 	}
11161 #endif
11162 	strmak(val, drvname, valMax, valLen);
11163 	break;
11164     case SQL_DRIVER_VER:
11165 	strmak(val, DRIVER_VER_INFO, valMax, valLen);
11166 	break;
11167     case SQL_FETCH_DIRECTION:
11168 	*((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
11169 	    SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
11170 	*valLen = sizeof (SQLUINTEGER);
11171 	break;
11172     case SQL_ODBC_VER:
11173 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
11174 	break;
11175     case SQL_ODBC_SAG_CLI_CONFORMANCE:
11176 	*((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
11177 	*valLen = sizeof (SQLSMALLINT);
11178 	break;
11179     case SQL_STANDARD_CLI_CONFORMANCE:
11180 	*((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
11181 	*valLen = sizeof (SQLUINTEGER);
11182 	break;
11183     case SQL_SQL_CONFORMANCE:
11184 	*((SQLUINTEGER *) val) = SQL_SC_SQL92_ENTRY;
11185 	*valLen = sizeof (SQLUINTEGER);
11186 	break;
11187     case SQL_SERVER_NAME:
11188     case SQL_DATABASE_NAME:
11189 	strmak(val, d->dbname ? d->dbname : "", valMax, valLen);
11190 	break;
11191     case SQL_SEARCH_PATTERN_ESCAPE:
11192 	strmak(val, "\\", valMax, valLen);
11193 	break;
11194     case SQL_ODBC_SQL_CONFORMANCE:
11195 	*((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
11196 	*valLen = sizeof (SQLSMALLINT);
11197 	break;
11198     case SQL_ODBC_API_CONFORMANCE:
11199 	*((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
11200 	*valLen = sizeof (SQLSMALLINT);
11201 	break;
11202     case SQL_DBMS_NAME:
11203 	strmak(val, "SQLite", valMax, valLen);
11204 	break;
11205     case SQL_DBMS_VER:
11206 	strmak(val, SQLITE_VERSION, valMax, valLen);
11207 	break;
11208     case SQL_COLUMN_ALIAS:
11209     case SQL_NEED_LONG_DATA_LEN:
11210     case SQL_OUTER_JOINS:
11211 	strmak(val, "Y", valMax, valLen);
11212 	break;
11213     case SQL_ROW_UPDATES:
11214     case SQL_ACCESSIBLE_PROCEDURES:
11215     case SQL_PROCEDURES:
11216     case SQL_EXPRESSIONS_IN_ORDERBY:
11217     case SQL_ODBC_SQL_OPT_IEF:
11218     case SQL_LIKE_ESCAPE_CLAUSE:
11219     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
11220     case SQL_ACCESSIBLE_TABLES:
11221     case SQL_MULT_RESULT_SETS:
11222     case SQL_MULTIPLE_ACTIVE_TXN:
11223     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
11224 	strmak(val, "N", valMax, valLen);
11225 	break;
11226 #ifdef SQL_CATALOG_NAME
11227     case SQL_CATALOG_NAME:
11228 #if defined(_WIN32) || defined(_WIN64)
11229 	strmak(val, d->xcelqrx ? "Y" : "N", valMax, valLen);
11230 #else
11231 	strmak(val, "N", valMax, valLen);
11232 #endif
11233 	break;
11234 #endif
11235     case SQL_DATA_SOURCE_READ_ONLY:
11236 	strmak(val, "N", valMax, valLen);
11237 	break;
11238 #ifdef SQL_OJ_CAPABILITIES
11239     case SQL_OJ_CAPABILITIES:
11240 	*((SQLUINTEGER *) val) = SQL_OJ_LEFT;
11241 	*valLen = sizeof (SQLUINTEGER);
11242 	break;
11243 #endif
11244 #ifdef SQL_MAX_IDENTIFIER_LEN
11245     case SQL_MAX_IDENTIFIER_LEN:
11246 	*((SQLUSMALLINT *) val) = 255;
11247 	*valLen = sizeof (SQLUSMALLINT);
11248 	break;
11249 #endif
11250     case SQL_CONCAT_NULL_BEHAVIOR:
11251 	*((SQLSMALLINT *) val) = SQL_CB_NULL;
11252 	*valLen = sizeof (SQLSMALLINT);
11253 	break;
11254     case SQL_CURSOR_COMMIT_BEHAVIOR:
11255     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
11256 	*((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
11257 	*valLen = sizeof (SQLSMALLINT);
11258 	break;
11259 #ifdef SQL_CURSOR_SENSITIVITY
11260     case SQL_CURSOR_SENSITIVITY:
11261 	*((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
11262 	*valLen = sizeof (SQLUINTEGER);
11263 	break;
11264 #endif
11265     case SQL_DEFAULT_TXN_ISOLATION:
11266 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
11267 	*valLen = sizeof (SQLUINTEGER);
11268 	break;
11269 #ifdef SQL_DESCRIBE_PARAMETER
11270     case SQL_DESCRIBE_PARAMETER:
11271 	strmak(val, "Y", valMax, valLen);
11272 	break;
11273 #endif
11274     case SQL_TXN_ISOLATION_OPTION:
11275 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
11276 	*valLen = sizeof (SQLUINTEGER);
11277 	break;
11278     case SQL_IDENTIFIER_CASE:
11279 	*((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
11280 	*valLen = sizeof (SQLSMALLINT);
11281 	break;
11282     case SQL_IDENTIFIER_QUOTE_CHAR:
11283 	strmak(val, "\"", valMax, valLen);
11284 	break;
11285     case SQL_MAX_TABLE_NAME_LEN:
11286     case SQL_MAX_COLUMN_NAME_LEN:
11287 	*((SQLSMALLINT *) val) = 255;
11288 	*valLen = sizeof (SQLSMALLINT);
11289 	break;
11290     case SQL_MAX_CURSOR_NAME_LEN:
11291 	*((SQLSMALLINT *) val) = 255;
11292 	*valLen = sizeof (SQLSMALLINT);
11293 	break;
11294     case SQL_MAX_PROCEDURE_NAME_LEN:
11295 	*((SQLSMALLINT *) val) = 0;
11296 	break;
11297     case SQL_MAX_QUALIFIER_NAME_LEN:
11298     case SQL_MAX_OWNER_NAME_LEN:
11299 	*((SQLSMALLINT *) val) = 255;
11300 	break;
11301     case SQL_OWNER_TERM:
11302 	strmak(val, "", valMax, valLen);
11303 	break;
11304     case SQL_PROCEDURE_TERM:
11305 	strmak(val, "PROCEDURE", valMax, valLen);
11306 	break;
11307     case SQL_QUALIFIER_NAME_SEPARATOR:
11308 	strmak(val, ".", valMax, valLen);
11309 	break;
11310     case SQL_QUALIFIER_TERM:
11311 #if defined(_WIN32) || defined(_WIN64)
11312 	strmak(val, d->xcelqrx ? "catalog" : "", valMax, valLen);
11313 #else
11314 	strmak(val, "", valMax, valLen);
11315 #endif
11316 	break;
11317     case SQL_QUALIFIER_USAGE:
11318 #if defined(_WIN32) || defined(_WIN64)
11319 	*((SQLUINTEGER *) val) = d->xcelqrx ?
11320 	    (SQL_CU_DML_STATEMENTS | SQL_CU_INDEX_DEFINITION |
11321 	     SQL_CU_TABLE_DEFINITION) : 0;
11322 #else
11323 	*((SQLUINTEGER *) val) = 0;
11324 #endif
11325 	*valLen = sizeof (SQLUINTEGER);
11326 	break;
11327     case SQL_SCROLL_CONCURRENCY:
11328 	*((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
11329 	*valLen = sizeof (SQLUINTEGER);
11330 	break;
11331     case SQL_SCROLL_OPTIONS:
11332 	*((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
11333 	*valLen = sizeof (SQLUINTEGER);
11334 	break;
11335     case SQL_TABLE_TERM:
11336 	strmak(val, "TABLE", valMax, valLen);
11337 	break;
11338     case SQL_TXN_CAPABLE:
11339 	*((SQLSMALLINT *) val) = SQL_TC_ALL;
11340 	*valLen = sizeof (SQLSMALLINT);
11341 	break;
11342     case SQL_CONVERT_FUNCTIONS:
11343 	*((SQLUINTEGER *) val) = 0;
11344 	*valLen = sizeof (SQLUINTEGER);
11345        break;
11346     case SQL_SYSTEM_FUNCTIONS:
11347     case SQL_NUMERIC_FUNCTIONS:
11348     case SQL_STRING_FUNCTIONS:
11349     case SQL_TIMEDATE_FUNCTIONS:
11350 	*((SQLUINTEGER *) val) = 0;
11351 	*valLen = sizeof (SQLUINTEGER);
11352 	break;
11353     case SQL_CONVERT_BIGINT:
11354     case SQL_CONVERT_BIT:
11355     case SQL_CONVERT_CHAR:
11356     case SQL_CONVERT_DATE:
11357     case SQL_CONVERT_DECIMAL:
11358     case SQL_CONVERT_DOUBLE:
11359     case SQL_CONVERT_FLOAT:
11360     case SQL_CONVERT_INTEGER:
11361     case SQL_CONVERT_LONGVARCHAR:
11362     case SQL_CONVERT_NUMERIC:
11363     case SQL_CONVERT_REAL:
11364     case SQL_CONVERT_SMALLINT:
11365     case SQL_CONVERT_TIME:
11366     case SQL_CONVERT_TIMESTAMP:
11367     case SQL_CONVERT_TINYINT:
11368     case SQL_CONVERT_VARCHAR:
11369 	*((SQLUINTEGER *) val) =
11370 	    SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
11371 	    SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
11372 	    SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
11373 	    SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
11374 	    SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
11375 	*valLen = sizeof (SQLUINTEGER);
11376 	break;
11377     case SQL_CONVERT_BINARY:
11378     case SQL_CONVERT_VARBINARY:
11379     case SQL_CONVERT_LONGVARBINARY:
11380 	*((SQLUINTEGER *) val) = 0;
11381 	*valLen = sizeof (SQLUINTEGER);
11382 	break;
11383     case SQL_POSITIONED_STATEMENTS:
11384 	*((SQLUINTEGER *) val) = 0;
11385 	*valLen = sizeof (SQLUINTEGER);
11386 	break;
11387     case SQL_LOCK_TYPES:
11388 	*((SQLUINTEGER *) val) = SQL_LCK_NO_CHANGE;
11389 	*valLen = sizeof (SQLUINTEGER);
11390 	break;
11391     case SQL_BOOKMARK_PERSISTENCE:
11392 	*((SQLUINTEGER *) val) = SQL_BP_SCROLL;
11393 	*valLen = sizeof (SQLUINTEGER);
11394 	break;
11395     case SQL_UNION:
11396 	*((SQLUINTEGER *) val) = SQL_U_UNION | SQL_U_UNION_ALL;
11397 	*valLen = sizeof (SQLUINTEGER);
11398 	break;
11399     case SQL_OWNER_USAGE:
11400     case SQL_SUBQUERIES:
11401     case SQL_TIMEDATE_ADD_INTERVALS:
11402     case SQL_TIMEDATE_DIFF_INTERVALS:
11403 	*((SQLUINTEGER *) val) = 0;
11404 	*valLen = sizeof (SQLUINTEGER);
11405 	break;
11406     case SQL_QUOTED_IDENTIFIER_CASE:
11407 	*((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
11408 	*valLen = sizeof (SQLUSMALLINT);
11409 	break;
11410     case SQL_POS_OPERATIONS:
11411 	*((SQLUINTEGER *) val) = SQL_POS_POSITION | SQL_POS_UPDATE |
11412 	    SQL_POS_DELETE | SQL_POS_ADD | SQL_POS_REFRESH;
11413 	*valLen = sizeof (SQLUINTEGER);
11414 	break;
11415     case SQL_ALTER_TABLE:
11416 	*((SQLUINTEGER *) val) = 0;
11417 	*valLen = sizeof (SQLUINTEGER);
11418 	break;
11419     case SQL_CORRELATION_NAME:
11420 	*((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
11421 	*valLen = sizeof (SQLSMALLINT);
11422 	break;
11423     case SQL_NON_NULLABLE_COLUMNS:
11424 	*((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
11425 	*valLen = sizeof (SQLSMALLINT);
11426 	break;
11427     case SQL_NULL_COLLATION:
11428 	*((SQLSMALLINT *) val) = SQL_NC_START;
11429 	*valLen = sizeof (SQLSMALLINT);
11430 	break;
11431     case SQL_MAX_COLUMNS_IN_GROUP_BY:
11432     case SQL_MAX_COLUMNS_IN_ORDER_BY:
11433     case SQL_MAX_COLUMNS_IN_SELECT:
11434     case SQL_MAX_COLUMNS_IN_TABLE:
11435     case SQL_MAX_ROW_SIZE:
11436     case SQL_MAX_TABLES_IN_SELECT:
11437 	*((SQLSMALLINT *) val) = 0;
11438 	*valLen = sizeof (SQLSMALLINT);
11439 	break;
11440     case SQL_MAX_BINARY_LITERAL_LEN:
11441     case SQL_MAX_CHAR_LITERAL_LEN:
11442 	*((SQLUINTEGER *) val) = 0;
11443 	*valLen = sizeof (SQLUINTEGER);
11444 	break;
11445     case SQL_MAX_COLUMNS_IN_INDEX:
11446 	*((SQLSMALLINT *) val) = 0;
11447 	*valLen = sizeof (SQLSMALLINT);
11448 	break;
11449     case SQL_MAX_INDEX_SIZE:
11450 	*((SQLUINTEGER *) val) = 0;
11451 	*valLen = sizeof (SQLUINTEGER);
11452 	break;
11453 #ifdef SQL_MAX_IDENTIFIER_LENGTH
11454     case SQL_MAX_IDENTIFIER_LENGTH:
11455 	*((SQLUINTEGER *) val) = 255;
11456 	*valLen = sizeof (SQLUINTEGER);
11457 	break;
11458 #endif
11459     case SQL_MAX_STATEMENT_LEN:
11460 	*((SQLUINTEGER *) val) = 16384;
11461 	*valLen = sizeof (SQLUINTEGER);
11462 	break;
11463     case SQL_QUALIFIER_LOCATION:
11464 	*((SQLSMALLINT *) val) = SQL_QL_START;
11465 	*valLen = sizeof (SQLSMALLINT);
11466 	break;
11467     case SQL_GETDATA_EXTENSIONS:
11468 	*((SQLUINTEGER *) val) =
11469 	    SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
11470 	*valLen = sizeof (SQLUINTEGER);
11471 	break;
11472     case SQL_STATIC_SENSITIVITY:
11473 	*((SQLUINTEGER *) val) = 0;
11474 	*valLen = sizeof (SQLUINTEGER);
11475 	break;
11476     case SQL_FILE_USAGE:
11477 #if defined(_WIN32) || defined(_WIN64)
11478 	*((SQLSMALLINT *) val) =
11479 	    d->xcelqrx ? SQL_FILE_CATALOG : SQL_FILE_NOT_SUPPORTED;
11480 #else
11481 	*((SQLSMALLINT *) val) = SQL_FILE_NOT_SUPPORTED;
11482 #endif
11483 	*valLen = sizeof (SQLSMALLINT);
11484 	break;
11485     case SQL_GROUP_BY:
11486 	*((SQLSMALLINT *) val) = SQL_GB_GROUP_BY_EQUALS_SELECT;
11487 	*valLen = sizeof (SQLSMALLINT);
11488 	break;
11489     case SQL_KEYWORDS:
11490 	strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
11491 	       "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
11492 	       valMax, valLen);
11493 	break;
11494     case SQL_SPECIAL_CHARACTERS:
11495 #ifdef SQL_COLLATION_SEQ
11496     case SQL_COLLATION_SEQ:
11497 #endif
11498 	strmak(val, "", valMax, valLen);
11499 	break;
11500     case SQL_BATCH_SUPPORT:
11501     case SQL_BATCH_ROW_COUNT:
11502     case SQL_PARAM_ARRAY_ROW_COUNTS:
11503 	*((SQLUINTEGER *) val) = 0;
11504 	*valLen = sizeof (SQLUINTEGER);
11505 	break;
11506     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
11507 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
11508 	*valLen = sizeof (SQLUINTEGER);
11509 	break;
11510     case SQL_STATIC_CURSOR_ATTRIBUTES1:
11511 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
11512 	    SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK | SQL_CA1_POS_POSITION |
11513 	    SQL_CA1_POS_DELETE | SQL_CA1_POS_UPDATE | SQL_CA1_POS_REFRESH |
11514 	    SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_BULK_ADD |
11515 	    SQL_CA1_BULK_UPDATE_BY_BOOKMARK | SQL_CA1_BULK_DELETE_BY_BOOKMARK;
11516 	*valLen = sizeof (SQLUINTEGER);
11517 	break;
11518     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
11519     case SQL_STATIC_CURSOR_ATTRIBUTES2:
11520 	*((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
11521 	    SQL_CA2_LOCK_CONCURRENCY;
11522 	*valLen = sizeof (SQLUINTEGER);
11523 	break;
11524     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
11525     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
11526     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
11527     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
11528 	*((SQLUINTEGER *) val) = 0;
11529 	*valLen = sizeof (SQLUINTEGER);
11530 	break;
11531     case SQL_ODBC_INTERFACE_CONFORMANCE:
11532 	*((SQLUINTEGER *) val) = SQL_OIC_CORE;
11533 	*valLen = sizeof (SQLUINTEGER);
11534 	break;
11535     default:
11536 	setstatd(d, -1, "unsupported info option %d",
11537 		 (*d->ov3) ? "HYC00" : "S1C00", type);
11538 	return SQL_ERROR;
11539     }
11540     return SQL_SUCCESS;
11541 }
11542 
11543 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
11544 /**
11545  * Return information about what this ODBC driver supports.
11546  * @param dbc database connection handle
11547  * @param type type of information to be retrieved
11548  * @param val output buffer
11549  * @param valMax length of output buffer
11550  * @param valLen output length
11551  * @result ODBC error code
11552  */
11553 
11554 SQLRETURN SQL_API
SQLGetInfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)11555 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
11556 	   SQLSMALLINT *valLen)
11557 {
11558     SQLRETURN ret;
11559 
11560     HDBC_LOCK(dbc);
11561     ret = drvgetinfo(dbc, type, val, valMax, valLen);
11562     HDBC_UNLOCK(dbc);
11563     return ret;
11564 }
11565 #endif
11566 
11567 #ifdef WINTERFACE
11568 /**
11569  * Return information about what this ODBC driver supports.
11570  * @param dbc database connection handle
11571  * @param type type of information to be retrieved
11572  * @param val output buffer
11573  * @param valMax length of output buffer
11574  * @param valLen output length
11575  * @result ODBC error code
11576  */
11577 
11578 SQLRETURN SQL_API
SQLGetInfoW(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)11579 SQLGetInfoW(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
11580 	    SQLSMALLINT *valLen)
11581 {
11582     SQLRETURN ret;
11583     SQLSMALLINT len = 0;
11584 
11585     HDBC_LOCK(dbc);
11586     ret = drvgetinfo(dbc, type, val, valMax, &len);
11587     HDBC_UNLOCK(dbc);
11588     if (ret == SQL_SUCCESS) {
11589 	SQLWCHAR *v = NULL;
11590 
11591 	switch (type) {
11592 	case SQL_USER_NAME:
11593 	case SQL_DRIVER_ODBC_VER:
11594 	case SQL_DATA_SOURCE_NAME:
11595 	case SQL_DRIVER_NAME:
11596 	case SQL_DRIVER_VER:
11597 	case SQL_ODBC_VER:
11598 	case SQL_SERVER_NAME:
11599 	case SQL_DATABASE_NAME:
11600 	case SQL_SEARCH_PATTERN_ESCAPE:
11601 	case SQL_DBMS_NAME:
11602 	case SQL_DBMS_VER:
11603 	case SQL_NEED_LONG_DATA_LEN:
11604 	case SQL_ROW_UPDATES:
11605 	case SQL_ACCESSIBLE_PROCEDURES:
11606 	case SQL_PROCEDURES:
11607 	case SQL_EXPRESSIONS_IN_ORDERBY:
11608 	case SQL_ODBC_SQL_OPT_IEF:
11609 	case SQL_LIKE_ESCAPE_CLAUSE:
11610 	case SQL_ORDER_BY_COLUMNS_IN_SELECT:
11611 	case SQL_OUTER_JOINS:
11612 	case SQL_COLUMN_ALIAS:
11613 	case SQL_ACCESSIBLE_TABLES:
11614 	case SQL_MULT_RESULT_SETS:
11615 	case SQL_MULTIPLE_ACTIVE_TXN:
11616 	case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
11617 	case SQL_DATA_SOURCE_READ_ONLY:
11618 #ifdef SQL_DESCRIBE_PARAMETER
11619 	case SQL_DESCRIBE_PARAMETER:
11620 #endif
11621 	case SQL_IDENTIFIER_QUOTE_CHAR:
11622 	case SQL_OWNER_TERM:
11623 	case SQL_PROCEDURE_TERM:
11624 	case SQL_QUALIFIER_NAME_SEPARATOR:
11625 	case SQL_QUALIFIER_TERM:
11626 	case SQL_TABLE_TERM:
11627 	case SQL_KEYWORDS:
11628 	case SQL_SPECIAL_CHARACTERS:
11629 #ifdef SQL_CATALOG_NAME
11630 	case SQL_CATALOG_NAME:
11631 #endif
11632 #ifdef SQL_COLLATION_SEQ
11633 	case SQL_COLLATION_SEQ:
11634 #endif
11635 	    if (val) {
11636 		if (len > 0) {
11637 		    v = uc_from_utf((SQLCHAR *) val, len);
11638 		    if (v) {
11639 			int vmax = valMax / sizeof (SQLWCHAR);
11640 
11641 			uc_strncpy(val, v, vmax);
11642 			if (len < vmax) {
11643 			    len = min(vmax, uc_strlen(v));
11644 			    v[len] = 0;
11645 			} else {
11646 			    len = vmax;
11647 			}
11648 			uc_free(v);
11649 			len *= sizeof (SQLWCHAR);
11650 		    } else {
11651 			len = 0;
11652 		    }
11653 		}
11654 		if (len <= 0) {
11655 		    len = 0;
11656 		    if (valMax >= sizeof (SQLWCHAR)) {
11657 			*((SQLWCHAR *)val) = 0;
11658 		    }
11659 		}
11660 	    } else {
11661 		len *= sizeof (SQLWCHAR);
11662 	    }
11663 	    break;
11664 	}
11665 	if (valLen) {
11666 	    *valLen = len;
11667 	}
11668     }
11669     return ret;
11670 }
11671 #endif
11672 
11673 /**
11674  * Return information about supported ODBC API functions.
11675  * @param dbc database connection handle
11676  * @param func function code to be retrieved
11677  * @param flags output indicator
11678  * @result ODBC error code
11679  */
11680 
11681 SQLRETURN SQL_API
SQLGetFunctions(SQLHDBC dbc,SQLUSMALLINT func,SQLUSMALLINT * flags)11682 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
11683 		SQLUSMALLINT *flags)
11684 {
11685     int i;
11686     SQLUSMALLINT exists[100];
11687 
11688     if (dbc == SQL_NULL_HDBC) {
11689 	return SQL_INVALID_HANDLE;
11690     }
11691     for (i = 0; i < array_size(exists); i++) {
11692 	exists[i] = SQL_FALSE;
11693     }
11694     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
11695     exists[SQL_API_SQLFETCH] = SQL_TRUE;
11696     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
11697     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
11698     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
11699     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
11700     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
11701     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
11702     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
11703     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
11704     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
11705     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
11706     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
11707     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
11708     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
11709     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
11710     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
11711     exists[SQL_API_SQLSETCURSORNAME] = SQL_FALSE;
11712     exists[SQL_API_SQLERROR] = SQL_TRUE;
11713     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
11714     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
11715     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
11716     exists[SQL_API_SQLBULKOPERATIONS] = SQL_TRUE;
11717     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
11718     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
11719     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
11720     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
11721     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
11722     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
11723     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
11724     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
11725     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
11726     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
11727     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
11728     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
11729     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
11730     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
11731     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
11732     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
11733     exists[SQL_API_SQLTABLES] = SQL_TRUE;
11734     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
11735     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
11736     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
11737     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
11738     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
11739     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
11740     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
11741     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
11742     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
11743     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
11744     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
11745     exists[SQL_API_SQLSETPOS] = SQL_TRUE;
11746     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
11747     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
11748     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
11749     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_TRUE;
11750     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
11751     if (func == SQL_API_ALL_FUNCTIONS) {
11752 	memcpy(flags, exists, sizeof (exists));
11753     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
11754 	int i;
11755 #define SET_EXISTS(x) \
11756 	flags[(x) >> 4] |= (1 << ((x) & 0xF))
11757 #define CLR_EXISTS(x) \
11758 	flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
11759 
11760 	memset(flags, 0,
11761 	       sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
11762 	for (i = 0; i < array_size(exists); i++) {
11763 	    if (exists[i]) {
11764 		flags[i >> 4] |= (1 << (i & 0xF));
11765 	    }
11766 	}
11767 	SET_EXISTS(SQL_API_SQLALLOCHANDLE);
11768 	SET_EXISTS(SQL_API_SQLFREEHANDLE);
11769 	SET_EXISTS(SQL_API_SQLGETSTMTATTR);
11770 	SET_EXISTS(SQL_API_SQLSETSTMTATTR);
11771 	SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
11772 	SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
11773 	SET_EXISTS(SQL_API_SQLGETENVATTR);
11774 	SET_EXISTS(SQL_API_SQLSETENVATTR);
11775 	SET_EXISTS(SQL_API_SQLCLOSECURSOR);
11776 	SET_EXISTS(SQL_API_SQLBINDPARAM);
11777 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
11778 	/*
11779 	 * Some unixODBC versions have problems with
11780 	 * SQLError() vs. SQLGetDiagRec() with loss
11781 	 * of error/warning messages.
11782 	 */
11783 	SET_EXISTS(SQL_API_SQLGETDIAGREC);
11784 #endif
11785 	SET_EXISTS(SQL_API_SQLGETDIAGFIELD);
11786 	SET_EXISTS(SQL_API_SQLFETCHSCROLL);
11787 	SET_EXISTS(SQL_API_SQLENDTRAN);
11788     } else {
11789 	if (func < array_size(exists)) {
11790 	    *flags = exists[func];
11791 	} else {
11792 	    switch (func) {
11793 	    case SQL_API_SQLALLOCHANDLE:
11794 	    case SQL_API_SQLFREEHANDLE:
11795 	    case SQL_API_SQLGETSTMTATTR:
11796 	    case SQL_API_SQLSETSTMTATTR:
11797 	    case SQL_API_SQLGETCONNECTATTR:
11798 	    case SQL_API_SQLSETCONNECTATTR:
11799 	    case SQL_API_SQLGETENVATTR:
11800 	    case SQL_API_SQLSETENVATTR:
11801 	    case SQL_API_SQLCLOSECURSOR:
11802 	    case SQL_API_SQLBINDPARAM:
11803 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
11804 	    /*
11805 	     * Some unixODBC versions have problems with
11806 	     * SQLError() vs. SQLGetDiagRec() with loss
11807 	     * of error/warning messages.
11808 	     */
11809 	    case SQL_API_SQLGETDIAGREC:
11810 #endif
11811 	    case SQL_API_SQLGETDIAGFIELD:
11812 	    case SQL_API_SQLFETCHSCROLL:
11813 	    case SQL_API_SQLENDTRAN:
11814 		*flags = SQL_TRUE;
11815 		break;
11816 	    default:
11817 		*flags = SQL_FALSE;
11818 	    }
11819 	}
11820     }
11821     return SQL_SUCCESS;
11822 }
11823 
11824 /**
11825  * Internal allocate HENV.
11826  * @param env pointer to environment handle
11827  * @result ODBC error code
11828  */
11829 
11830 static SQLRETURN
drvallocenv(SQLHENV * env)11831 drvallocenv(SQLHENV *env)
11832 {
11833     ENV *e;
11834 
11835     if (env == NULL) {
11836 	return SQL_INVALID_HANDLE;
11837     }
11838     e = (ENV *) xmalloc(sizeof (ENV));
11839     if (e == NULL) {
11840 	*env = SQL_NULL_HENV;
11841 	return SQL_ERROR;
11842     }
11843     e->magic = ENV_MAGIC;
11844     e->ov3 = 0;
11845     e->pool = 0;
11846 #if defined(_WIN32) || defined(_WIN64)
11847     InitializeCriticalSection(&e->cs);
11848 #else
11849 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
11850     nvfs_init();
11851 #endif
11852 #endif
11853     e->dbcs = NULL;
11854     *env = (SQLHENV) e;
11855     return SQL_SUCCESS;
11856 }
11857 
11858 /**
11859  * Allocate HENV.
11860  * @param env pointer to environment handle
11861  * @result ODBC error code
11862  */
11863 
11864 SQLRETURN SQL_API
SQLAllocEnv(SQLHENV * env)11865 SQLAllocEnv(SQLHENV *env)
11866 {
11867     return drvallocenv(env);
11868 }
11869 
11870 /**
11871  * Internal free HENV.
11872  * @param env environment handle
11873  * @result ODBC error code
11874  */
11875 
11876 static SQLRETURN
drvfreeenv(SQLHENV env)11877 drvfreeenv(SQLHENV env)
11878 {
11879     ENV *e;
11880 
11881     if (env == SQL_NULL_HENV) {
11882 	return SQL_INVALID_HANDLE;
11883     }
11884     e = (ENV *) env;
11885     if (e->magic != ENV_MAGIC) {
11886 	return SQL_SUCCESS;
11887     }
11888 #if defined(_WIN32) || defined(_WIN64)
11889     EnterCriticalSection(&e->cs);
11890 #endif
11891     if (e->dbcs) {
11892 #if defined(_WIN32) || defined(_WIN64)
11893 	LeaveCriticalSection(&e->cs);
11894 #endif
11895 	return SQL_ERROR;
11896     }
11897     e->magic = DEAD_MAGIC;
11898 #if defined(_WIN32) || defined(_WIN64)
11899     LeaveCriticalSection(&e->cs);
11900     DeleteCriticalSection(&e->cs);
11901 #endif
11902     xfree(e);
11903     return SQL_SUCCESS;
11904 }
11905 
11906 /**
11907  * Free HENV.
11908  * @param env environment handle
11909  * @result ODBC error code
11910  */
11911 
11912 SQLRETURN SQL_API
SQLFreeEnv(SQLHENV env)11913 SQLFreeEnv(SQLHENV env)
11914 {
11915     return drvfreeenv(env);
11916 }
11917 
11918 /**
11919  * Internal allocate HDBC.
11920  * @param env environment handle
11921  * @param dbc pointer to database connection handle
11922  * @result ODBC error code
11923  */
11924 
11925 static SQLRETURN
drvallocconnect(SQLHENV env,SQLHDBC * dbc)11926 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
11927 {
11928     DBC *d;
11929     ENV *e;
11930     const char *verstr;
11931     int maj = 0, min = 0, lev = 0;
11932 
11933     if (dbc == NULL) {
11934 	return SQL_ERROR;
11935     }
11936     d = (DBC *) xmalloc(sizeof (DBC));
11937     if (d == NULL) {
11938 	*dbc = SQL_NULL_HDBC;
11939 	return SQL_ERROR;
11940     }
11941     memset(d, 0, sizeof (DBC));
11942     d->curtype = SQL_CURSOR_STATIC;
11943     d->ov3 = &d->ov3val;
11944     verstr = sqlite3_libversion();
11945     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
11946     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
11947     e = (ENV *) env;
11948 #if defined(_WIN32) || defined(_WIN64)
11949     if (e->magic == ENV_MAGIC) {
11950 	EnterCriticalSection(&e->cs);
11951     }
11952 #endif
11953     if (e->magic == ENV_MAGIC) {
11954 	DBC *n, *p;
11955 
11956 	d->env = e;
11957 	d->ov3 = &e->ov3;
11958 	p = NULL;
11959 	n = e->dbcs;
11960 	while (n) {
11961 	    p = n;
11962 	    n = n->next;
11963 	}
11964 	if (p) {
11965 	    p->next = d;
11966 	} else {
11967 	    e->dbcs = d;
11968 	}
11969     }
11970 #if defined(_WIN32) || defined(_WIN64)
11971     InitializeCriticalSection(&d->cs);
11972     d->owner = 0;
11973     if (e->magic == ENV_MAGIC) {
11974 	LeaveCriticalSection(&e->cs);
11975     }
11976     d->oemcp = 1;
11977 #endif
11978     d->autocommit = 1;
11979     d->magic = DBC_MAGIC;
11980     *dbc = (SQLHDBC) d;
11981     drvgetgpps(d);
11982     return SQL_SUCCESS;
11983 }
11984 
11985 /**
11986  * Allocate HDBC.
11987  * @param env environment handle
11988  * @param dbc pointer to database connection handle
11989  * @result ODBC error code
11990  */
11991 
11992 SQLRETURN SQL_API
SQLAllocConnect(SQLHENV env,SQLHDBC * dbc)11993 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
11994 {
11995     return drvallocconnect(env, dbc);
11996 }
11997 
11998 /**
11999  * Internal free connection (HDBC).
12000  * @param dbc database connection handle
12001  * @result ODBC error code
12002  */
12003 
12004 static SQLRETURN
drvfreeconnect(SQLHDBC dbc)12005 drvfreeconnect(SQLHDBC dbc)
12006 {
12007     DBC *d;
12008     ENV *e;
12009     SQLRETURN ret = SQL_ERROR;
12010 
12011     if (dbc == SQL_NULL_HDBC) {
12012 	return SQL_INVALID_HANDLE;
12013     }
12014     d = (DBC *) dbc;
12015     if (d->magic != DBC_MAGIC) {
12016 	return SQL_INVALID_HANDLE;
12017     }
12018     e = d->env;
12019     if (e && e->magic == ENV_MAGIC) {
12020 #if defined(_WIN32) || defined(_WIN64)
12021 	EnterCriticalSection(&e->cs);
12022 #endif
12023     } else {
12024 	e = NULL;
12025     }
12026     HDBC_LOCK(dbc);
12027     if (d->sqlite) {
12028 	setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
12029 	HDBC_UNLOCK(dbc);
12030 	goto done;
12031     }
12032     while (d->stmt) {
12033 	freestmt((HSTMT) d->stmt);
12034     }
12035     if (e && e->magic == ENV_MAGIC) {
12036 	DBC *n, *p;
12037 
12038 	p = NULL;
12039 	n = e->dbcs;
12040 	while (n) {
12041 	    if (n == d) {
12042 		break;
12043 	    }
12044 	    p = n;
12045 	    n = n->next;
12046 	}
12047 	if (n) {
12048 	    if (p) {
12049 		p->next = d->next;
12050 	    } else {
12051 		e->dbcs = d->next;
12052 	    }
12053 	}
12054     }
12055     drvrelgpps(d);
12056     d->magic = DEAD_MAGIC;
12057     if (d->trace) {
12058 	fclose(d->trace);
12059     }
12060 #if defined(_WIN32) || defined(_WIN64)
12061     d->owner = 0;
12062     LeaveCriticalSection(&d->cs);
12063     DeleteCriticalSection(&d->cs);
12064 #endif
12065     xfree(d);
12066     ret = SQL_SUCCESS;
12067 done:
12068 #if defined(_WIN32) || defined(_WIN64)
12069     if (e) {
12070 	LeaveCriticalSection(&e->cs);
12071     }
12072 #endif
12073     return ret;
12074 }
12075 
12076 /**
12077  * Free connection (HDBC).
12078  * @param dbc database connection handle
12079  * @result ODBC error code
12080  */
12081 
12082 SQLRETURN SQL_API
SQLFreeConnect(SQLHDBC dbc)12083 SQLFreeConnect(SQLHDBC dbc)
12084 {
12085     return drvfreeconnect(dbc);
12086 }
12087 
12088 /**
12089  * Internal get connect attribute of HDBC.
12090  * @param dbc database connection handle
12091  * @param attr option to be retrieved
12092  * @param val output buffer
12093  * @param bufmax size of output buffer
12094  * @param buflen output length
12095  * @result ODBC error code
12096  */
12097 
12098 static SQLRETURN
drvgetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)12099 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
12100 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
12101 {
12102     DBC *d;
12103     SQLINTEGER dummy;
12104 
12105     if (dbc == SQL_NULL_HDBC) {
12106 	return SQL_INVALID_HANDLE;
12107     }
12108     d = (DBC *) dbc;
12109     if (!val) {
12110 	val = (SQLPOINTER) &dummy;
12111     }
12112     if (!buflen) {
12113 	buflen = &dummy;
12114     }
12115     switch (attr) {
12116     case SQL_ATTR_CONNECTION_DEAD:
12117 	*((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
12118 	*buflen = sizeof (SQLINTEGER);
12119 	break;
12120     case SQL_ATTR_ACCESS_MODE:
12121 	*((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
12122 	*buflen = sizeof (SQLINTEGER);
12123 	break;
12124     case SQL_ATTR_AUTOCOMMIT:
12125 	*((SQLINTEGER *) val) =
12126 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
12127 	*buflen = sizeof (SQLINTEGER);
12128 	break;
12129     case SQL_ATTR_LOGIN_TIMEOUT:
12130 	*((SQLINTEGER *) val) = 100;
12131 	*buflen = sizeof (SQLINTEGER);
12132 	break;
12133     case SQL_ATTR_ODBC_CURSORS:
12134 	*((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
12135 	*buflen = sizeof (SQLINTEGER);
12136 	break;
12137     case SQL_ATTR_PACKET_SIZE:
12138 	*((SQLINTEGER *) val) = 16384;
12139 	*buflen = sizeof (SQLINTEGER);
12140 	break;
12141     case SQL_ATTR_TXN_ISOLATION:
12142 	*((SQLINTEGER *) val) = SQL_TXN_SERIALIZABLE;
12143 	*buflen = sizeof (SQLINTEGER);
12144 	break;
12145     case SQL_ATTR_TRACEFILE:
12146     case SQL_ATTR_TRANSLATE_LIB:
12147 	*((SQLCHAR *) val) = 0;
12148 	*buflen = 0;
12149 	break;
12150     case SQL_ATTR_CURRENT_CATALOG:
12151 #if defined(_WIN32) || defined(_WIN64)
12152 	if (d->xcelqrx) {
12153 	    if ((bufmax > 4) && (val != (SQLPOINTER) &dummy)) {
12154 		strcpy((char *) val, "main");
12155 		*buflen = 4;
12156 		break;
12157 	    }
12158 	}
12159 #endif
12160 	*((SQLCHAR *) val) = 0;
12161 	*buflen = 0;
12162 	break;
12163     case SQL_ATTR_TRACE:
12164     case SQL_ATTR_QUIET_MODE:
12165     case SQL_ATTR_TRANSLATE_OPTION:
12166     case SQL_ATTR_KEYSET_SIZE:
12167     case SQL_ATTR_QUERY_TIMEOUT:
12168 	*((SQLINTEGER *) val) = 0;
12169 	*buflen = sizeof (SQLINTEGER);
12170 	break;
12171     case SQL_ATTR_PARAM_BIND_TYPE:
12172 	*((SQLULEN *) val) = SQL_PARAM_BIND_BY_COLUMN;
12173 	*buflen = sizeof (SQLUINTEGER);
12174 	break;
12175     case SQL_ATTR_ROW_BIND_TYPE:
12176 	*((SQLULEN *) val) = SQL_BIND_BY_COLUMN;
12177 	*buflen = sizeof (SQLULEN);
12178 	break;
12179     case SQL_ATTR_USE_BOOKMARKS:
12180 	*((SQLINTEGER *) val) = SQL_UB_OFF;
12181 	*buflen = sizeof (SQLINTEGER);
12182 	break;
12183     case SQL_ATTR_ASYNC_ENABLE:
12184 	*((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
12185 	*buflen = sizeof (SQLINTEGER);
12186 	break;
12187     case SQL_ATTR_NOSCAN:
12188 	*((SQLINTEGER *) val) = SQL_NOSCAN_ON;
12189 	*buflen = sizeof (SQLINTEGER);
12190 	break;
12191     case SQL_ATTR_CONCURRENCY:
12192 	*((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
12193 	*buflen = sizeof (SQLINTEGER);
12194 	break;
12195 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
12196     case SQL_ATTR_CURSOR_SENSITIVITY:
12197 	*((SQLINTEGER *) val) = SQL_UNSPECIFIED;
12198 	*buflen = sizeof (SQLINTEGER);
12199 	break;
12200 #endif
12201     case SQL_ATTR_SIMULATE_CURSOR:
12202 	*((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
12203 	*buflen = sizeof (SQLINTEGER);
12204 	break;
12205     case SQL_ATTR_MAX_ROWS:
12206 	*((SQLINTEGER *) val) = 0;
12207 	*buflen = sizeof (SQLINTEGER);
12208     case SQL_ATTR_MAX_LENGTH:
12209 	*((SQLINTEGER *) val) = 1000000000;
12210 	*buflen = sizeof (SQLINTEGER);
12211 	break;
12212     case SQL_ATTR_CURSOR_TYPE:
12213 	*((SQLINTEGER *) val) = d->curtype;
12214 	*buflen = sizeof (SQLINTEGER);
12215 	break;
12216     case SQL_ATTR_RETRIEVE_DATA:
12217 	*((SQLINTEGER *) val) = SQL_RD_ON;
12218 	*buflen = sizeof (SQLINTEGER);
12219 	break;
12220 #ifdef SQL_ATTR_METADATA_ID
12221     case SQL_ATTR_METADATA_ID:
12222 	*((SQLULEN *) val) = SQL_FALSE;
12223 	return SQL_SUCCESS;
12224 #endif
12225     default:
12226 	*((SQLINTEGER *) val) = 0;
12227 	*buflen = sizeof (SQLINTEGER);
12228 	setstatd(d, -1, "unsupported connect attribute %d",
12229 		 (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
12230 	return SQL_ERROR;
12231     }
12232     return SQL_SUCCESS;
12233 }
12234 
12235 #ifndef WINTERFACE
12236 /**
12237  * Get connect attribute of HDBC.
12238  * @param dbc database connection handle
12239  * @param attr option to be retrieved
12240  * @param val output buffer
12241  * @param bufmax size of output buffer
12242  * @param buflen output length
12243  * @result ODBC error code
12244  */
12245 
12246 SQLRETURN SQL_API
SQLGetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)12247 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
12248 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
12249 {
12250     SQLRETURN ret;
12251 
12252     HDBC_LOCK(dbc);
12253     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
12254     HDBC_UNLOCK(dbc);
12255     return ret;
12256 }
12257 #endif
12258 
12259 #ifdef WINTERFACE
12260 /**
12261  * Get connect attribute of HDBC (UNICODE version).
12262  * @param dbc database connection handle
12263  * @param attr option to be retrieved
12264  * @param val output buffer
12265  * @param bufmax size of output buffer
12266  * @param buflen output length
12267  * @result ODBC error code
12268  */
12269 
12270 SQLRETURN SQL_API
SQLGetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)12271 SQLGetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
12272 		   SQLINTEGER bufmax, SQLINTEGER *buflen)
12273 {
12274     SQLRETURN ret;
12275     SQLINTEGER len = 0;
12276 
12277     HDBC_LOCK(dbc);
12278     ret = drvgetconnectattr(dbc, attr, val, bufmax, &len);
12279     if (ret == SQL_SUCCESS) {
12280 	SQLWCHAR *v = NULL;
12281 
12282 	switch (attr) {
12283 	case SQL_ATTR_TRACEFILE:
12284 	case SQL_ATTR_CURRENT_CATALOG:
12285 	case SQL_ATTR_TRANSLATE_LIB:
12286 	    if (val) {
12287 		if (len > 0) {
12288 		    v = uc_from_utf((SQLCHAR *) val, len);
12289 		    if (v) {
12290 			int vmax = bufmax / sizeof (SQLWCHAR);
12291 
12292 			uc_strncpy(val, v, vmax);
12293 			if (len < vmax) {
12294 			    len = min(vmax, uc_strlen(v));
12295 			    v[len] = 0;
12296 			} else {
12297 			    len = vmax;
12298 			}
12299 			uc_free(v);
12300 			len *= sizeof (SQLWCHAR);
12301 		    } else {
12302 			len = 0;
12303 		    }
12304 		}
12305 		if (len <= 0) {
12306 		    len = 0;
12307 		    if (bufmax >= sizeof (SQLWCHAR)) {
12308 			*((SQLWCHAR *)val) = 0;
12309 		    }
12310 		}
12311 	    } else {
12312 		len *= sizeof (SQLWCHAR);
12313 	    }
12314 	    break;
12315 	}
12316 	if (buflen) {
12317 	    *buflen = len;
12318 	}
12319     }
12320     HDBC_UNLOCK(dbc);
12321     return ret;
12322 }
12323 #endif
12324 
12325 /**
12326  * Internal set connect attribute of HDBC.
12327  * @param dbc database connection handle
12328  * @param attr option to be set
12329  * @param val option value
12330  * @param len size of option
12331  * @result ODBC error code
12332  */
12333 
12334 static SQLRETURN
drvsetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)12335 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
12336 		  SQLINTEGER len)
12337 {
12338     DBC *d;
12339 
12340     if (dbc == SQL_NULL_HDBC) {
12341 	return SQL_INVALID_HANDLE;
12342     }
12343     d = (DBC *) dbc;
12344     switch (attr) {
12345     case SQL_AUTOCOMMIT:
12346 	d->autocommit = val == (SQLPOINTER) SQL_AUTOCOMMIT_ON;
12347 	if (d->autocommit && d->intrans) {
12348 	    return endtran(d, SQL_COMMIT, 1);
12349 	} else if (!d->autocommit) {
12350 	    s3stmt_end(d->cur_s3stmt);
12351 	}
12352 	break;
12353 	return SQL_SUCCESS;
12354 #ifdef SQL_ATTR_METADATA_ID
12355     case SQL_ATTR_METADATA_ID:
12356 	if (val == (SQLPOINTER) SQL_FALSE) {
12357 	    break;
12358 	}
12359 	/* fall through */
12360 #endif
12361     default:
12362 	setstatd(d, -1, "option value changed", "01S02");
12363 	return SQL_SUCCESS_WITH_INFO;
12364     }
12365     return SQL_SUCCESS;
12366 }
12367 
12368 #ifndef WINTERFACE
12369 /**
12370  * Set connect attribute of HDBC.
12371  * @param dbc database connection handle
12372  * @param attr option to be set
12373  * @param val option value
12374  * @param len size of option
12375  * @result ODBC error code
12376  */
12377 
12378 SQLRETURN SQL_API
SQLSetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)12379 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
12380 		  SQLINTEGER len)
12381 {
12382     SQLRETURN ret;
12383 
12384     HDBC_LOCK(dbc);
12385     ret = drvsetconnectattr(dbc, attr, val, len);
12386     HDBC_UNLOCK(dbc);
12387     return ret;
12388 }
12389 #endif
12390 
12391 #ifdef WINTERFACE
12392 /**
12393  * Set connect attribute of HDBC (UNICODE version).
12394  * @param dbc database connection handle
12395  * @param attr option to be set
12396  * @param val option value
12397  * @param len size of option
12398  * @result ODBC error code
12399  */
12400 
12401 SQLRETURN SQL_API
SQLSetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)12402 SQLSetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
12403 		   SQLINTEGER len)
12404 {
12405     SQLRETURN ret;
12406 
12407     HDBC_LOCK(dbc);
12408     ret = drvsetconnectattr(dbc, attr, val, len);
12409     HDBC_UNLOCK(dbc);
12410     return ret;
12411 }
12412 #endif
12413 
12414 /**
12415  * Internal get connect option of HDBC.
12416  * @param dbc database connection handle
12417  * @param opt option to be retrieved
12418  * @param param output buffer
12419  * @result ODBC error code
12420  */
12421 
12422 static SQLRETURN
drvgetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)12423 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
12424 {
12425     DBC *d;
12426     SQLINTEGER dummy;
12427 
12428     if (dbc == SQL_NULL_HDBC) {
12429 	return SQL_INVALID_HANDLE;
12430     }
12431     d = (DBC *) dbc;
12432     if (!param) {
12433 	param = (SQLPOINTER) &dummy;
12434     }
12435     switch (opt) {
12436     case SQL_ACCESS_MODE:
12437 	*((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
12438 	break;
12439     case SQL_AUTOCOMMIT:
12440 	*((SQLINTEGER *) param) =
12441 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
12442 	break;
12443     case SQL_LOGIN_TIMEOUT:
12444 	*((SQLINTEGER *) param) = 100;
12445 	break;
12446     case SQL_ODBC_CURSORS:
12447 	*((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
12448 	break;
12449     case SQL_PACKET_SIZE:
12450 	*((SQLINTEGER *) param) = 16384;
12451 	break;
12452     case SQL_TXN_ISOLATION:
12453 	*((SQLINTEGER *) param) = SQL_TXN_SERIALIZABLE;
12454 	break;
12455     case SQL_OPT_TRACE:
12456     case SQL_OPT_TRACEFILE:
12457     case SQL_QUIET_MODE:
12458     case SQL_TRANSLATE_DLL:
12459     case SQL_TRANSLATE_OPTION:
12460     case SQL_KEYSET_SIZE:
12461     case SQL_QUERY_TIMEOUT:
12462     case SQL_BIND_TYPE:
12463     case SQL_CURRENT_QUALIFIER:
12464 	*((SQLINTEGER *) param) = 0;
12465 	break;
12466     case SQL_USE_BOOKMARKS:
12467 	*((SQLINTEGER *) param) = SQL_UB_OFF;
12468 	break;
12469     case SQL_ASYNC_ENABLE:
12470 	*((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
12471 	break;
12472     case SQL_NOSCAN:
12473 	*((SQLINTEGER *) param) = SQL_NOSCAN_ON;
12474 	break;
12475     case SQL_CONCURRENCY:
12476 	*((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
12477 	break;
12478     case SQL_SIMULATE_CURSOR:
12479 	*((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
12480 	break;
12481     case SQL_MAX_ROWS:
12482 	*((SQLINTEGER *) param) = 0;
12483 	break;
12484     case SQL_ROWSET_SIZE:
12485     case SQL_MAX_LENGTH:
12486 	*((SQLINTEGER *) param) = 1000000000;
12487 	break;
12488     case SQL_CURSOR_TYPE:
12489 	*((SQLINTEGER *) param) = d->curtype;
12490 	break;
12491     case SQL_RETRIEVE_DATA:
12492 	*((SQLINTEGER *) param) = SQL_RD_ON;
12493 	break;
12494     default:
12495 	*((SQLINTEGER *) param) = 0;
12496 	setstatd(d, -1, "unsupported connect option %d",
12497 		 (*d->ov3) ? "HYC00" : "S1C00", opt);
12498 	return SQL_ERROR;
12499     }
12500     return SQL_SUCCESS;
12501 }
12502 
12503 #ifndef WINTERFACE
12504 /**
12505  * Get connect option of HDBC.
12506  * @param dbc database connection handle
12507  * @param opt option to be retrieved
12508  * @param param output buffer
12509  * @result ODBC error code
12510  */
12511 
12512 SQLRETURN SQL_API
SQLGetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)12513 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
12514 {
12515     SQLRETURN ret;
12516 
12517     HDBC_LOCK(dbc);
12518     ret = drvgetconnectoption(dbc, opt, param);
12519     HDBC_UNLOCK(dbc);
12520     return ret;
12521 }
12522 #endif
12523 
12524 #ifdef WINTERFACE
12525 /**
12526  * Get connect option of HDBC (UNICODE version).
12527  * @param dbc database connection handle
12528  * @param opt option to be retrieved
12529  * @param param output buffer
12530  * @result ODBC error code
12531  */
12532 
12533 SQLRETURN SQL_API
SQLGetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)12534 SQLGetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
12535 {
12536     SQLRETURN ret;
12537 
12538     HDBC_LOCK(dbc);
12539     ret = drvgetconnectoption(dbc, opt, param);
12540     if (SQL_SUCCEEDED(ret)) {
12541 	switch (opt) {
12542 	case SQL_OPT_TRACEFILE:
12543 	case SQL_CURRENT_QUALIFIER:
12544 	case SQL_TRANSLATE_DLL:
12545 	    if (param) {
12546 		*(SQLWCHAR *) param = 0;
12547 	    }
12548 	    break;
12549 	}
12550     }
12551     HDBC_UNLOCK(dbc);
12552     return ret;
12553 }
12554 #endif
12555 
12556 /**
12557  * Internal set option on HDBC.
12558  * @param dbc database connection handle
12559  * @param opt option to be set
12560  * @param param option value
12561  * @result ODBC error code
12562  */
12563 
12564 static SQLRETURN
drvsetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLUINTEGER param)12565 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
12566 {
12567     DBC *d;
12568 
12569     if (dbc == SQL_NULL_HDBC) {
12570 	return SQL_INVALID_HANDLE;
12571     }
12572     d = (DBC *) dbc;
12573     switch (opt) {
12574     case SQL_AUTOCOMMIT:
12575 	d->autocommit = param == SQL_AUTOCOMMIT_ON;
12576 	if (d->autocommit && d->intrans) {
12577 	    return endtran(d, SQL_COMMIT, 1);
12578 	} else if (!d->autocommit) {
12579 	    s3stmt_end(d->cur_s3stmt);
12580 	}
12581 	break;
12582     default:
12583 	setstatd(d, -1, "option value changed", "01S02");
12584 	return SQL_SUCCESS_WITH_INFO;
12585     }
12586     return SQL_SUCCESS;
12587 }
12588 
12589 #ifndef WINTERFACE
12590 /**
12591  * Set option on HDBC.
12592  * @param dbc database connection handle
12593  * @param opt option to be set
12594  * @param param option value
12595  * @result ODBC error code
12596  */
12597 
12598 SQLRETURN SQL_API
SQLSetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)12599 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
12600 {
12601     SQLRETURN ret;
12602 
12603     HDBC_LOCK(dbc);
12604     ret = drvsetconnectoption(dbc, opt, param);
12605     HDBC_UNLOCK(dbc);
12606     return ret;
12607 }
12608 #endif
12609 
12610 #ifdef WINTERFACE
12611 /**
12612  * Set option on HDBC (UNICODE version).
12613  * @param dbc database connection handle
12614  * @param opt option to be set
12615  * @param param option value
12616  * @result ODBC error code
12617  */
12618 
12619 SQLRETURN SQL_API
SQLSetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)12620 SQLSetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
12621 {
12622     SQLRETURN ret;
12623 
12624     HDBC_LOCK(dbc);
12625     ret = drvsetconnectoption(dbc, opt, param);
12626     HDBC_UNLOCK(dbc);
12627     return ret;
12628 }
12629 #endif
12630 
12631 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
12632 
12633 /**
12634  * Handling of SQLConnect() connection attributes
12635  * for standalone operation without driver manager.
12636  * @param dsn DSN/driver connection string
12637  * @param attr attribute string to be retrieved
12638  * @param out output buffer
12639  * @param outLen length of output buffer
12640  * @result true or false
12641  */
12642 
12643 static int
getdsnattr(char * dsn,char * attr,char * out,int outLen)12644 getdsnattr(char *dsn, char *attr, char *out, int outLen)
12645 {
12646     char *str = dsn, *start;
12647     int len = strlen(attr);
12648 
12649     while (*str) {
12650 	while (*str && *str == ';') {
12651 	    ++str;
12652 	}
12653 	start = str;
12654 	if ((str = strchr(str, '=')) == NULL) {
12655 	    return 0;
12656 	}
12657 	if (str - start == len && strncasecmp(start, attr, len) == 0) {
12658 	    start = ++str;
12659 	    while (*str && *str != ';') {
12660 		++str;
12661 	    }
12662 	    len = min(outLen - 1, str - start);
12663 	    strncpy(out, start, len);
12664 	    out[len] = '\0';
12665 	    return 1;
12666 	}
12667 	while (*str && *str != ';') {
12668 	    ++str;
12669 	}
12670     }
12671     return 0;
12672 }
12673 #endif
12674 
12675 /**
12676  * Internal connect to SQLite database.
12677  * @param dbc database connection handle
12678  * @param dsn DSN string
12679  * @param dsnLen length of DSN string or SQL_NTS
12680  * @param pwd password or NULL
12681  * @param pwdLen length of password or SQL_NTS
12682  * @param isu true/false: file name is UTF8 encoded
12683  * @result ODBC error code
12684  */
12685 
12686 static SQLRETURN
drvconnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,char * pwd,int pwdLen,int isu)12687 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen, char *pwd,
12688 	   int pwdLen, int isu)
12689 {
12690     DBC *d;
12691     int len;
12692     SQLRETURN ret;
12693     char buf[SQL_MAX_MESSAGE_LENGTH * 6], dbname[SQL_MAX_MESSAGE_LENGTH];
12694     char busy[SQL_MAX_MESSAGE_LENGTH / 4], tracef[SQL_MAX_MESSAGE_LENGTH];
12695     char loadext[SQL_MAX_MESSAGE_LENGTH];
12696     char sflag[32], spflag[32], ntflag[32], nwflag[32], biflag[32];
12697     char snflag[32], lnflag[32], ncflag[32], fkflag[32], jmode[32];
12698     char jdflag[32];
12699 #if defined(_WIN32) || defined(_WIN64)
12700     char oemcp[32];
12701 #endif
12702 
12703     if (dbc == SQL_NULL_HDBC) {
12704 	return SQL_INVALID_HANDLE;
12705     }
12706     d = (DBC *) dbc;
12707     if (d->magic != DBC_MAGIC) {
12708 	return SQL_INVALID_HANDLE;
12709     }
12710     if (d->sqlite != NULL) {
12711 	setstatd(d, -1, "connection already established", "08002");
12712 	return SQL_ERROR;
12713     }
12714     buf[0] = '\0';
12715     if (dsnLen == SQL_NTS) {
12716 	len = sizeof (buf) - 1;
12717     } else {
12718 	len = min(sizeof (buf) - 1, dsnLen);
12719     }
12720     if (dsn != NULL) {
12721 	strncpy(buf, (char *) dsn, len);
12722     }
12723     buf[len] = '\0';
12724     if (buf[0] == '\0') {
12725 	setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
12726 	return SQL_ERROR;
12727     }
12728 #if defined(_WIN32) || defined(_WIN64)
12729     /*
12730      * When DSN is in UTF it must be converted to ANSI
12731      * here for ANSI SQLGetPrivateProfileString()
12732      */
12733     if (isu) {
12734 	char *cdsn = utf_to_wmb(buf, len);
12735 
12736 	if (!cdsn) {
12737 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12738 	    return SQL_ERROR;
12739 	}
12740 	strcpy(buf, cdsn);
12741 	uc_free(cdsn);
12742     }
12743 #endif
12744     busy[0] = '\0';
12745     dbname[0] = '\0';
12746 #ifdef WITHOUT_DRIVERMGR
12747     getdsnattr(buf, "database", dbname, sizeof (dbname));
12748     if (dbname[0] == '\0') {
12749 	strncpy(dbname, buf, sizeof (dbname));
12750 	dbname[sizeof (dbname) - 1] = '\0';
12751     }
12752     getdsnattr(buf, "timeout", busy, sizeof (busy));
12753     sflag[0] = '\0';
12754     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
12755     spflag[0] = '\0';
12756     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
12757     ntflag[0] = '\0';
12758     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
12759     nwflag[0] = '\0';
12760     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
12761     snflag[0] = '\0';
12762     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
12763     lnflag[0] = '\0';
12764     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
12765     ncflag[0] = '\0';
12766     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
12767     fkflag[0] = '\0';
12768     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
12769     loadext[0] = '\0';
12770     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
12771     jmode[0] = '\0';
12772     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
12773     jdflag[0] = '\0';
12774     getdsnattr(buf, "jdconv", jdflag, sizeof (jdflag));
12775 #if defined(_WIN32) || defined(_WIN64)
12776     oemcp[0] = '\0';
12777     getdsnattr(buf, "oemcp", oemcp, sizeof (oemcp));
12778 #endif
12779     biflag[0] = '\0';
12780     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
12781 #else
12782     SQLGetPrivateProfileString(buf, "timeout", "100000",
12783 			       busy, sizeof (busy), ODBC_INI);
12784     SQLGetPrivateProfileString(buf, "database", "",
12785 			       dbname, sizeof (dbname), ODBC_INI);
12786 #if defined(_WIN32) || defined(_WIN64)
12787     /* database name read from registry is not UTF8 !!! */
12788     isu = 0;
12789 #endif
12790     SQLGetPrivateProfileString(buf, "stepapi", "",
12791 			       sflag, sizeof (sflag), ODBC_INI);
12792     SQLGetPrivateProfileString(buf, "syncpragma", "NORMAL",
12793 			       spflag, sizeof (spflag), ODBC_INI);
12794     SQLGetPrivateProfileString(buf, "notxn", "",
12795 			       ntflag, sizeof (ntflag), ODBC_INI);
12796     SQLGetPrivateProfileString(buf, "nowchar", "",
12797 			       nwflag, sizeof (nwflag), ODBC_INI);
12798     SQLGetPrivateProfileString(buf, "shortnames", "",
12799 			       snflag, sizeof (snflag), ODBC_INI);
12800     SQLGetPrivateProfileString(buf, "longnames", "",
12801 			       lnflag, sizeof (lnflag), ODBC_INI);
12802     SQLGetPrivateProfileString(buf, "nocreat", "",
12803 			       ncflag, sizeof (ncflag), ODBC_INI);
12804     SQLGetPrivateProfileString(buf, "fksupport", "",
12805 			       fkflag, sizeof (fkflag), ODBC_INI);
12806     SQLGetPrivateProfileString(buf, "loadext", "",
12807 			       loadext, sizeof (loadext), ODBC_INI);
12808     SQLGetPrivateProfileString(buf, "journalmode", "",
12809 			       jmode, sizeof (jmode), ODBC_INI);
12810     SQLGetPrivateProfileString(buf, "jdconv", "",
12811 			       jdflag, sizeof (jdflag), ODBC_INI);
12812 #if defined(_WIN32) || defined(_WIN64)
12813     SQLGetPrivateProfileString(buf, "oemcp", "1",
12814 			       oemcp, sizeof (oemcp), ODBC_INI);
12815 #endif
12816     SQLGetPrivateProfileString(buf, "bigint", "",
12817 			       biflag, sizeof (biflag), ODBC_INI);
12818 #endif
12819     tracef[0] = '\0';
12820 #ifdef WITHOUT_DRIVERMGR
12821     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
12822 #else
12823     SQLGetPrivateProfileString(buf, "tracefile", "",
12824 			       tracef, sizeof (tracef), ODBC_INI);
12825 #endif
12826     if (tracef[0] != '\0') {
12827 	d->trace = fopen(tracef, "a");
12828     }
12829     d->nowchar = getbool(nwflag);
12830     d->shortnames = getbool(snflag);
12831     d->longnames = getbool(lnflag);
12832     d->nocreat = getbool(ncflag);
12833     d->fksupport = getbool(fkflag);
12834     d->jdconv = getbool(jdflag);
12835 #if defined(_WIN32) || defined(_WIN64)
12836     d->oemcp = getbool(oemcp);
12837 #else
12838     d->oemcp = 0;
12839 #endif
12840     d->dobigint = getbool(biflag);
12841     d->pwd = pwd;
12842     d->pwdLen = 0;
12843     if (d->pwd) {
12844 	d->pwdLen = (pwdLen == SQL_NTS) ? strlen(d->pwd) : pwdLen;
12845     }
12846     ret = dbopen(d, dbname, isu, (char *) dsn, sflag, spflag, ntflag,
12847 		  jmode, busy);
12848     if (ret == SQL_SUCCESS) {
12849 	dbloadext(d, loadext);
12850     }
12851     return ret;
12852 }
12853 
12854 #ifndef WINTERFACE
12855 /**
12856  * Connect to SQLite database.
12857  * @param dbc database connection handle
12858  * @param dsn DSN string
12859  * @param dsnLen length of DSN string or SQL_NTS
12860  * @param uid user id string or NULL
12861  * @param uidLen length of user id string or SQL_NTS
12862  * @param pwd password string or NULL
12863  * @param pwdLen length of password string or SQL_NTS
12864  * @result ODBC error code
12865  */
12866 
12867 SQLRETURN SQL_API
SQLConnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,SQLCHAR * uid,SQLSMALLINT uidLen,SQLCHAR * pwd,SQLSMALLINT pwdLen)12868 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
12869 	   SQLCHAR *uid, SQLSMALLINT uidLen,
12870 	   SQLCHAR *pwd, SQLSMALLINT pwdLen)
12871 {
12872     SQLRETURN ret;
12873 
12874     HDBC_LOCK(dbc);
12875     ret = drvconnect(dbc, dsn, dsnLen, (char *) pwd, pwdLen, 0);
12876     HDBC_UNLOCK(dbc);
12877     return ret;
12878 }
12879 #endif
12880 
12881 #ifdef WINTERFACE
12882 /**
12883  * Connect to SQLite database.
12884  * @param dbc database connection handle
12885  * @param dsn DSN string
12886  * @param dsnLen length of DSN string or SQL_NTS
12887  * @param uid user id string or NULL
12888  * @param uidLen length of user id string or SQL_NTS
12889  * @param pwd password string or NULL
12890  * @param pwdLen length of password string or SQL_NTS
12891  * @result ODBC error code
12892  */
12893 
12894 SQLRETURN SQL_API
SQLConnectW(SQLHDBC dbc,SQLWCHAR * dsn,SQLSMALLINT dsnLen,SQLWCHAR * uid,SQLSMALLINT uidLen,SQLWCHAR * pwd,SQLSMALLINT pwdLen)12895 SQLConnectW(SQLHDBC dbc, SQLWCHAR *dsn, SQLSMALLINT dsnLen,
12896 	    SQLWCHAR *uid, SQLSMALLINT uidLen,
12897 	    SQLWCHAR *pwd, SQLSMALLINT pwdLen)
12898 {
12899     char *dsna = NULL;
12900     char *pwda = NULL;
12901     SQLRETURN ret;
12902 
12903     HDBC_LOCK(dbc);
12904     if (dsn) {
12905 	dsna = uc_to_utf_c(dsn, dsnLen);
12906 	if (!dsna) {
12907 	    DBC *d = (DBC *) dbc;
12908 
12909 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12910 	    ret = SQL_ERROR;
12911 	    goto done;
12912 	}
12913     }
12914     if (pwd) {
12915 	pwda = uc_to_utf_c(pwd, pwdLen);
12916 	if (!pwda) {
12917 	    DBC *d = (DBC *) dbc;
12918 
12919 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12920 	    ret = SQL_ERROR;
12921 	    goto done;
12922 	}
12923     }
12924     ret = drvconnect(dbc, (SQLCHAR *) dsna, SQL_NTS, pwda, SQL_NTS, 1);
12925 done:
12926     HDBC_UNLOCK(dbc);
12927     uc_free(dsna);
12928     uc_free(pwda);
12929     return ret;
12930 }
12931 #endif
12932 
12933 /**
12934  * Internal disconnect given HDBC.
12935  * @param dbc database connection handle
12936  * @result ODBC error code
12937  */
12938 
12939 static SQLRETURN
drvdisconnect(SQLHDBC dbc)12940 drvdisconnect(SQLHDBC dbc)
12941 {
12942     DBC *d;
12943     int rc;
12944 
12945     if (dbc == SQL_NULL_HDBC) {
12946 	return SQL_INVALID_HANDLE;
12947     }
12948     d = (DBC *) dbc;
12949     if (d->magic != DBC_MAGIC) {
12950 	return SQL_INVALID_HANDLE;
12951     }
12952     if (d->intrans) {
12953 	setstatd(d, -1, "incomplete transaction", "25000");
12954 	return SQL_ERROR;
12955     }
12956     if (d->cur_s3stmt) {
12957 	s3stmt_end(d->cur_s3stmt);
12958     }
12959     if (d->sqlite) {
12960 	if (d->trace) {
12961 	    fprintf(d->trace, "-- sqlite3_close: '%s'\n",
12962 		    d->dbname);
12963 	    fflush(d->trace);
12964 	}
12965 	rc = sqlite3_close(d->sqlite);
12966 	if (rc == SQLITE_BUSY) {
12967 	    setstatd(d, -1, "unfinished statements", "25000");
12968 	    return SQL_ERROR;
12969 	}
12970 	d->sqlite = NULL;
12971     }
12972     freep(&d->dbname);
12973     freep(&d->dsn);
12974     return SQL_SUCCESS;
12975 }
12976 
12977 /**
12978  * Disconnect given HDBC.
12979  * @param dbc database connection handle
12980  * @result ODBC error code
12981  */
12982 
12983 SQLRETURN SQL_API
SQLDisconnect(SQLHDBC dbc)12984 SQLDisconnect(SQLHDBC dbc)
12985 {
12986     SQLRETURN ret;
12987 
12988     HDBC_LOCK(dbc);
12989     ret = drvdisconnect(dbc);
12990     HDBC_UNLOCK(dbc);
12991     return ret;
12992 }
12993 
12994 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
12995 
12996 /**
12997  * Internal standalone (w/o driver manager) database connect.
12998  * @param dbc database connection handle
12999  * @param hwnd dummy window handle or NULL
13000  * @param connIn driver connect input string
13001  * @param connInLen length of driver connect input string or SQL_NTS
13002  * @param connOut driver connect output string
13003  * @param connOutMax length of driver connect output string
13004  * @param connOutLen output length of driver connect output string
13005  * @param drvcompl completion type
13006  * @result ODBC error code
13007  */
13008 
13009 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)13010 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
13011 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
13012 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
13013 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
13014 {
13015     DBC *d;
13016     int len;
13017     SQLRETURN ret;
13018     char buf[SQL_MAX_MESSAGE_LENGTH * 8], dbname[SQL_MAX_MESSAGE_LENGTH];
13019     char dsn[SQL_MAX_MESSAGE_LENGTH], busy[SQL_MAX_MESSAGE_LENGTH / 4];
13020     char tracef[SQL_MAX_MESSAGE_LENGTH], loadext[SQL_MAX_MESSAGE_LENGTH];
13021     char pwd[SQL_MAX_MESSAGE_LENGTH];
13022     char sflag[32], spflag[32], ntflag[32], snflag[32], lnflag[32];
13023     char ncflag[32], nwflag[32], fkflag[32], jmode[32], biflag[32];
13024     char jdflag[32];
13025 
13026     if (dbc == SQL_NULL_HDBC) {
13027 	return SQL_INVALID_HANDLE;
13028     }
13029     if (drvcompl != SQL_DRIVER_COMPLETE &&
13030 	drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
13031 	drvcompl != SQL_DRIVER_PROMPT &&
13032 	drvcompl != SQL_DRIVER_NOPROMPT) {
13033 	return SQL_NO_DATA;
13034     }
13035     d = (DBC *) dbc;
13036     if (d->sqlite) {
13037 	setstatd(d, -1, "connection already established", "08002");
13038 	return SQL_ERROR;
13039     }
13040     buf[0] = '\0';
13041     if (connInLen == SQL_NTS) {
13042 	len = sizeof (buf) - 1;
13043     } else {
13044 	len = min(connInLen, sizeof (buf) - 1);
13045     }
13046     if (connIn != NULL) {
13047 	strncpy(buf, (char *) connIn, len);
13048     }
13049     buf[len] = '\0';
13050     if (!buf[0]) {
13051 	setstatd(d, -1, "invalid connect attributes",
13052 		 (*d->ov3) ? "HY090" : "S1090");
13053 	return SQL_ERROR;
13054     }
13055     dsn[0] = '\0';
13056     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
13057 
13058     /* special case: connIn is sole DSN value without keywords */
13059     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
13060 	strncpy(dsn, buf, sizeof (dsn) - 1);
13061 	dsn[sizeof (dsn) - 1] = '\0';
13062     }
13063 
13064     busy[0] = '\0';
13065     getdsnattr(buf, "timeout", busy, sizeof (busy));
13066 #ifndef WITHOUT_DRIVERMGR
13067     if (dsn[0] && !busy[0]) {
13068 	SQLGetPrivateProfileString(dsn, "timeout", "100000",
13069 				   busy, sizeof (busy), ODBC_INI);
13070     }
13071 #endif
13072     dbname[0] = '\0';
13073     getdsnattr(buf, "database", dbname, sizeof (dbname));
13074 #ifndef WITHOUT_DRIVERMGR
13075     if (dsn[0] && !dbname[0]) {
13076 	SQLGetPrivateProfileString(dsn, "database", "",
13077 				   dbname, sizeof (dbname), ODBC_INI);
13078     }
13079 #endif
13080     sflag[0] = '\0';
13081     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
13082 #ifndef WITHOUT_DRIVERMGR
13083     if (dsn[0] && !sflag[0]) {
13084 	SQLGetPrivateProfileString(dsn, "stepapi", "",
13085 				   sflag, sizeof (sflag), ODBC_INI);
13086     }
13087 #endif
13088     spflag[0] = '\0';
13089     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
13090 #ifndef WITHOUT_DRIVERMGR
13091     if (dsn[0] && !spflag[0]) {
13092 	SQLGetPrivateProfileString(dsn, "syncpragma", "NORMAL",
13093 				   spflag, sizeof (spflag), ODBC_INI);
13094     }
13095 #endif
13096     ntflag[0] = '\0';
13097     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
13098 #ifndef WITHOUT_DRIVERMGR
13099     if (dsn[0] && !ntflag[0]) {
13100 	SQLGetPrivateProfileString(dsn, "notxn", "",
13101 				   ntflag, sizeof (ntflag), ODBC_INI);
13102     }
13103 #endif
13104     snflag[0] = '\0';
13105     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
13106 #ifndef WITHOUT_DRIVERMGR
13107     if (dsn[0] && !snflag[0]) {
13108 	SQLGetPrivateProfileString(dsn, "shortnames", "",
13109 				   snflag, sizeof (snflag), ODBC_INI);
13110     }
13111 #endif
13112     lnflag[0] = '\0';
13113     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
13114 #ifndef WITHOUT_DRIVERMGR
13115     if (dsn[0] && !lnflag[0]) {
13116 	SQLGetPrivateProfileString(dsn, "longnames", "",
13117 				   lnflag, sizeof (lnflag), ODBC_INI);
13118     }
13119 #endif
13120     ncflag[0] = '\0';
13121     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
13122 #ifndef WITHOUT_DRIVERMGR
13123     if (dsn[0] && !ncflag[0]) {
13124 	SQLGetPrivateProfileString(dsn, "nocreat", "",
13125 				   ncflag, sizeof (ncflag), ODBC_INI);
13126     }
13127 #endif
13128     nwflag[0] = '\0';
13129     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
13130 #ifndef WITHOUT_DRIVERMGR
13131     if (dsn[0] && !nwflag[0]) {
13132 	SQLGetPrivateProfileString(dsn, "nowchar", "",
13133 				   nwflag, sizeof (nwflag), ODBC_INI);
13134     }
13135 #endif
13136     fkflag[0] = '\0';
13137     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
13138 #ifndef WITHOUT_DRIVERMGR
13139     if (dsn[0] && !fkflag[0]) {
13140 	SQLGetPrivateProfileString(dsn, "fksupport", "",
13141 				   fkflag, sizeof (fkflag), ODBC_INI);
13142     }
13143 #endif
13144     loadext[0] = '\0';
13145     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
13146 #ifndef WITHOUT_DRIVERMGR
13147     if (dsn[0] && !loadext[0]) {
13148 	SQLGetPrivateProfileString(dsn, "loadext", "",
13149 				   loadext, sizeof (loadext), ODBC_INI);
13150     }
13151 #endif
13152     jmode[0] = '\0';
13153     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
13154 #ifndef WITHOUT_DRIVERMGR
13155     if (dsn[0] && !jmode[0]) {
13156 	SQLGetPrivateProfileString(dsn, "journalmode", "",
13157 				   jmode, sizeof (jmode), ODBC_INI);
13158     }
13159 #endif
13160     biflag[0] = '\0';
13161     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
13162 #ifndef WITHOUT_DRIVERMGR
13163     if (dsn[0] && !biflag[0]) {
13164 	SQLGetPrivateProfileString(dsn, "bigint", "",
13165 				   biflag, sizeof (biflag), ODBC_INI);
13166     }
13167 #endif
13168     jdflag[0] = '\0';
13169     getdsnattr(buf, "jdconv", jdflag, sizeof (jdflag));
13170 #ifndef WITHOUT_DRIVERMGR
13171     if (dsn[0] && !jdflag[0]) {
13172 	SQLGetPrivateProfileString(dsn, "jdconv", "",
13173 				   jdflag, sizeof (jdflag), ODBC_INI);
13174     }
13175 #endif
13176     pwd[0] = '\0';
13177     getdsnattr(buf, "pwd", pwd, sizeof (pwd));
13178 #ifndef WITHOUT_DRIVERMGR
13179     if (dsn[0] && !pwd[0]) {
13180 	SQLGetPrivateProfileString(dsn, "pwd", "",
13181 				   pwd, sizeof (pwd), ODBC_INI);
13182     }
13183 #endif
13184 
13185     if (!dbname[0] && !dsn[0]) {
13186 	strcpy(dsn, "SQLite");
13187 	strncpy(dbname, buf, sizeof (dbname));
13188 	dbname[sizeof (dbname) - 1] = '\0';
13189     }
13190     tracef[0] = '\0';
13191     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
13192 #ifndef WITHOUT_DRIVERMGR
13193     if (dsn[0] && !tracef[0]) {
13194 	SQLGetPrivateProfileString(dsn, "tracefile", "",
13195 				   tracef, sizeof (tracef), ODBC_INI);
13196     }
13197 #endif
13198     if (connOut || connOutLen) {
13199 	int count;
13200 
13201 	buf[0] = '\0';
13202 	count = snprintf(buf, sizeof (buf),
13203 			 "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s;"
13204 			 "SyncPragma=%s;NoTXN=%s;ShortNames=%s;LongNames=%s;"
13205 			 "NoCreat=%s;NoWCHAR=%s;FKSupport=%s;Tracefile=%s;"
13206 			 "JournalMode=%s;LoadExt=%s;BigInt=%s;JDConv=%s;"
13207 			 "PWD=%s",
13208 			 dsn, dbname, sflag, busy, spflag, ntflag,
13209 			 snflag, lnflag, ncflag, nwflag, fkflag, tracef,
13210 			 jmode, loadext, biflag, jdflag, pwd);
13211 	if (count < 0) {
13212 	    buf[sizeof (buf) - 1] = '\0';
13213 	}
13214 	len = min(connOutMax - 1, strlen(buf));
13215 	if (connOut) {
13216 	    strncpy((char *) connOut, buf, len);
13217 	    connOut[len] = '\0';
13218 	}
13219 	if (connOutLen) {
13220 	    *connOutLen = len;
13221 	}
13222     }
13223     if (tracef[0] != '\0') {
13224 	d->trace = fopen(tracef, "a");
13225     }
13226     d->shortnames = getbool(snflag);
13227     d->longnames = getbool(lnflag);
13228     d->nocreat = getbool(ncflag);
13229     d->nowchar = getbool(nwflag);
13230     d->fksupport = getbool(fkflag);
13231     d->dobigint = getbool(biflag);
13232     d->jdconv = getbool(jdflag);
13233     d->oemcp = 0;
13234     d->pwdLen = strlen(pwd);
13235     d->pwd = (d->pwdLen > 0) ? pwd : NULL;
13236     ret = dbopen(d, dbname, 0, dsn, sflag, spflag, ntflag, jmode, busy);
13237     memset(pwd, 0, sizeof (pwd));
13238     if (ret == SQL_SUCCESS) {
13239 	dbloadext(d, loadext);
13240     }
13241     return ret;
13242 }
13243 #endif
13244 
13245 /**
13246  * Internal free function for HSTMT.
13247  * @param stmt statement handle
13248  * @result ODBC error code
13249  */
13250 
13251 static SQLRETURN
freestmt(SQLHSTMT stmt)13252 freestmt(SQLHSTMT stmt)
13253 {
13254     STMT *s;
13255     DBC *d;
13256 
13257     if (stmt == SQL_NULL_HSTMT) {
13258 	return SQL_INVALID_HANDLE;
13259     }
13260     s = (STMT *) stmt;
13261     s3stmt_drop(s);
13262     freeresult(s, 1);
13263     freep(&s->query);
13264     d = (DBC *) s->dbc;
13265     if (d && d->magic == DBC_MAGIC) {
13266 	STMT *p, *n;
13267 
13268 	p = NULL;
13269 	n = d->stmt;
13270 	while (n) {
13271 	    if (n == s) {
13272 		break;
13273 	    }
13274 	    p = n;
13275 	    n = n->next;
13276 	}
13277 	if (n) {
13278 	    if (p) {
13279 		p->next = s->next;
13280 	    } else {
13281 		d->stmt = s->next;
13282 	    }
13283 	}
13284     }
13285     freeparams(s);
13286     freep(&s->bindparms);
13287     if (s->row_status0 != &s->row_status1) {
13288 	freep(&s->row_status0);
13289 	s->rowset_size = 1;
13290 	s->row_status0 = &s->row_status1;
13291     }
13292     xfree(s);
13293     return SQL_SUCCESS;
13294 }
13295 
13296 /**
13297  * Allocate HSTMT given HDBC (driver internal version).
13298  * @param dbc database connection handle
13299  * @param stmt pointer to statement handle
13300  * @result ODBC error code
13301  */
13302 
13303 static SQLRETURN
drvallocstmt(SQLHDBC dbc,SQLHSTMT * stmt)13304 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
13305 {
13306     DBC *d;
13307     STMT *s, *sl, *pl;
13308 
13309     if (dbc == SQL_NULL_HDBC) {
13310 	return SQL_INVALID_HANDLE;
13311     }
13312     d = (DBC *) dbc;
13313     if (d->magic != DBC_MAGIC || stmt == NULL) {
13314 	return SQL_INVALID_HANDLE;
13315     }
13316     s = (STMT *) xmalloc(sizeof (STMT));
13317     if (s == NULL) {
13318 	*stmt = SQL_NULL_HSTMT;
13319 	return SQL_ERROR;
13320     }
13321     *stmt = (SQLHSTMT) s;
13322     memset(s, 0, sizeof (STMT));
13323     s->dbc = dbc;
13324     s->ov3 = d->ov3;
13325     s->bkmrk = SQL_UB_OFF;
13326     s->bkmrkptr = 0;
13327     s->oemcp = &d->oemcp;
13328     s->jdconv = &d->jdconv;
13329     s->nowchar[0] = d->nowchar;
13330     s->nowchar[1] = 0;
13331     s->dobigint = d->dobigint;
13332     s->curtype = d->curtype;
13333     s->row_status0 = &s->row_status1;
13334     s->rowset_size = 1;
13335     s->longnames = d->longnames;
13336     s->retr_data = SQL_RD_ON;
13337     s->max_rows = 0;
13338     s->bind_type = SQL_BIND_BY_COLUMN;
13339     s->bind_offs = NULL;
13340     s->paramset_size = 1;
13341     s->parm_bind_type = SQL_PARAM_BIND_BY_COLUMN;
13342     s->one_tbl = -1;
13343     s->has_pk = -1;
13344     s->has_rowid = -1;
13345 #ifdef _WIN64
13346     sprintf((char *) s->cursorname, "CUR_%I64X", (SQLUBIGINT) *stmt);
13347 #else
13348     sprintf((char *) s->cursorname, "CUR_%016lX", (long) *stmt);
13349 #endif
13350     sl = d->stmt;
13351     pl = NULL;
13352     while (sl) {
13353 	pl = sl;
13354 	sl = sl->next;
13355     }
13356     if (pl) {
13357 	pl->next = s;
13358     } else {
13359 	d->stmt = s;
13360     }
13361     return SQL_SUCCESS;
13362 }
13363 
13364 /**
13365  * Allocate HSTMT given HDBC.
13366  * @param dbc database connection handle
13367  * @param stmt pointer to statement handle
13368  * @result ODBC error code
13369  */
13370 
13371 SQLRETURN SQL_API
SQLAllocStmt(SQLHDBC dbc,SQLHSTMT * stmt)13372 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
13373 {
13374     SQLRETURN ret;
13375 
13376     HDBC_LOCK(dbc);
13377     ret = drvallocstmt(dbc, stmt);
13378     HDBC_UNLOCK(dbc);
13379     return ret;
13380 }
13381 
13382 /**
13383  * Internal function to perform certain kinds of free/close on STMT.
13384  * @param stmt statement handle
13385  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
13386  * @result ODBC error code
13387  */
13388 
13389 static SQLRETURN
drvfreestmt(SQLHSTMT stmt,SQLUSMALLINT opt)13390 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
13391 {
13392     STMT *s;
13393     SQLRETURN ret = SQL_SUCCESS;
13394     SQLHDBC dbc;
13395 
13396     if (stmt == SQL_NULL_HSTMT) {
13397 	return SQL_INVALID_HANDLE;
13398     }
13399     HSTMT_LOCK(stmt);
13400     s = (STMT *) stmt;
13401     dbc = s->dbc;
13402     switch (opt) {
13403     case SQL_RESET_PARAMS:
13404 	freeparams(s);
13405 	break;
13406     case SQL_UNBIND:
13407 	unbindcols(s);
13408 	break;
13409     case SQL_CLOSE:
13410 	s3stmt_end_if(s);
13411 	freeresult(s, 0);
13412 	break;
13413     case SQL_DROP:
13414 	s3stmt_end_if(s);
13415 	ret = freestmt(stmt);
13416 	break;
13417     default:
13418 	setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
13419 	ret = SQL_ERROR;
13420 	break;
13421     }
13422     HDBC_UNLOCK(dbc);
13423     return ret;
13424 }
13425 
13426 /**
13427  * Free HSTMT.
13428  * @param stmt statement handle
13429  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
13430  * @result ODBC error code
13431  */
13432 
13433 SQLRETURN SQL_API
SQLFreeStmt(SQLHSTMT stmt,SQLUSMALLINT opt)13434 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
13435 {
13436     return drvfreestmt(stmt, opt);
13437 }
13438 
13439 /**
13440  * Cancel HSTMT closing cursor.
13441  * @param stmt statement handle
13442  * @result ODBC error code
13443  */
13444 
13445 SQLRETURN SQL_API
SQLCancel(SQLHSTMT stmt)13446 SQLCancel(SQLHSTMT stmt)
13447 {
13448     if (stmt != SQL_NULL_HSTMT) {
13449 	DBC *d = (DBC *) ((STMT *) stmt)->dbc;
13450 #if defined(_WIN32) || defined(_WIN64)
13451 	/* interrupt when other thread owns critical section */
13452 	if (d->magic == DBC_MAGIC && d->owner != GetCurrentThreadId() &&
13453 	    d->owner != 0) {
13454 	    d->busyint = 1;
13455 	    sqlite3_interrupt(d->sqlite);
13456 	    return SQL_SUCCESS;
13457 	}
13458 #else
13459 	if (d->magic == DBC_MAGIC) {
13460 	    d->busyint = 1;
13461 	    sqlite3_interrupt(d->sqlite);
13462 	}
13463 #endif
13464     }
13465     return drvfreestmt(stmt, SQL_CLOSE);
13466 }
13467 
13468 /**
13469  * Internal function to get cursor name of STMT.
13470  * @param stmt statement handle
13471  * @param cursor output buffer
13472  * @param buflen length of output buffer
13473  * @param lenp output length
13474  * @result ODBC error code
13475  */
13476 
13477 static SQLRETURN
drvgetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)13478 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
13479 		 SQLSMALLINT *lenp)
13480 {
13481     STMT *s;
13482 
13483     if (stmt == SQL_NULL_HSTMT) {
13484 	return SQL_INVALID_HANDLE;
13485     }
13486     s = (STMT *) stmt;
13487     if (lenp && !cursor) {
13488 	*lenp = strlen((char *) s->cursorname);
13489 	return SQL_SUCCESS;
13490     }
13491     if (cursor) {
13492 	if (buflen > 0) {
13493 	    strncpy((char *) cursor, (char *) s->cursorname, buflen - 1);
13494 	    cursor[buflen - 1] = '\0';
13495 	}
13496 	if (lenp) {
13497 	    *lenp = min(strlen((char *) s->cursorname), buflen - 1);
13498 	}
13499     }
13500     return SQL_SUCCESS;
13501 }
13502 
13503 #ifndef WINTERFACE
13504 /**
13505  * Get cursor name of STMT.
13506  * @param stmt statement handle
13507  * @param cursor output buffer
13508  * @param buflen length of output buffer
13509  * @param lenp output length
13510  * @result ODBC error code
13511  */
13512 
13513 SQLRETURN SQL_API
SQLGetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)13514 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
13515 		 SQLSMALLINT *lenp)
13516 {
13517     SQLRETURN ret;
13518 #if defined(_WIN32) || defined(_WIN64)
13519     SQLSMALLINT len = 0;
13520 #endif
13521 
13522     HSTMT_LOCK(stmt);
13523 #if defined(_WIN32) || defined(_WIN64)
13524     if (!((STMT *) stmt)->oemcp[0]) {
13525 	ret = drvgetcursorname(stmt, cursor, buflen, lenp);
13526 	goto done;
13527     }
13528     ret = drvgetcursorname(stmt, cursor, buflen, &len);
13529     if (ret == SQL_SUCCESS) {
13530 	char *c = NULL;
13531 
13532 	if (cursor) {
13533 	    c = utf_to_wmb((char *) cursor, len);
13534 	    if (!c) {
13535 		ret = nomem((STMT *) stmt);
13536 		goto done;
13537 	    }
13538 	    c[len] = 0;
13539 	    len = strlen(c);
13540 	    if (buflen > 0) {
13541 		strncpy((char *) cursor, c, buflen - 1);
13542 		cursor[buflen - 1] = 0;
13543 	    }
13544 	    uc_free(c);
13545 	}
13546 	if (lenp) {
13547 	    *lenp = min(len, buflen - 1);
13548 	}
13549     }
13550 done:
13551     ;
13552 #else
13553     ret = drvgetcursorname(stmt, cursor, buflen, lenp);
13554 #endif
13555     HSTMT_UNLOCK(stmt);
13556     return ret;
13557 }
13558 #endif
13559 
13560 #ifdef WINTERFACE
13561 /**
13562  * Get cursor name of STMT (UNICODE version).
13563  * @param stmt statement handle
13564  * @param cursor output buffer
13565  * @param buflen length of output buffer
13566  * @param lenp output length
13567  * @result ODBC error code
13568  */
13569 
13570 SQLRETURN SQL_API
SQLGetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)13571 SQLGetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT buflen,
13572 		  SQLSMALLINT *lenp)
13573 {
13574     SQLRETURN ret;
13575     SQLSMALLINT len = 0;
13576 
13577     HSTMT_LOCK(stmt);
13578     ret = drvgetcursorname(stmt, (SQLCHAR *) cursor, buflen, &len);
13579     if (ret == SQL_SUCCESS) {
13580 	SQLWCHAR *c = NULL;
13581 
13582 	if (cursor) {
13583 	    c = uc_from_utf((SQLCHAR *) cursor, len);
13584 	    if (!c) {
13585 		ret = nomem((STMT *) stmt);
13586 		goto done;
13587 	    }
13588 	    c[len] = 0;
13589 	    len = uc_strlen(c);
13590 	    if (buflen > 0) {
13591 		uc_strncpy(cursor, c, buflen - 1);
13592 		cursor[buflen - 1] = 0;
13593 	    }
13594 	    uc_free(c);
13595 	}
13596 	if (lenp) {
13597 	    *lenp = min(len, buflen - 1);
13598 	}
13599     }
13600 done:
13601     HSTMT_UNLOCK(stmt);
13602     return ret;
13603 }
13604 #endif
13605 
13606 /**
13607  * Internal function to set cursor name on STMT.
13608  * @param stmt statement handle
13609  * @param cursor new cursor name
13610  * @param len length of cursor name or SQL_NTS
13611  * @result ODBC error code
13612  */
13613 
13614 static SQLRETURN
drvsetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)13615 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
13616 {
13617     STMT *s;
13618 
13619     if (stmt == SQL_NULL_HSTMT) {
13620 	return SQL_INVALID_HANDLE;
13621     }
13622     s = (STMT *) stmt;
13623     if (!cursor ||
13624 	!((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
13625 	  (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
13626 	setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
13627 	return SQL_ERROR;
13628     }
13629     if (len == SQL_NTS) {
13630 	len = sizeof (s->cursorname) - 1;
13631     } else {
13632 	len = min(sizeof (s->cursorname) - 1, len);
13633     }
13634     strncpy((char *) s->cursorname, (char *) cursor, len);
13635     s->cursorname[len] = '\0';
13636     return SQL_SUCCESS;
13637 }
13638 
13639 #ifndef WINTERFACE
13640 /**
13641  * Set cursor name on STMT.
13642  * @param stmt statement handle
13643  * @param cursor new cursor name
13644  * @param len length of cursor name or SQL_NTS
13645  * @result ODBC error code
13646  */
13647 
13648 SQLRETURN SQL_API
SQLSetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)13649 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
13650 {
13651 #if defined(_WIN32) || defined(_WIN64)
13652     char *c = NULL;
13653 #endif
13654     SQLRETURN ret;
13655 
13656     HSTMT_LOCK(stmt);
13657 #if defined(_WIN32) || defined(_WIN64)
13658     if (!((STMT *) stmt)->oemcp[0]) {
13659 	ret = drvsetcursorname(stmt, cursor, len);
13660 	goto done2;
13661     }
13662     if (cursor) {
13663 	c = wmb_to_utf_c((char *) cursor, len);
13664 	if (!c) {
13665 	    ret = nomem((STMT *) stmt);
13666 	    goto done;
13667 	}
13668     }
13669     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
13670 #else
13671     ret = drvsetcursorname(stmt, cursor, len);
13672 #endif
13673 #if defined(_WIN32) || defined(_WIN64)
13674 done:
13675     uc_free(c);
13676 done2:
13677     ;
13678 #endif
13679     HSTMT_UNLOCK(stmt);
13680     return ret;
13681 }
13682 #endif
13683 
13684 #ifdef WINTERFACE
13685 /**
13686  * Set cursor name on STMT (UNICODE version).
13687  * @param stmt statement handle
13688  * @param cursor new cursor name
13689  * @param len length of cursor name or SQL_NTS
13690  * @result ODBC error code
13691  */
13692 
13693 SQLRETURN SQL_API
SQLSetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT len)13694 SQLSetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT len)
13695 {
13696     char *c = NULL;
13697     SQLRETURN ret;
13698 
13699     HSTMT_LOCK(stmt);
13700     if (cursor) {
13701 	c = uc_to_utf_c(cursor, len);
13702 	if (!c) {
13703 	    ret = nomem((STMT *) stmt);
13704 	    goto done;
13705 	}
13706     }
13707     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
13708 done:
13709     uc_free(c);
13710     HSTMT_UNLOCK(stmt);
13711     return ret;
13712 }
13713 #endif
13714 
13715 /**
13716  * Close open cursor.
13717  * @param stmt statement handle
13718  * @return ODBC error code
13719  */
13720 
13721 SQLRETURN SQL_API
SQLCloseCursor(SQLHSTMT stmt)13722 SQLCloseCursor(SQLHSTMT stmt)
13723 {
13724     return drvfreestmt(stmt, SQL_CLOSE);
13725 }
13726 
13727 /**
13728  * Allocate a HENV, HDBC, or HSTMT handle.
13729  * @param type handle type
13730  * @param input input handle (HENV, HDBC)
13731  * @param output pointer to output handle (HENV, HDBC, HSTMT)
13732  * @result ODBC error code
13733  */
13734 
13735 SQLRETURN SQL_API
SQLAllocHandle(SQLSMALLINT type,SQLHANDLE input,SQLHANDLE * output)13736 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
13737 {
13738     SQLRETURN ret;
13739 
13740     switch (type) {
13741     case SQL_HANDLE_ENV:
13742 	ret = drvallocenv((SQLHENV *) output);
13743 	if (ret == SQL_SUCCESS) {
13744 	    ENV *e = (ENV *) *output;
13745 
13746 	    if (e && e->magic == ENV_MAGIC) {
13747 		e->ov3 = 1;
13748 	    }
13749 	}
13750 	return ret;
13751     case SQL_HANDLE_DBC:
13752 	return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
13753     case SQL_HANDLE_STMT:
13754 	HDBC_LOCK((SQLHDBC) input);
13755 	ret = drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
13756 	HDBC_UNLOCK((SQLHDBC) input);
13757 	return ret;
13758     }
13759     return SQL_ERROR;
13760 }
13761 
13762 /**
13763  * Free a HENV, HDBC, or HSTMT handle.
13764  * @param type handle type
13765  * @param h handle (HENV, HDBC, or HSTMT)
13766  * @result ODBC error code
13767  */
13768 
13769 SQLRETURN SQL_API
SQLFreeHandle(SQLSMALLINT type,SQLHANDLE h)13770 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
13771 {
13772     switch (type) {
13773     case SQL_HANDLE_ENV:
13774 	return drvfreeenv((SQLHENV) h);
13775     case SQL_HANDLE_DBC:
13776 	return drvfreeconnect((SQLHDBC) h);
13777     case SQL_HANDLE_STMT:
13778 	return drvfreestmt((SQLHSTMT) h, SQL_DROP);
13779     }
13780     return SQL_ERROR;
13781 }
13782 
13783 /**
13784  * Free dynamically allocated column descriptions of STMT.
13785  * @param s statement pointer
13786  */
13787 
13788 static void
freedyncols(STMT * s)13789 freedyncols(STMT *s)
13790 {
13791     if (s->dyncols) {
13792 	int i;
13793 
13794 	for (i = 0; i < s->dcols; i++) {
13795 	    freep(&s->dyncols[i].typename);
13796 	}
13797 	if (s->cols == s->dyncols) {
13798 	    s->cols = NULL;
13799 	    s->ncols = 0;
13800 	}
13801 	freep(&s->dyncols);
13802     }
13803     s->dcols = 0;
13804 }
13805 
13806 /**
13807  * Free statement's result.
13808  * @param s statement pointer
13809  * @param clrcols flag to clear column information
13810  *
13811  * The result rows are free'd using the rowfree function pointer.
13812  * If clrcols is greater than zero, then column bindings and dynamic column
13813  * descriptions are free'd.
13814  * If clrcols is less than zero, then dynamic column descriptions are free'd.
13815  */
13816 
13817 static void
freeresult(STMT * s,int clrcols)13818 freeresult(STMT *s, int clrcols)
13819 {
13820     freep(&s->bincache);
13821     s->bincell = NULL;
13822     s->binlen = 0;
13823     if (s->rows) {
13824 	if (s->rowfree) {
13825 	    s->rowfree(s->rows);
13826 	    s->rowfree = NULL;
13827 	}
13828 	s->rows = NULL;
13829     }
13830     s->nrows = -1;
13831     if (clrcols > 0) {
13832 	freep(&s->bindcols);
13833 	s->nbindcols = 0;
13834     }
13835     if (clrcols) {
13836 	freedyncols(s);
13837 	s->cols = NULL;
13838 	s->ncols = 0;
13839 	s->nowchar[1] = 0;
13840 	s->one_tbl = -1;
13841 	s->has_pk = -1;
13842 	s->has_rowid = -1;
13843     }
13844 }
13845 
13846 /**
13847  * Reset bound columns to unbound state.
13848  * @param s statement pointer
13849  */
13850 
13851 static void
unbindcols(STMT * s)13852 unbindcols(STMT *s)
13853 {
13854     int i;
13855 
13856     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
13857 	s->bindcols[i].type = SQL_UNKNOWN_TYPE;
13858 	s->bindcols[i].max = 0;
13859 	s->bindcols[i].lenp = NULL;
13860 	s->bindcols[i].valp = NULL;
13861 	s->bindcols[i].index = i;
13862 	s->bindcols[i].offs = 0;
13863     }
13864 }
13865 
13866 /**
13867  * Reallocate space for bound columns.
13868  * @param s statement pointer
13869  * @param ncols number of columns
13870  * @result ODBC error code
13871  */
13872 
13873 static SQLRETURN
mkbindcols(STMT * s,int ncols)13874 mkbindcols(STMT *s, int ncols)
13875 {
13876     if (s->bindcols) {
13877 	if (s->nbindcols < ncols) {
13878 	    int i;
13879 	    BINDCOL *bindcols =
13880 		xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
13881 
13882 	    if (!bindcols) {
13883 		return nomem(s);
13884 	    }
13885 	    for (i = s->nbindcols; i < ncols; i++) {
13886 		bindcols[i].type = SQL_UNKNOWN_TYPE;
13887 		bindcols[i].max = 0;
13888 		bindcols[i].lenp = NULL;
13889 		bindcols[i].valp = NULL;
13890 		bindcols[i].index = i;
13891 		bindcols[i].offs = 0;
13892 	    }
13893 	    s->bindcols = bindcols;
13894 	    s->nbindcols = ncols;
13895 	}
13896     } else if (ncols > 0) {
13897 	s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
13898 	if (!s->bindcols) {
13899 	    return nomem(s);
13900 	}
13901 	s->nbindcols = ncols;
13902 	unbindcols(s);
13903     }
13904     return SQL_SUCCESS;
13905 }
13906 
13907 /**
13908  * Internal function to retrieve row data, used by SQLFetch() and
13909  * friends and SQLGetData().
13910  * @param s statement pointer
13911  * @param col column number, 0 based
13912  * @param otype output data type
13913  * @param val output buffer
13914  * @param len length of output buffer
13915  * @param lenp output length
13916  * @param partial flag for partial data retrieval
13917  * @result ODBC error code
13918  */
13919 
13920 static SQLRETURN
getrowdata(STMT * s,SQLUSMALLINT col,SQLSMALLINT otype,SQLPOINTER val,SQLINTEGER len,SQLLEN * lenp,int partial)13921 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
13922 	   SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp, int partial)
13923 {
13924     char **data, valdummy[16];
13925     SQLLEN dummy;
13926     SQLINTEGER *ilenp = NULL;
13927     int valnull = 0;
13928     int type = otype;
13929     SQLRETURN sret = SQL_NO_DATA;
13930 
13931     if (!lenp) {
13932 	lenp = &dummy;
13933     }
13934     /* workaround for JDK 1.7.0 on x86_64 */
13935     if (((SQLINTEGER *) lenp) + 1 == (SQLINTEGER *) val) {
13936 	ilenp = (SQLINTEGER *) lenp;
13937 	lenp = &dummy;
13938     }
13939     if (col >= s->ncols) {
13940 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
13941 	return SQL_ERROR;
13942     }
13943     if (s->retr_data != SQL_RD_ON) {
13944 	return SQL_SUCCESS;
13945     }
13946     if (!s->rows) {
13947 	*lenp = SQL_NULL_DATA;
13948 	goto done;
13949     }
13950     if (s->rowp < 0 || s->rowp >= s->nrows) {
13951 	*lenp = SQL_NULL_DATA;
13952 	goto done;
13953     }
13954     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0,
13955 		      s->nowchar[0]);
13956 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
13957     /* MS Access hack part 3 (map SQL_C_DEFAULT to SQL_C_CHAR) */
13958     if (type == SQL_C_WCHAR && otype == SQL_C_DEFAULT) {
13959 	type = SQL_C_CHAR;
13960     }
13961 #endif
13962     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
13963     if (!val) {
13964 	valnull = 1;
13965 	val = (SQLPOINTER) valdummy;
13966     }
13967     if (*data == NULL) {
13968 	*lenp = SQL_NULL_DATA;
13969 	switch (type) {
13970 	case SQL_C_UTINYINT:
13971 	case SQL_C_TINYINT:
13972 	case SQL_C_STINYINT:
13973 #ifdef SQL_BIT
13974 	case SQL_C_BIT:
13975 #endif
13976 	    *((SQLCHAR *) val) = 0;
13977 	    break;
13978 	case SQL_C_USHORT:
13979 	case SQL_C_SHORT:
13980 	case SQL_C_SSHORT:
13981 	    *((SQLSMALLINT *) val) = 0;
13982 	    break;
13983 	case SQL_C_ULONG:
13984 	case SQL_C_LONG:
13985 	case SQL_C_SLONG:
13986 	    *((SQLINTEGER *) val) = 0;
13987 	    break;
13988 #ifdef SQL_BIGINT
13989 	case SQL_C_SBIGINT:
13990 	case SQL_C_UBIGINT:
13991 	    *((SQLBIGINT *) val) = 0;
13992 	    break;
13993 #endif
13994 	case SQL_C_FLOAT:
13995 	    *((float *) val) = 0;
13996 	    break;
13997 	case SQL_C_DOUBLE:
13998 	    *((double *) val) = 0;
13999 	    break;
14000 	case SQL_C_BINARY:
14001 	case SQL_C_CHAR:
14002 	    if (len > 0) {
14003 		*((SQLCHAR *) val) = '\0';
14004 	    }
14005 	    break;
14006 #ifdef WCHARSUPPORT
14007 	case SQL_C_WCHAR:
14008 	    if (len > 0) {
14009 		*((SQLWCHAR *) val) = '\0';
14010 	    }
14011 	    break;
14012 #endif
14013 #ifdef SQL_C_TYPE_DATE
14014 	case SQL_C_TYPE_DATE:
14015 #endif
14016 	case SQL_C_DATE:
14017 	    memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
14018 	    break;
14019 #ifdef SQL_C_TYPE_TIME
14020 	case SQL_C_TYPE_TIME:
14021 #endif
14022 	case SQL_C_TIME:
14023 	    memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
14024 	    break;
14025 #ifdef SQL_C_TYPE_TIMESTAMP
14026 	case SQL_C_TYPE_TIMESTAMP:
14027 #endif
14028 	case SQL_C_TIMESTAMP:
14029 	    memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
14030 	    break;
14031 	default:
14032 	    return SQL_ERROR;
14033 	}
14034     } else {
14035 	char *endp = NULL;
14036 #if defined(_WIN32) || defined(_WIN64)
14037 #ifdef SQL_BIGINT
14038 	char endc;
14039 #endif
14040 #endif
14041 
14042 	switch (type) {
14043 	case SQL_C_UTINYINT:
14044 	case SQL_C_TINYINT:
14045 	case SQL_C_STINYINT:
14046 	    *((SQLCHAR *) val) = strtol(*data, &endp, 0);
14047 	    if (endp && endp == *data) {
14048 		*lenp = SQL_NULL_DATA;
14049 	    } else {
14050 		*lenp = sizeof (SQLCHAR);
14051 	    }
14052 	    break;
14053 #ifdef SQL_BIT
14054 	case SQL_C_BIT:
14055 	    *((SQLCHAR *) val) = getbool(*data);
14056 	    *lenp = sizeof (SQLCHAR);
14057 	    break;
14058 #endif
14059 	case SQL_C_USHORT:
14060 	case SQL_C_SHORT:
14061 	case SQL_C_SSHORT:
14062 	    *((SQLSMALLINT *) val) = strtol(*data, &endp, 0);
14063 	    if (endp && endp == *data) {
14064 		*lenp = SQL_NULL_DATA;
14065 	    } else {
14066 		*lenp = sizeof (SQLSMALLINT);
14067 	    }
14068 	    break;
14069 	case SQL_C_ULONG:
14070 	case SQL_C_LONG:
14071 	case SQL_C_SLONG:
14072 	    *((SQLINTEGER *) val) = strtol(*data, &endp, 0);
14073 	    if (endp && endp == *data) {
14074 		*lenp = SQL_NULL_DATA;
14075 	    } else {
14076 		*lenp = sizeof (SQLINTEGER);
14077 	    }
14078 	    break;
14079 #ifdef SQL_BIGINT
14080 	case SQL_C_UBIGINT:
14081 #if defined(_WIN32) || defined(_WIN64)
14082 	    if (sscanf(*data, "%I64u%c", (SQLUBIGINT *) val, &endc) != 1) {
14083 		*lenp = SQL_NULL_DATA;
14084 	    } else {
14085 		*lenp = sizeof (SQLUBIGINT);
14086 	    }
14087 #else
14088 #ifdef __osf__
14089 	    *((SQLUBIGINT *) val) = strtoul(*data, &endp, 0);
14090 #else
14091 	    *((SQLUBIGINT *) val) = strtoull(*data, &endp, 0);
14092 #endif
14093 	    if (endp && endp == *data) {
14094 		*lenp = SQL_NULL_DATA;
14095 	    } else {
14096 		*lenp = sizeof (SQLUBIGINT);
14097 	    }
14098 #endif
14099 	    break;
14100 	case SQL_C_SBIGINT:
14101 #if defined(_WIN32) || defined(_WIN64)
14102 	    if (sscanf(*data, "%I64d%c", (SQLBIGINT *) val, &endc) != 1) {
14103 		*lenp = SQL_NULL_DATA;
14104 	    } else {
14105 		*lenp = sizeof (SQLBIGINT);
14106 	    }
14107 #else
14108 #ifdef __osf__
14109 	    *((SQLBIGINT *) val) = strtol(*data, &endp, 0);
14110 #else
14111 	    *((SQLBIGINT *) val) = strtoll(*data, &endp, 0);
14112 #endif
14113 	    if (endp && endp == *data) {
14114 		*lenp = SQL_NULL_DATA;
14115 	    } else {
14116 		*lenp = sizeof (SQLBIGINT);
14117 	    }
14118 #endif
14119 	    break;
14120 #endif
14121 	case SQL_C_FLOAT:
14122 	    *((float *) val) = ln_strtod(*data, &endp);
14123 	    if (endp && endp == *data) {
14124 		*lenp = SQL_NULL_DATA;
14125 	    } else {
14126 		*lenp = sizeof (float);
14127 	    }
14128 	    break;
14129 	case SQL_C_DOUBLE:
14130 	    *((double *) val) = ln_strtod(*data, &endp);
14131 	    if (endp && endp == *data) {
14132 		*lenp = SQL_NULL_DATA;
14133 	    } else {
14134 		*lenp = sizeof (double);
14135 	    }
14136 	    break;
14137 	case SQL_C_BINARY: {
14138 	    int dlen, offs = 0;
14139 	    char *bin;
14140 
14141 	    if (valnull) {
14142 		freep(&s->bincache);
14143 		s->binlen = 0;
14144 		goto doCHAR;
14145 	    }
14146 	    if (*data == s->bincell) {
14147 		if (s->bincache) {
14148 		    bin = s->bincache;
14149 		    dlen = s->binlen;
14150 		} else {
14151 		    goto doCHAR;
14152 		}
14153 	    } else {
14154 		char *dp;
14155 		int i;
14156 
14157 		freep(&s->bincache);
14158 		dp = *data;
14159 		dlen = strlen(dp);
14160 		s->bincell = dp;
14161 		s->binlen = 0;
14162 		if (!(dp[0] == 'x' || dp[0] == 'X') || dp[1] != '\'' ||
14163 		    dp[dlen - 1] != '\'') {
14164 		    goto doCHAR;
14165 		}
14166 		dlen -= 2;
14167 		dp += 2;
14168 		dlen = dlen / 2;
14169 		s->bincache = bin = xmalloc(dlen + 1);
14170 		if (!bin) {
14171 		    return nomem(s);
14172 		}
14173 		s->binlen = dlen;
14174 		memset(bin, 0, dlen);
14175 		bin[dlen] = '\0';	/* terminator, just in case */
14176 		for (i = 0; i < dlen; i++) {
14177 		    char *x;
14178 		    int v;
14179 
14180 		    if (!*dp || !(x = strchr(xdigits, *dp))) {
14181 			goto converr;
14182 		    }
14183 		    v = x - xdigits;
14184 		    bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
14185 		    ++dp;
14186 		    if (!*dp || !(x = strchr(xdigits, *dp))) {
14187 converr:
14188 			freep(&s->bincache);
14189 			s->binlen = 0;
14190 			setstat(s, -1, "conversion error",
14191 				(*s->ov3) ? "HY000" : "S1000");
14192 			return SQL_ERROR;
14193 		    }
14194 		    v = x - xdigits;
14195 		    bin[i] |= (v >= 16) ? (v - 6) : v;
14196 		    ++dp;
14197 		}
14198 		bin = s->bincache;
14199 	    }
14200 	    if (partial && len && s->bindcols) {
14201 		if (s->bindcols[col].offs >= dlen) {
14202 		    *lenp = 0;
14203 		    if (!dlen && s->bindcols[col].offs == dlen) {
14204 			s->bindcols[col].offs = 1;
14205 			sret = SQL_SUCCESS;
14206 			goto done;
14207 		    }
14208 		    s->bindcols[col].offs = 0;
14209 		    sret = SQL_NO_DATA;
14210 		    goto done;
14211 		}
14212 		offs = s->bindcols[col].offs;
14213 		dlen -= offs;
14214 	    }
14215 	    if (val && len) {
14216 		memcpy(val, bin + offs, min(len, dlen));
14217 	    }
14218 	    if (len < 1) {
14219 		*lenp = dlen;
14220 	    } else {
14221 		*lenp = min(len, dlen);
14222 		if (*lenp == len && *lenp != dlen) {
14223 		    *lenp = SQL_NO_TOTAL;
14224 		}
14225 	    }
14226 	    if (partial && len && s->bindcols) {
14227 		if (*lenp == SQL_NO_TOTAL) {
14228 		    *lenp = dlen;
14229 		    s->bindcols[col].offs += len;
14230 		    setstat(s, -1, "data right truncated", "01004");
14231 		    if (s->bindcols[col].lenp) {
14232 			*s->bindcols[col].lenp = dlen;
14233 		    }
14234 		    sret = SQL_SUCCESS_WITH_INFO;
14235 		    goto done;
14236 		}
14237 		s->bindcols[col].offs += *lenp;
14238 	    }
14239 	    if (*lenp == SQL_NO_TOTAL) {
14240 		*lenp = dlen;
14241 		setstat(s, -1, "data right truncated", "01004");
14242 		sret = SQL_SUCCESS_WITH_INFO;
14243 		goto done;
14244 	    }
14245 	    break;
14246 	}
14247 	doCHAR:
14248 #ifdef WCHARSUPPORT
14249 	case SQL_C_WCHAR:
14250 #endif
14251 	case SQL_C_CHAR: {
14252 	    int doz, zlen = len - 1;
14253 	    int dlen = strlen(*data);
14254 	    int offs = 0;
14255 #ifdef WCHARSUPPORT
14256 	    SQLWCHAR *ucdata = NULL;
14257 	    SQLCHAR *cdata = (SQLCHAR *) *data;
14258 #endif
14259 
14260 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
14261 	    /* MS Access hack part 2 (reserved error -7748) */
14262 	    if (!valnull &&
14263 		(s->cols == statSpec2P || s->cols == statSpec3P) &&
14264 		type == SQL_C_WCHAR) {
14265 		if (len > 0 && len <= sizeof (SQLWCHAR)) {
14266 		    ((char *) val)[0] = data[0][0];
14267 		    memset((char *) val + 1, 0, len - 1);
14268 		    *lenp = 1;
14269 		    sret = SQL_SUCCESS;
14270 		    goto done;
14271 		}
14272 	    }
14273 #endif
14274 
14275 #ifdef WCHARSUPPORT
14276 	    switch (type) {
14277 	    case SQL_C_CHAR:
14278 		doz = 1;
14279 		break;
14280 	    case SQL_C_WCHAR:
14281 		doz = sizeof (SQLWCHAR);
14282 		break;
14283 	    default:
14284 		doz = 0;
14285 		break;
14286 	    }
14287 	    if (type == SQL_C_WCHAR) {
14288 		ucdata = uc_from_utf(cdata, dlen);
14289 		if (!ucdata) {
14290 		    return nomem(s);
14291 		}
14292 		dlen = uc_strlen(ucdata) * sizeof (SQLWCHAR);
14293 	    }
14294 #if defined(_WIN32) || defined(_WIN64)
14295 	    else if (*s->oemcp && type == SQL_C_CHAR) {
14296 		ucdata = (SQLWCHAR *) utf_to_wmb((char *) cdata, dlen);
14297 		if (!ucdata) {
14298 		    return nomem(s);
14299 		}
14300 		cdata = (SQLCHAR *) ucdata;
14301 		dlen = strlen((char *) cdata);
14302 	    }
14303 #endif
14304 #else
14305 	    doz = (type == SQL_C_CHAR) ? 1 : 0;
14306 #endif
14307 	    if (partial && len && s->bindcols) {
14308 		if (s->bindcols[col].offs >= dlen) {
14309 #ifdef WCHARSUPPORT
14310 		    uc_free(ucdata);
14311 #endif
14312 		    *lenp = 0;
14313 		    if (doz && val) {
14314 #ifdef WCHARSUPPORT
14315 			if (type == SQL_C_WCHAR) {
14316 			    ((SQLWCHAR *) val)[0] = 0;
14317 			} else {
14318 			    ((char *) val)[0] = '\0';
14319 			}
14320 #else
14321 			((char *) val)[0] = '\0';
14322 #endif
14323 		    }
14324 		    if (!dlen && s->bindcols[col].offs == dlen) {
14325 			s->bindcols[col].offs = 1;
14326 			sret = SQL_SUCCESS;
14327 			goto done;
14328 		    }
14329 		    s->bindcols[col].offs = 0;
14330 		    sret = SQL_NO_DATA;
14331 		    goto done;
14332 		}
14333 		offs = s->bindcols[col].offs;
14334 		dlen -= offs;
14335 	    }
14336 	    if (val && !valnull && len) {
14337 #ifdef WCHARSUPPORT
14338 		if (type == SQL_C_WCHAR) {
14339 		    uc_strncpy(val, ucdata + offs / sizeof (SQLWCHAR),
14340 			       (len - doz) / sizeof (SQLWCHAR));
14341 		} else {
14342 		    strncpy(val, (char *) cdata + offs, len - doz);
14343 		}
14344 #else
14345 		strncpy(val, *data + offs, len - doz);
14346 #endif
14347 	    }
14348 	    if (valnull || len < 1) {
14349 		*lenp = dlen;
14350 	    } else {
14351 		*lenp = min(len - doz, dlen);
14352 		if (*lenp == len - doz && *lenp != dlen) {
14353 		    *lenp = SQL_NO_TOTAL;
14354 		} else if (*lenp < zlen) {
14355 		    zlen = *lenp;
14356 		}
14357 	    }
14358 	    if (len && !valnull && doz) {
14359 #ifdef WCHARSUPPORT
14360 		if (type == SQL_C_WCHAR) {
14361 		    ((SQLWCHAR *) val)[zlen / sizeof (SQLWCHAR)] = 0;
14362 		} else {
14363 		    ((char *) val)[zlen] = '\0';
14364 		}
14365 #else
14366 		((char *) val)[zlen] = '\0';
14367 #endif
14368 	    }
14369 #ifdef WCHARSUPPORT
14370 	    uc_free(ucdata);
14371 #endif
14372 	    if (partial && len && s->bindcols) {
14373 		if (*lenp == SQL_NO_TOTAL) {
14374 		    *lenp = dlen;
14375 		    s->bindcols[col].offs += len - doz;
14376 		    setstat(s, -1, "data right truncated", "01004");
14377 		    if (s->bindcols[col].lenp) {
14378 			*s->bindcols[col].lenp = dlen;
14379 		    }
14380 		    sret = SQL_SUCCESS_WITH_INFO;
14381 		    goto done;
14382 		}
14383 		s->bindcols[col].offs += *lenp;
14384 	    }
14385 	    if (*lenp == SQL_NO_TOTAL) {
14386 		*lenp = dlen;
14387 		setstat(s, -1, "data right truncated", "01004");
14388 		sret = SQL_SUCCESS_WITH_INFO;
14389 		goto done;
14390 	    }
14391 	    break;
14392 	}
14393 #ifdef SQL_C_TYPE_DATE
14394 	case SQL_C_TYPE_DATE:
14395 #endif
14396 	case SQL_C_DATE:
14397 	    if (str2date(*s->jdconv, *data, (DATE_STRUCT *) val) < 0) {
14398 		*lenp = SQL_NULL_DATA;
14399 	    } else {
14400 		*lenp = sizeof (DATE_STRUCT);
14401 	    }
14402 	    break;
14403 #ifdef SQL_C_TYPE_TIME
14404 	case SQL_C_TYPE_TIME:
14405 #endif
14406 	case SQL_C_TIME:
14407 	    if (str2time(*s->jdconv, *data, (TIME_STRUCT *) val) < 0) {
14408 		*lenp = SQL_NULL_DATA;
14409 	    } else {
14410 		*lenp = sizeof (TIME_STRUCT);
14411 	    }
14412 	    break;
14413 #ifdef SQL_C_TYPE_TIMESTAMP
14414 	case SQL_C_TYPE_TIMESTAMP:
14415 #endif
14416 	case SQL_C_TIMESTAMP:
14417 	    if (str2timestamp(*s->jdconv, *data,
14418 			      (TIMESTAMP_STRUCT *) val) < 0) {
14419 		*lenp = SQL_NULL_DATA;
14420 	    } else {
14421 		*lenp = sizeof (TIMESTAMP_STRUCT);
14422 	    }
14423 	    switch (s->cols[col].prec) {
14424 	    case 0:
14425 		((TIMESTAMP_STRUCT *) val)->fraction = 0;
14426 		break;
14427 	    case 1:
14428 		((TIMESTAMP_STRUCT *) val)->fraction /= 100000000;
14429 		((TIMESTAMP_STRUCT *) val)->fraction *= 100000000;
14430 		break;
14431 	    case 2:
14432 		((TIMESTAMP_STRUCT *) val)->fraction /= 10000000;
14433 		((TIMESTAMP_STRUCT *) val)->fraction *= 10000000;
14434 		break;
14435 	    }
14436 	    break;
14437 	default:
14438 	    return SQL_ERROR;
14439 	}
14440     }
14441     sret = SQL_SUCCESS;
14442 done:
14443     if (ilenp) {
14444 	*ilenp = *lenp;
14445     }
14446     return sret;
14447 }
14448 
14449 /**
14450  * Internal bind C variable to column of result set.
14451  * @param stmt statement handle
14452  * @param col column number, starting at 1
14453  * @param type output type
14454  * @param val output buffer
14455  * @param max length of output buffer
14456  * @param lenp output length pointer
14457  * @result ODBC error code
14458  */
14459 
14460 static SQLRETURN
drvbindcol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)14461 drvbindcol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
14462 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
14463 {
14464     STMT *s;
14465     int sz = 0;
14466 
14467     if (stmt == SQL_NULL_HSTMT) {
14468 	return SQL_INVALID_HANDLE;
14469     }
14470     s = (STMT *) stmt;
14471     if (col < 1) {
14472 	if (col == 0 && s->bkmrk == SQL_UB_ON &&
14473 	    type == SQL_C_BOOKMARK) {
14474 	    s->bkmrkcol.type = val ? type : SQL_UNKNOWN_TYPE;
14475 	    s->bkmrkcol.max = val ? sizeof (SQLINTEGER) : 0;
14476 	    s->bkmrkcol.lenp = val ? lenp : 0;
14477 	    s->bkmrkcol.valp = val;
14478 	    s->bkmrkcol.offs = 0;
14479 	    if (val && lenp) {
14480 		*lenp = 0;
14481 	    }
14482 	    return SQL_SUCCESS;
14483 	} else if (col == 0 && s->bkmrk == SQL_UB_VARIABLE &&
14484 		   type == SQL_C_VARBOOKMARK &&
14485 		   max >= sizeof (sqlite_int64)) {
14486 	    s->bkmrkcol.type = val ? type : SQL_UNKNOWN_TYPE;
14487 	    s->bkmrkcol.max = val ? max : 0;
14488 	    s->bkmrkcol.lenp = val ? lenp : 0;
14489 	    s->bkmrkcol.valp = val;
14490 	    s->bkmrkcol.offs = 0;
14491 	    if (val && lenp) {
14492 		*lenp = 0;
14493 	    }
14494 	    return SQL_SUCCESS;
14495 	}
14496 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
14497 	return SQL_ERROR;
14498     }
14499     if (mkbindcols(s, col) != SQL_SUCCESS) {
14500 	return SQL_ERROR;
14501     }
14502     --col;
14503     if (type == SQL_C_DEFAULT) {
14504 	type = mapdeftype(type, s->cols[col].type, 0,
14505 			  s->nowchar[0] || s->nowchar[1]);
14506     }
14507     switch (type) {
14508     case SQL_C_LONG:
14509     case SQL_C_ULONG:
14510     case SQL_C_SLONG:
14511 	sz = sizeof (SQLINTEGER);
14512 	break;
14513     case SQL_C_TINYINT:
14514     case SQL_C_UTINYINT:
14515     case SQL_C_STINYINT:
14516 	sz = sizeof (SQLCHAR);
14517 	break;
14518     case SQL_C_SHORT:
14519     case SQL_C_USHORT:
14520     case SQL_C_SSHORT:
14521 	sz = sizeof (SQLSMALLINT);
14522 	break;
14523     case SQL_C_FLOAT:
14524 	sz = sizeof (SQLFLOAT);
14525 	break;
14526     case SQL_C_DOUBLE:
14527 	sz = sizeof (SQLDOUBLE);
14528 	break;
14529     case SQL_C_TIMESTAMP:
14530 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
14531 	break;
14532     case SQL_C_TIME:
14533 	sz = sizeof (SQL_TIME_STRUCT);
14534 	break;
14535     case SQL_C_DATE:
14536 	sz = sizeof (SQL_DATE_STRUCT);
14537 	break;
14538     case SQL_C_CHAR:
14539 	break;
14540 #ifdef WCHARSUPPORT
14541     case SQL_C_WCHAR:
14542 	break;
14543 #endif
14544 #ifdef SQL_C_TYPE_DATE
14545     case SQL_C_TYPE_DATE:
14546 	sz = sizeof (SQL_DATE_STRUCT);
14547 	break;
14548 #endif
14549 #ifdef SQL_C_TYPE_TIME
14550     case SQL_C_TYPE_TIME:
14551 	sz = sizeof (SQL_TIME_STRUCT);
14552 	break;
14553 #endif
14554 #ifdef SQL_C_TYPE_TIMESTAMP
14555     case SQL_C_TYPE_TIMESTAMP:
14556 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
14557 	break;
14558 #endif
14559 #ifdef SQL_BIT
14560     case SQL_C_BIT:
14561 	sz = sizeof (SQLCHAR);
14562 	break;
14563 #endif
14564     case SQL_C_BINARY:
14565 	break;
14566 #ifdef SQL_BIGINT
14567     case SQL_C_SBIGINT:
14568     case SQL_C_UBIGINT:
14569 	sz = sizeof (SQLBIGINT);
14570 	break;
14571 #endif
14572     default:
14573 	if (val == NULL) {
14574 	    /* fall through, unbinding column */
14575 	    break;
14576 	}
14577 	setstat(s, -1, "invalid type %d", "HY003", type);
14578 	return SQL_ERROR;
14579     }
14580     if (val == NULL) {
14581 	/* unbind column */
14582 	s->bindcols[col].type = SQL_UNKNOWN_TYPE;
14583 	s->bindcols[col].max = 0;
14584 	s->bindcols[col].lenp = NULL;
14585 	s->bindcols[col].valp = NULL;
14586 	s->bindcols[col].offs = 0;
14587     } else {
14588 	if (sz == 0 && max < 0) {
14589 	    setstat(s, -1, "invalid length", "HY090");
14590 	    return SQL_ERROR;
14591 	}
14592 	s->bindcols[col].type = type;
14593 	s->bindcols[col].max = (sz == 0) ? max : sz;
14594 	s->bindcols[col].lenp = lenp;
14595 	s->bindcols[col].valp = val;
14596 	s->bindcols[col].offs = 0;
14597 	if (lenp) {
14598 	    *lenp = 0;
14599 	}
14600     }
14601     return SQL_SUCCESS;
14602 }
14603 
14604 /**
14605  * Bind C variable to column of result set.
14606  * @param stmt statement handle
14607  * @param col column number, starting at 1
14608  * @param type output type
14609  * @param val output buffer
14610  * @param max length of output buffer
14611  * @param lenp output length pointer
14612  * @result ODBC error code
14613  */
14614 
14615 SQLRETURN SQL_API
SQLBindCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)14616 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
14617 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
14618 {
14619     SQLRETURN ret;
14620 
14621     HSTMT_LOCK(stmt);
14622     ret = drvbindcol(stmt, col, type, val, max, lenp);
14623     HSTMT_UNLOCK(stmt);
14624     return ret;
14625 }
14626 
14627 /**
14628  * Columns for result set of SQLTables().
14629  */
14630 
14631 static COL tableSpec2[] = {
14632     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
14633     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
14634     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
14635     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
14636     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
14637 };
14638 
14639 static COL tableSpec3[] = {
14640     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
14641     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
14642     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
14643     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
14644     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
14645 };
14646 
14647 /**
14648  * Retrieve information on tables and/or views.
14649  * @param stmt statement handle
14650  * @param cat catalog name/pattern or NULL
14651  * @param catLen length of catalog name/pattern or SQL_NTS
14652  * @param schema schema name/pattern or NULL
14653  * @param schemaLen length of schema name/pattern or SQL_NTS
14654  * @param table table name/pattern or NULL
14655  * @param tableLen length of table name/pattern or SQL_NTS
14656  * @param type types of tables string or NULL
14657  * @param typeLen length of types of tables string or SQL_NTS
14658  * @result ODBC error code
14659  */
14660 
14661 static SQLRETURN
drvtables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)14662 drvtables(SQLHSTMT stmt,
14663 	  SQLCHAR *cat, SQLSMALLINT catLen,
14664 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
14665 	  SQLCHAR *table, SQLSMALLINT tableLen,
14666 	  SQLCHAR *type, SQLSMALLINT typeLen)
14667 {
14668     SQLRETURN ret;
14669     STMT *s;
14670     DBC *d;
14671     int ncols, asize, rc, size, npatt;
14672     char *errp = NULL, *sql, tname[512];
14673     char *where = "(type = 'table' or type = 'view')";
14674 
14675     ret = mkresultset(stmt, tableSpec2, array_size(tableSpec2),
14676 		      tableSpec3, array_size(tableSpec3), &asize);
14677     if (ret != SQL_SUCCESS) {
14678 	return ret;
14679     }
14680     s = (STMT *) stmt;
14681     d = (DBC *) s->dbc;
14682     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
14683 	int size = 3 * asize;
14684 
14685 	s->rows = xmalloc(size * sizeof (char *));
14686 	if (!s->rows) {
14687 	    s->nrows = 0;
14688 	    return nomem(s);
14689 	}
14690 	memset(s->rows, 0, sizeof (char *) * size);
14691 	s->ncols = asize;
14692 	s->rows[s->ncols + 0] = "";
14693 	s->rows[s->ncols + 1] = "";
14694 	s->rows[s->ncols + 2] = "";
14695 	s->rows[s->ncols + 3] = "TABLE";
14696 	s->rows[s->ncols + 5] = "";
14697 	s->rows[s->ncols + 6] = "";
14698 	s->rows[s->ncols + 7] = "";
14699 	s->rows[s->ncols + 8] = "VIEW";
14700 #ifdef MEMORY_DEBUG
14701 	s->rowfree = xfree__;
14702 #else
14703 	s->rowfree = sqlite3_free;
14704 #endif
14705 	s->nrows = 2;
14706 	s->rowp = s->rowprs = -1;
14707 	return SQL_SUCCESS;
14708     }
14709     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
14710 	table = NULL;
14711 	goto doit;
14712     }
14713     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
14714 	schema[0] == '%') {
14715 	if ((!cat || catLen == 0 || !cat[0]) &&
14716 	    (!table || tableLen == 0 || !table[0])) {
14717 	    table = NULL;
14718 	    goto doit;
14719 	}
14720     }
14721     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] != '\0') {
14722 	char tmp[256], *t;
14723 	int with_view = 0, with_table = 0;
14724 
14725 	if (typeLen == SQL_NTS) {
14726 	    strncpy(tmp, (char *) type, sizeof (tmp));
14727 	    tmp[sizeof (tmp) - 1] = '\0';
14728 	} else {
14729 	    int len = min(sizeof (tmp) - 1, typeLen);
14730 
14731 	    strncpy(tmp, (char *) type, len);
14732 	    tmp[len] = '\0';
14733 	}
14734 	t = tmp;
14735 	while (*t) {
14736 	    *t = TOLOWER(*t);
14737 	    t++;
14738 	}
14739 	t = tmp;
14740 	unescpat(t);
14741 	while (t) {
14742 	    if (t[0] == '\'') {
14743 		++t;
14744 	    }
14745 	    if (strncmp(t, "table", 5) == 0) {
14746 		with_table++;
14747 	    } else if (strncmp(t, "view", 4) == 0) {
14748 		with_view++;
14749 	    }
14750 	    t = strchr(t, ',');
14751 	    if (t) {
14752 		++t;
14753 	    }
14754 	}
14755 	if (with_view && with_table) {
14756 	    /* where is already preset */
14757 	} else if (with_view && !with_table) {
14758 	    where = "type = 'view'";
14759 	} else if (!with_view && with_table) {
14760 	    where = "type = 'table'";
14761 	} else {
14762 	    return SQL_SUCCESS;
14763 	}
14764     }
14765 doit:
14766     if (!table) {
14767 	size = 1;
14768 	tname[0] = '%';
14769     } else {
14770 	if (tableLen == SQL_NTS) {
14771 	    size = sizeof (tname) - 1;
14772 	} else {
14773 	    size = min(sizeof (tname) - 1, tableLen);
14774 	}
14775 	strncpy(tname, (char *) table, size);
14776     }
14777     tname[size] = '\0';
14778     npatt = unescpat(tname);
14779 #if defined(_WIN32) || defined(_WIN64)
14780     if (npatt) {
14781 	sql = sqlite3_mprintf("select %s as 'TABLE_CAT', "
14782 			      "%s as 'TABLE_SCHEM', "
14783 			      "tbl_name as 'TABLE_NAME', "
14784 			      "upper(type) as 'TABLE_TYPE', "
14785 			      "NULL as 'REMARKS' "
14786 			      "from sqlite_master where %s "
14787 			      "and tbl_name like %Q",
14788 			      d->xcelqrx ? "'main'" : "NULL",
14789 			      d->xcelqrx ? "''" : "NULL",
14790 			      where, tname);
14791     } else {
14792 	sql = sqlite3_mprintf("select %s as 'TABLE_CAT', "
14793 			      "%s as 'TABLE_SCHEM', "
14794 			      "tbl_name as 'TABLE_NAME', "
14795 			      "upper(type) as 'TABLE_TYPE', "
14796 			      "NULL as 'REMARKS' "
14797 			      "from sqlite_master where %s "
14798 			      "and lower(tbl_name) = lower(%Q)",
14799 			      d->xcelqrx ? "'main'" : "NULL",
14800 			      d->xcelqrx ? "''" : "NULL",
14801 			      where, tname);
14802     }
14803 #else
14804     if (npatt) {
14805 	sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
14806 			      "NULL as 'TABLE_OWNER', "
14807 			      "tbl_name as 'TABLE_NAME', "
14808 			      "upper(type) as 'TABLE_TYPE', "
14809 			      "NULL as 'REMARKS' "
14810 			      "from sqlite_master where %s "
14811 			      "and tbl_name like %Q",
14812 			      where, tname);
14813     } else {
14814 	sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
14815 			      "NULL as 'TABLE_OWNER', "
14816 			      "tbl_name as 'TABLE_NAME', "
14817 			      "upper(type) as 'TABLE_TYPE', "
14818 			      "NULL as 'REMARKS' "
14819 			      "from sqlite_master where %s "
14820 			      "and lower(tbl_name) = lower(%Q)",
14821 			      where, tname);
14822     }
14823 #endif
14824     if (!sql) {
14825 	return nomem(s);
14826     }
14827     ret = starttran(s);
14828     if (ret != SQL_SUCCESS) {
14829 	sqlite3_free(sql);
14830 	return ret;
14831     }
14832     dbtraceapi(d, "sqlite3_get_table", sql);
14833     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
14834     sqlite3_free(sql);
14835     if (rc == SQLITE_OK) {
14836 	if (ncols != s->ncols) {
14837 	    freeresult(s, 0);
14838 	    s->nrows = 0;
14839 	} else {
14840 	    s->rowfree = sqlite3_free_table;
14841 	}
14842     } else {
14843 	s->nrows = 0;
14844 	s->rows = NULL;
14845 	s->rowfree = NULL;
14846     }
14847     if (errp) {
14848 	sqlite3_free(errp);
14849 	errp = NULL;
14850     }
14851     s->rowp = s->rowprs = -1;
14852     return SQL_SUCCESS;
14853 }
14854 
14855 #ifndef WINTERFACE
14856 /**
14857  * Retrieve information on tables and/or views.
14858  * @param stmt statement handle
14859  * @param cat catalog name/pattern or NULL
14860  * @param catLen length of catalog name/pattern or SQL_NTS
14861  * @param schema schema name/pattern or NULL
14862  * @param schemaLen length of schema name/pattern or SQL_NTS
14863  * @param table table name/pattern or NULL
14864  * @param tableLen length of table name/pattern or SQL_NTS
14865  * @param type types of tables string or NULL
14866  * @param typeLen length of types of tables string or SQL_NTS
14867  * @result ODBC error code
14868  */
14869 
14870 SQLRETURN SQL_API
SQLTables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)14871 SQLTables(SQLHSTMT stmt,
14872 	  SQLCHAR *cat, SQLSMALLINT catLen,
14873 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
14874 	  SQLCHAR *table, SQLSMALLINT tableLen,
14875 	  SQLCHAR *type, SQLSMALLINT typeLen)
14876 {
14877 #if defined(_WIN32) || defined(_WIN64)
14878     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
14879 #endif
14880     SQLRETURN ret;
14881 
14882     HSTMT_LOCK(stmt);
14883 #if defined(_WIN32) || defined(_WIN64)
14884     if (!((STMT *) stmt)->oemcp[0]) {
14885 	ret = drvtables(stmt, cat, catLen, schema, schemaLen,
14886 			table, tableLen, type, typeLen);
14887 	goto done2;
14888     }
14889     if (cat) {
14890 	c = wmb_to_utf_c((char *) cat, catLen);
14891 	if (!c) {
14892 	    ret = nomem((STMT *) stmt);
14893 	    goto done;
14894 	}
14895     }
14896     if (schema) {
14897 	s = wmb_to_utf_c((char *) schema, schemaLen);
14898 	if (!s) {
14899 	    ret = nomem((STMT *) stmt);
14900 	    goto done;
14901 	}
14902     }
14903     if (table) {
14904 	t = wmb_to_utf_c((char *) table, tableLen);
14905 	if (!t) {
14906 	    ret = nomem((STMT *) stmt);
14907 	    goto done;
14908 	}
14909     }
14910     if (type) {
14911 	y = wmb_to_utf_c((char *) type, typeLen);
14912 	if (!y) {
14913 	    ret = nomem((STMT *) stmt);
14914 	    goto done;
14915 	}
14916     }
14917     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14918 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
14919 #else
14920     ret = drvtables(stmt, cat, catLen, schema, schemaLen,
14921 		    table, tableLen, type, typeLen);
14922 #endif
14923 #if defined(_WIN32) || defined(_WIN64)
14924 done:
14925     uc_free(y);
14926     uc_free(t);
14927     uc_free(s);
14928     uc_free(c);
14929 done2:
14930     ;
14931 #endif
14932     HSTMT_UNLOCK(stmt);
14933     return ret;
14934 }
14935 #endif
14936 
14937 #ifdef WINTERFACE
14938 /**
14939  * Retrieve information on tables and/or views.
14940  * @param stmt statement handle
14941  * @param cat catalog name/pattern or NULL
14942  * @param catLen length of catalog name/pattern or SQL_NTS
14943  * @param schema schema name/pattern or NULL
14944  * @param schemaLen length of schema name/pattern or SQL_NTS
14945  * @param table table name/pattern or NULL
14946  * @param tableLen length of table name/pattern or SQL_NTS
14947  * @param type types of tables string or NULL
14948  * @param typeLen length of types of tables string or SQL_NTS
14949  * @result ODBC error code
14950  */
14951 
14952 SQLRETURN SQL_API
SQLTablesW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * type,SQLSMALLINT typeLen)14953 SQLTablesW(SQLHSTMT stmt,
14954 	   SQLWCHAR *cat, SQLSMALLINT catLen,
14955 	   SQLWCHAR *schema, SQLSMALLINT schemaLen,
14956 	   SQLWCHAR *table, SQLSMALLINT tableLen,
14957 	   SQLWCHAR *type, SQLSMALLINT typeLen)
14958 {
14959     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
14960     SQLRETURN ret;
14961 
14962     HSTMT_LOCK(stmt);
14963     if (cat) {
14964 	c = uc_to_utf_c(cat, catLen);
14965 	if (!c) {
14966 	    ret = nomem((STMT *) stmt);
14967 	    goto done;
14968 	}
14969     }
14970     if (schema) {
14971 	s = uc_to_utf_c(schema, schemaLen);
14972 	if (!s) {
14973 	    ret = nomem((STMT *) stmt);
14974 	    goto done;
14975 	}
14976     }
14977     if (table) {
14978 	t = uc_to_utf_c(table, tableLen);
14979 	if (!t) {
14980 	    ret = nomem((STMT *) stmt);
14981 	    goto done;
14982 	}
14983     }
14984     if (type) {
14985 	y = uc_to_utf_c(type, typeLen);
14986 	if (!y) {
14987 	    ret = nomem((STMT *) stmt);
14988 	    goto done;
14989 	}
14990     }
14991     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14992 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
14993 done:
14994     uc_free(y);
14995     uc_free(t);
14996     uc_free(s);
14997     uc_free(c);
14998     HSTMT_UNLOCK(stmt);
14999     return ret;
15000 }
15001 #endif
15002 
15003 /**
15004  * Columns for result set of SQLColumns().
15005  */
15006 
15007 static COL colSpec2[] = {
15008     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
15009     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
15010     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
15011     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
15012     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
15013     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
15014     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
15015     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
15016     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
15017     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
15018     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
15019     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
15020     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
15021     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
15022     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
15023     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
15024     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
15025     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
15026 };
15027 
15028 static COL colSpec3[] = {
15029     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
15030     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
15031     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
15032     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
15033     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
15034     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
15035     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
15036     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
15037     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_SMALLINT, 50 },
15038     { "SYSTEM", "COLUMN", "NUM_PREC_RADIX", SQL_SMALLINT, 50 },
15039     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
15040     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
15041     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
15042     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
15043     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
15044     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
15045     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
15046     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
15047 };
15048 
15049 /**
15050  * Internal retrieve column information on table.
15051  * @param stmt statement handle
15052  * @param cat catalog name/pattern or NULL
15053  * @param catLen length of catalog name/pattern or SQL_NTS
15054  * @param schema schema name/pattern or NULL
15055  * @param schemaLen length of schema name/pattern or SQL_NTS
15056  * @param table table name/pattern or NULL
15057  * @param tableLen length of table name/pattern or SQL_NTS
15058  * @param col column name/pattern or NULL
15059  * @param colLen length of column name/pattern or SQL_NTS
15060  * @result ODBC error code
15061  */
15062 
15063 static SQLRETURN
drvcolumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)15064 drvcolumns(SQLHSTMT stmt,
15065 	   SQLCHAR *cat, SQLSMALLINT catLen,
15066 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
15067 	   SQLCHAR *table, SQLSMALLINT tableLen,
15068 	   SQLCHAR *col, SQLSMALLINT colLen)
15069 {
15070     SQLRETURN sret;
15071     STMT *s;
15072     DBC *d;
15073     int ret, nrows, ncols, asize, i, k, roffs, namec;
15074     int tnrows, tncols, npatt;
15075     PTRDIFF_T size;
15076     char *errp = NULL, *sql, tname[512], cname[512], **rowp, **trows;
15077 
15078     sret = mkresultset(stmt, colSpec2, array_size(colSpec2),
15079 		       colSpec3, array_size(colSpec3), &asize);
15080     if (sret != SQL_SUCCESS) {
15081 	return sret;
15082     }
15083     s = (STMT *) stmt;
15084     d = (DBC *) s->dbc;
15085     if (!table) {
15086 	size = 1;
15087 	tname[0] = '%';
15088     } else {
15089 	if (tableLen == SQL_NTS) {
15090 	    size = sizeof (tname) - 1;
15091 	} else {
15092 	    size = min(sizeof (tname) - 1, tableLen);
15093 	}
15094 	strncpy(tname, (char *) table, size);
15095     }
15096     tname[size] = '\0';
15097     npatt = unescpat(tname);
15098     size = 0;
15099     if (col) {
15100 	if (colLen == SQL_NTS) {
15101 	    size = sizeof (cname) - 1;
15102 	} else {
15103 	    size = min(sizeof (cname) - 1, colLen);
15104 	}
15105 	strncpy(cname, (char *) col, size);
15106     }
15107     cname[size] = '\0';
15108     if (!strcmp(cname, "%")) {
15109 	cname[0] = '\0';
15110     }
15111     if (npatt) {
15112 	sql = sqlite3_mprintf("select tbl_name from sqlite_master where "
15113 			      "(type = 'table' or type = 'view') "
15114 			      "and tbl_name like %Q", tname);
15115     } else {
15116 	sql = sqlite3_mprintf("select tbl_name from sqlite_master where "
15117 			      "(type = 'table' or type = 'view') "
15118 			      "and lower(tbl_name) = lower(%Q)", tname);
15119     }
15120     if (!sql) {
15121 	return nomem(s);
15122     }
15123     sret = starttran(s);
15124     if (sret != SQL_SUCCESS) {
15125 	sqlite3_free(sql);
15126 	return sret;
15127     }
15128     dbtraceapi(d, "sqlite3_get_table", sql);
15129     ret = sqlite3_get_table(d->sqlite, sql, &trows, &tnrows, &tncols, &errp);
15130     sqlite3_free(sql);
15131     if (ret != SQLITE_OK) {
15132 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
15133 		errp ? errp : "unknown error", ret);
15134 	if (errp) {
15135 	    sqlite3_free(errp);
15136 	    errp = NULL;
15137 	}
15138 	return SQL_ERROR;
15139     }
15140     if (errp) {
15141 	sqlite3_free(errp);
15142 	errp = NULL;
15143     }
15144     /* pass 1: compute number of rows of result set */
15145     if (tncols * tnrows <= 0) {
15146 	sqlite3_free_table(trows);
15147 	return SQL_SUCCESS;
15148     }
15149     size = 0;
15150     for (i = 1; i <= tnrows; i++) {
15151 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", trows[i]);
15152 	if (!sql) {
15153 	    sqlite3_free_table(trows);
15154 	    return nomem(s);
15155 	}
15156 	dbtraceapi(d, "sqlite3_get_table", sql);
15157 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
15158 	sqlite3_free(sql);
15159 	if (ret != SQLITE_OK) {
15160 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
15161 		    errp ? errp : "unknown error", ret);
15162 	    if (errp) {
15163 		sqlite3_free(errp);
15164 		errp = NULL;
15165 	    }
15166 	    sqlite3_free_table(trows);
15167 	    return SQL_ERROR;
15168 	}
15169 	if (errp) {
15170 	    sqlite3_free(errp);
15171 	    errp = NULL;
15172 	}
15173 	if (ncols * nrows > 0) {
15174 	    namec = -1;
15175 	    for (k = 0; k < ncols; k++) {
15176 		if (strcmp(rowp[k], "name") == 0) {
15177 		    namec = k;
15178 		    break;
15179 		}
15180 	    }
15181 	    if (cname[0]) {
15182 		if (namec >= 0) {
15183 		    for (k = 1; k <= nrows; k++) {
15184 			if (namematch(rowp[k * ncols + namec], cname, 1)) {
15185 			    size++;
15186 			}
15187 		    }
15188 		}
15189 	    } else {
15190 		size += nrows;
15191 	    }
15192 	}
15193 	sqlite3_free_table(rowp);
15194     }
15195     /* pass 2: fill result set */
15196     if (size <= 0) {
15197 	sqlite3_free_table(trows);
15198 	return SQL_SUCCESS;
15199     }
15200     s->nrows = size;
15201     size = (size + 1) * asize;
15202     s->rows = xmalloc((size + 1) * sizeof (char *));
15203     if (!s->rows) {
15204 	s->nrows = 0;
15205 	sqlite3_free_table(trows);
15206 	return nomem(s);
15207     }
15208     s->rows[0] = (char *) size;
15209     s->rows += 1;
15210     memset(s->rows, 0, sizeof (char *) * size);
15211     s->rowfree = freerows;
15212     roffs = 1;
15213     for (i = 1; i <= tnrows; i++) {
15214 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", trows[i]);
15215 	if (!sql) {
15216 	    sqlite3_free_table(trows);
15217 	    return nomem(s);
15218 	}
15219 	dbtraceapi(d, "sqlite3_get_table", sql);
15220 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
15221 	sqlite3_free(sql);
15222 	if (ret != SQLITE_OK) {
15223 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
15224 		    errp ? errp : "unknown error", ret);
15225 	    if (errp) {
15226 		sqlite3_free(errp);
15227 		errp = NULL;
15228 	    }
15229 	    sqlite3_free_table(trows);
15230 	    return SQL_ERROR;
15231 	}
15232 	if (errp) {
15233 	    sqlite3_free(errp);
15234 	    errp = NULL;
15235 	}
15236 	if (ncols * nrows > 0) {
15237 	    int m, mr, nr = nrows;
15238 
15239 	    namec = -1;
15240 	    for (k = 0; k < ncols; k++) {
15241 		if (strcmp(rowp[k], "name") == 0) {
15242 		    namec = k;
15243 		    break;
15244 		}
15245 	    }
15246 	    if (cname[0]) {
15247 		nr = 0;
15248 		if (namec >= 0) {
15249 		    for (k = 1; k <= nrows; k++) {
15250 			if (namematch(rowp[k * ncols + namec], cname, 1)) {
15251 			    nr++;
15252 			}
15253 		    }
15254 		}
15255 	    }
15256 	    for (k = 0; k < nr; k++) {
15257 		m = asize * (roffs + k);
15258 #if defined(_WIN32) || defined(_WIN64)
15259 		s->rows[m + 0] = xstrdup(d->xcelqrx ? "main" : "");
15260 		s->rows[m + 1] = xstrdup("");
15261 #else
15262 		s->rows[m + 0] = xstrdup("");
15263 		s->rows[m + 1] = xstrdup("");
15264 #endif
15265 		s->rows[m + 2] = xstrdup(trows[i]);
15266 		s->rows[m + 8] = xstrdup("10");
15267 		s->rows[m + 9] = xstrdup("0");
15268 		s->rows[m + 15] = xstrdup("16384");
15269 	    }
15270 	    for (k = 0; nr && k < ncols; k++) {
15271 		if (strcmp(rowp[k], "cid") == 0) {
15272 		    for (mr = 0, m = 1; m <= nrows; m++) {
15273 			char buf[256];
15274 			int ir, coln = k;
15275 
15276 			if (cname[0] &&
15277 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
15278 			    continue;
15279 			}
15280 			ir = asize * (roffs + mr);
15281 			sscanf(rowp[m * ncols + k], "%d", &coln);
15282 			sprintf(buf, "%d", coln + 1);
15283 			s->rows[ir + 16] = xstrdup(buf);
15284 			++mr;
15285 		    }
15286 		} else if (k == namec) {
15287 		    for (mr = 0, m = 1; m <= nrows; m++) {
15288 			int ir;
15289 
15290 			if (cname[0] &&
15291 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
15292 			    continue;
15293 			}
15294 			ir = asize * (roffs + mr);
15295 			s->rows[ir + 3] = xstrdup(rowp[m * ncols + k]);
15296 			++mr;
15297 		    }
15298 		} else if (strcmp(rowp[k], "notnull") == 0) {
15299 		    for (mr = 0, m = 1; m <= nrows; m++) {
15300 			int ir;
15301 
15302 			if (cname[0] &&
15303 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
15304 			    continue;
15305 			}
15306 			ir = asize * (roffs + mr);
15307 			if (*rowp[m * ncols + k] != '0') {
15308 			    s->rows[ir + 10] = xstrdup(stringify(SQL_FALSE));
15309 			} else {
15310 			    s->rows[ir + 10] = xstrdup(stringify(SQL_TRUE));
15311 			}
15312 			s->rows[ir + 17] =
15313 			    xstrdup((*rowp[m * ncols + k] != '0') ?
15314 				    "NO" : "YES");
15315 			++mr;
15316 		    }
15317 		} else if (strcmp(rowp[k], "dflt_value") == 0) {
15318 		    for (mr = 0, m = 1; m <= nrows; m++) {
15319 			char *dflt = unquote(rowp[m * ncols + k]);
15320 			int ir;
15321 
15322 			if (cname[0] &&
15323 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
15324 			    continue;
15325 			}
15326 			ir = asize * (roffs + mr);
15327 			s->rows[ir + 12] = xstrdup(dflt ? dflt : "NULL");
15328 			++mr;
15329 		    }
15330 		} else if (strcmp(rowp[k], "type") == 0) {
15331 		    for (mr = 0, m = 1; m <= nrows; m++) {
15332 			char *typename = rowp[m * ncols + k];
15333 			int sqltype, mm, dd, ir;
15334 			char buf[256];
15335 
15336 			if (cname[0] &&
15337 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
15338 			    continue;
15339 			}
15340 			ir = asize * (roffs + mr);
15341 			s->rows[ir + 5] = xstrdup(typename);
15342 			sqltype = mapsqltype(typename, NULL, *s->ov3,
15343 					     s->nowchar[0], s->dobigint);
15344 			getmd(typename, sqltype, &mm, &dd);
15345 #ifdef SQL_LONGVARCHAR
15346 			if (sqltype == SQL_VARCHAR && mm > 255) {
15347 			    sqltype = SQL_LONGVARCHAR;
15348 			}
15349 #endif
15350 #ifdef WINTERFACE
15351 #ifdef SQL_WLONGVARCHAR
15352 			if (sqltype == SQL_WVARCHAR && mm > 255) {
15353 			    sqltype = SQL_WLONGVARCHAR;
15354 			}
15355 #endif
15356 #endif
15357 			if (sqltype == SQL_VARBINARY && mm > 255) {
15358 			    sqltype = SQL_LONGVARBINARY;
15359 			}
15360 			sprintf(buf, "%d", sqltype);
15361 			s->rows[ir + 4] = xstrdup(buf);
15362 			s->rows[ir + 13] = xstrdup(buf);
15363 			sprintf(buf, "%d", mm);
15364 			s->rows[ir + 7] = xstrdup(buf);
15365 			sprintf(buf, "%d", dd);
15366 			s->rows[ir + 6] = xstrdup(buf);
15367 			++mr;
15368 		    }
15369 		}
15370 	    }
15371 	    roffs += nr;
15372 	}
15373 	sqlite3_free_table(rowp);
15374     }
15375     sqlite3_free_table(trows);
15376     return SQL_SUCCESS;
15377 }
15378 
15379 #ifndef WINTERFACE
15380 /**
15381  * Retrieve column information on table.
15382  * @param stmt statement handle
15383  * @param cat catalog name/pattern or NULL
15384  * @param catLen length of catalog name/pattern or SQL_NTS
15385  * @param schema schema name/pattern or NULL
15386  * @param schemaLen length of schema name/pattern or SQL_NTS
15387  * @param table table name/pattern or NULL
15388  * @param tableLen length of table name/pattern or SQL_NTS
15389  * @param col column name/pattern or NULL
15390  * @param colLen length of column name/pattern or SQL_NTS
15391  * @result ODBC error code
15392  */
15393 
15394 SQLRETURN SQL_API
SQLColumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)15395 SQLColumns(SQLHSTMT stmt,
15396 	   SQLCHAR *cat, SQLSMALLINT catLen,
15397 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
15398 	   SQLCHAR *table, SQLSMALLINT tableLen,
15399 	   SQLCHAR *col, SQLSMALLINT colLen)
15400 {
15401 #if defined(_WIN32) || defined(_WIN64)
15402     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
15403 #endif
15404     SQLRETURN ret;
15405 
15406     HSTMT_LOCK(stmt);
15407 #if defined(_WIN32) || defined(_WIN64)
15408     if (!((STMT *) stmt)->oemcp[0]) {
15409 	ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
15410 			 table, tableLen, col, colLen);
15411 	goto done2;
15412     }
15413     if (cat) {
15414 	c = wmb_to_utf_c((char *) cat, catLen);
15415 	if (!c) {
15416 	    ret = nomem((STMT *) stmt);
15417 	    goto done;
15418 	}
15419     }
15420     if (schema) {
15421 	s = wmb_to_utf_c((char *) schema, schemaLen);
15422 	if (!s) {
15423 	    ret = nomem((STMT *) stmt);
15424 	    goto done;
15425 	}
15426     }
15427     if (table) {
15428 	t = wmb_to_utf_c((char *) table, tableLen);
15429 	if (!t) {
15430 	    ret = nomem((STMT *) stmt);
15431 	    goto done;
15432 	}
15433     }
15434     if (col) {
15435 	k = wmb_to_utf_c((char *) col, colLen);
15436 	if (!k) {
15437 	    ret = nomem((STMT *) stmt);
15438 	    goto done;
15439 	}
15440     }
15441     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
15442 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
15443 #else
15444     ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
15445 		     table, tableLen, col, colLen);
15446 #endif
15447 #if defined(_WIN32) || defined(_WIN64)
15448 done:
15449     uc_free(k);
15450     uc_free(t);
15451     uc_free(s);
15452     uc_free(c);
15453 done2:
15454     ;
15455 #endif
15456     HSTMT_UNLOCK(stmt);
15457     return ret;
15458 }
15459 #endif
15460 
15461 #ifdef WINTERFACE
15462 /**
15463  * Retrieve column information on table (UNICODE version).
15464  * @param stmt statement handle
15465  * @param cat catalog name/pattern or NULL
15466  * @param catLen length of catalog name/pattern or SQL_NTS
15467  * @param schema schema name/pattern or NULL
15468  * @param schemaLen length of schema name/pattern or SQL_NTS
15469  * @param table table name/pattern or NULL
15470  * @param tableLen length of table name/pattern or SQL_NTS
15471  * @param col column name/pattern or NULL
15472  * @param colLen length of column name/pattern or SQL_NTS
15473  * @result ODBC error code
15474  */
15475 
15476 SQLRETURN SQL_API
SQLColumnsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * col,SQLSMALLINT colLen)15477 SQLColumnsW(SQLHSTMT stmt,
15478 	    SQLWCHAR *cat, SQLSMALLINT catLen,
15479 	    SQLWCHAR *schema, SQLSMALLINT schemaLen,
15480 	    SQLWCHAR *table, SQLSMALLINT tableLen,
15481 	    SQLWCHAR *col, SQLSMALLINT colLen)
15482 {
15483     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
15484     SQLRETURN ret;
15485 
15486     HSTMT_LOCK(stmt);
15487     if (cat) {
15488 	c = uc_to_utf_c(cat, catLen);
15489 	if (!c) {
15490 	    ret = nomem((STMT *) stmt);
15491 	    goto done;
15492 	}
15493     }
15494     if (schema) {
15495 	s = uc_to_utf_c(schema, schemaLen);
15496 	if (!s) {
15497 	    ret = nomem((STMT *) stmt);
15498 	    goto done;
15499 	}
15500     }
15501     if (table) {
15502 	t = uc_to_utf_c(table, tableLen);
15503 	if (!t) {
15504 	    ret = nomem((STMT *) stmt);
15505 	    goto done;
15506 	}
15507     }
15508     if (col) {
15509 	k = uc_to_utf_c(col, colLen);
15510 	if (!k) {
15511 	    ret = nomem((STMT *) stmt);
15512 	    goto done;
15513 	}
15514     }
15515     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
15516 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
15517 done:
15518     uc_free(k);
15519     uc_free(t);
15520     uc_free(s);
15521     uc_free(c);
15522     HSTMT_UNLOCK(stmt);
15523     return ret;
15524 
15525 }
15526 #endif
15527 
15528 /**
15529  * Columns for result set of SQLGetTypeInfo().
15530  */
15531 
15532 static COL typeSpec2[] = {
15533     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
15534     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
15535     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 9 },
15536     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
15537     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
15538     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
15539     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
15540     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
15541     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
15542     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
15543     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
15544     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
15545     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
15546     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
15547     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
15548 };
15549 
15550 static COL typeSpec3[] = {
15551     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
15552     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
15553     { "SYSTEM", "TYPE", "COLUMN_SIZE", SQL_INTEGER, 9 },
15554     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
15555     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
15556     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
15557     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
15558     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
15559     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
15560     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
15561     { "SYSTEM", "TYPE", "FIXED_PREC_SCALE", SQL_SMALLINT, 2 },
15562     { "SYSTEM", "TYPE", "AUTO_UNIQUE_VALUE", SQL_SMALLINT, 2 },
15563     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
15564     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
15565     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 },
15566     { "SYSTEM", "TYPE", "SQL_DATA_TYPE", SQL_SMALLINT, 2 },
15567     { "SYSTEM", "TYPE", "SQL_DATETIME_SUB", SQL_SMALLINT, 2 },
15568     { "SYSTEM", "TYPE", "NUM_PREC_RADIX", SQL_INTEGER, 4 },
15569     { "SYSTEM", "TYPE", "INTERVAL_PRECISION", SQL_SMALLINT, 2 }
15570 };
15571 
15572 /**
15573  * Internal function to build up data type information as row in result set.
15574  * @param s statement pointer
15575  * @param row row number
15576  * @param asize number of items in a row
15577  * @param typename name of type
15578  * @param type integer SQL type
15579  * @param tind type index
15580  */
15581 
15582 static void
mktypeinfo(STMT * s,int row,int asize,char * typename,int type,int tind)15583 mktypeinfo(STMT *s, int row, int asize, char *typename, int type, int tind)
15584 {
15585     int offs = row * asize;
15586     char *tcode, *crpar = NULL, *sign = stringify(SQL_FALSE);
15587     char *quote[2] = { NULL, NULL };
15588     static char tcodes[32 * 32];
15589 
15590     if (tind <= 0) {
15591 	tind = row;
15592     }
15593     tcode = tcodes + tind * 32;
15594     sprintf(tcode, "%d", type);
15595     s->rows[offs + 0] = typename;
15596     s->rows[offs + 1] = tcode;
15597     if (asize >= 17) {
15598 	s->rows[offs + 15] = tcode;
15599 	s->rows[offs + 16] = "0";
15600     }
15601     switch (type) {
15602     default:
15603 #ifdef SQL_LONGVARCHAR
15604     case SQL_LONGVARCHAR:
15605 #ifdef WINTERFACE
15606     case SQL_WLONGVARCHAR:
15607 #endif
15608 	crpar = "length";
15609 	quote[0] = quote[1] = "'";
15610 	sign = NULL;
15611 	s->rows[offs + 2] = "65536";
15612 	break;
15613 #endif
15614 #ifdef SQL_BIT
15615     case SQL_BIT:
15616 	sign = NULL;
15617 	s->rows[offs + 2] = "1";
15618 	break;
15619 #endif
15620     case SQL_CHAR:
15621     case SQL_VARCHAR:
15622 #ifdef WINTERFACE
15623     case SQL_WCHAR:
15624     case SQL_WVARCHAR:
15625 #endif
15626 	s->rows[offs + 2] = "255";
15627 	crpar = "length";
15628 	quote[0] = quote[1] = "'";
15629 	sign = NULL;
15630 	break;
15631     case SQL_TINYINT:
15632 	s->rows[offs + 2] = "3";
15633 	break;
15634     case SQL_SMALLINT:
15635 	s->rows[offs + 2] = "5";
15636 	break;
15637     case SQL_INTEGER:
15638 	s->rows[offs + 2] = "9";
15639 	break;
15640 #ifdef SQL_BIGINT
15641     case SQL_BIGINT:
15642 	s->rows[offs + 2] = "19";
15643 	break;
15644 #endif
15645     case SQL_FLOAT:
15646 	s->rows[offs + 2] = "7";
15647 	break;
15648     case SQL_DOUBLE:
15649 	s->rows[offs + 2] = "15";
15650 	break;
15651 #ifdef SQL_TYPE_DATE
15652     case SQL_TYPE_DATE:
15653 #endif
15654     case SQL_DATE:
15655 	s->rows[offs + 2] = "10";
15656 	quote[0] = quote[1] = "'";
15657 	sign = NULL;
15658 	break;
15659 #ifdef SQL_TYPE_TIME
15660     case SQL_TYPE_TIME:
15661 #endif
15662     case SQL_TIME:
15663 	s->rows[offs + 2] = "8";
15664 	quote[0] = quote[1] = "'";
15665 	sign = NULL;
15666 	break;
15667 #ifdef SQL_TYPE_TIMESTAMP
15668     case SQL_TYPE_TIMESTAMP:
15669 #endif
15670     case SQL_TIMESTAMP:
15671 	s->rows[offs + 2] = "32";
15672 	quote[0] = quote[1] = "'";
15673 	sign = NULL;
15674 	break;
15675     case SQL_VARBINARY:
15676 	quote[0] = "0x";
15677 	sign = NULL;
15678 	s->rows[offs + 2] = "255";
15679 	break;
15680     case SQL_LONGVARBINARY:
15681 	quote[0] = "0x";
15682 	sign = NULL;
15683 	s->rows[offs + 2] = "65536";
15684 	break;
15685     }
15686     s->rows[offs + 3] = quote[0];
15687     s->rows[offs + 4] = quote[1];
15688     s->rows[offs + 5] = crpar;
15689     s->rows[offs + 6] = stringify(SQL_NULLABLE);
15690     s->rows[offs + 7] = stringify(SQL_FALSE);
15691     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
15692     s->rows[offs + 9] = sign;
15693     s->rows[offs + 10] = stringify(SQL_FALSE);
15694     s->rows[offs + 11] = stringify(SQL_FALSE);
15695     s->rows[offs + 12] = typename;
15696     switch (type) {
15697     case SQL_DATE:
15698     case SQL_TIME:
15699 	s->rows[offs + 13] = "0";
15700 	s->rows[offs + 14] = "0";
15701 	break;
15702 #ifdef SQL_TYPE_TIMESTAMP
15703     case SQL_TYPE_TIMESTAMP:
15704 #endif
15705     case SQL_TIMESTAMP:
15706 	s->rows[offs + 13] = "0";
15707 	s->rows[offs + 14] = "3";
15708 	break;
15709     default:
15710 	s->rows[offs + 13] = NULL;
15711 	s->rows[offs + 14] = NULL;
15712 	break;
15713     }
15714 }
15715 
15716 /**
15717  * Helper function to sort type information.
15718  * Callback for qsort().
15719  * @param a first item to compare
15720  * @param b second item to compare
15721  * @result ==0, <0, >0 according to data type number
15722  */
15723 
15724 static int
typeinfosort(const void * a,const void * b)15725 typeinfosort(const void *a, const void *b)
15726 {
15727     char **pa = (char **) a;
15728     char **pb = (char **) b;
15729     int na, nb;
15730 
15731     na = strtol(pa[1], NULL, 0);
15732     nb = strtol(pb[1], NULL, 0);
15733     return na - nb;
15734 }
15735 
15736 /**
15737  * Internal return data type information.
15738  * @param stmt statement handle
15739  * @param sqltype which type to retrieve
15740  * @result ODBC error code
15741  */
15742 
15743 static SQLRETURN
drvgettypeinfo(SQLHSTMT stmt,SQLSMALLINT sqltype)15744 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
15745 {
15746     SQLRETURN ret;
15747     STMT *s;
15748     int asize;
15749 
15750     ret = mkresultset(stmt, typeSpec2, array_size(typeSpec2),
15751 		      typeSpec3, array_size(typeSpec3), &asize);
15752     if (ret != SQL_SUCCESS) {
15753 	return ret;
15754     }
15755     s = (STMT *) stmt;
15756 #ifdef SQL_LONGVARCHAR
15757     s->nrows = (sqltype == SQL_ALL_TYPES) ? 13 : 1;
15758 #else
15759     s->nrows = (sqltype == SQL_ALL_TYPES) ? 12 : 1;
15760 #endif
15761     if (sqltype == SQL_ALL_TYPES) {
15762 #ifdef WINTERFACE
15763 	s->nrows += 2;
15764 #ifdef SQL_WLONGVARCHAR
15765 	s->nrows += 2;
15766 #endif
15767 #endif
15768     }
15769     if (sqltype == SQL_ALL_TYPES) {
15770 	s->nrows += 2;
15771 #ifdef SQL_BIT
15772 	s->nrows += 1;
15773 #endif
15774 #ifdef SQL_BIGINT
15775 	s->nrows += 1;
15776 #endif
15777     }
15778     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1) * asize);
15779     if (!s->rows) {
15780 	s->nrows = 0;
15781 	return nomem(s);
15782     }
15783 #ifdef MEMORY_DEBUG
15784     s->rowfree = xfree__;
15785 #else
15786     s->rowfree = sqlite3_free;
15787 #endif
15788     memset(s->rows, 0, sizeof (char *) * (s->nrows + 1) * asize);
15789     if (sqltype == SQL_ALL_TYPES) {
15790 	int cc = 1;
15791 
15792 	mktypeinfo(s, cc++, asize, "varchar", SQL_VARCHAR, 0);
15793 	mktypeinfo(s, cc++, asize, "tinyint", SQL_TINYINT, 0);
15794 	mktypeinfo(s, cc++, asize, "smallint", SQL_SMALLINT, 0);
15795 	mktypeinfo(s, cc++, asize, "integer", SQL_INTEGER, 0);
15796 	mktypeinfo(s, cc++, asize, "float", SQL_FLOAT, 0);
15797 	mktypeinfo(s, cc++, asize, "double", SQL_DOUBLE, 0);
15798 #ifdef SQL_TYPE_DATE
15799 	mktypeinfo(s, cc++, asize, "date",
15800 		   (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
15801 #else
15802 	mktypeinfo(s, cc++, asize, "date", SQL_DATE, 0);
15803 #endif
15804 #ifdef SQL_TYPE_TIME
15805 	mktypeinfo(s, cc++, asize, "time",
15806 		   (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
15807 #else
15808 	mktypeinfo(s, cc++, asize, "time", SQL_TIME, 0);
15809 #endif
15810 #ifdef SQL_TYPE_TIMESTAMP
15811 	mktypeinfo(s, cc++, asize, "timestamp",
15812 		   (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
15813 #else
15814 	mktypeinfo(s, cc++, asize, "timestamp", SQL_TIMESTAMP, 0);
15815 #endif
15816 	mktypeinfo(s, cc++, asize, "char", SQL_CHAR, 0);
15817 	mktypeinfo(s, cc++, asize, "numeric", SQL_DOUBLE, 0);
15818 #ifdef SQL_LONGVARCHAR
15819 	mktypeinfo(s, cc++, asize, "text", SQL_LONGVARCHAR, 0);
15820 	mktypeinfo(s, cc++, asize, "longvarchar", SQL_LONGVARCHAR, 0);
15821 #else
15822 	mktypeinfo(s, cc++, asize, "text", SQL_VARCHAR, 0);
15823 #endif
15824 	mktypeinfo(s, cc++, asize, "varbinary", SQL_VARBINARY, 0);
15825 	mktypeinfo(s, cc++, asize, "longvarbinary", SQL_LONGVARBINARY, 0);
15826 #ifdef SQL_BIT
15827 	mktypeinfo(s, cc++, asize, "bit", SQL_BIT, 0);
15828 #endif
15829 #ifdef SQL_BIGINT
15830 	mktypeinfo(s, cc++, asize, "bigint", SQL_BIGINT, 0);
15831 #endif
15832 #ifdef WINTERFACE
15833 	mktypeinfo(s, cc++, asize, "wvarchar", SQL_WVARCHAR, 0);
15834 	mktypeinfo(s, cc++, asize, "wchar", SQL_WCHAR, 0);
15835 #ifdef SQL_WLONGVARCHAR
15836 	mktypeinfo(s, cc++, asize, "wtext", SQL_WLONGVARCHAR, 0);
15837 	mktypeinfo(s, cc++, asize, "longwvarchar", SQL_WLONGVARCHAR, 0);
15838 #endif
15839 #endif
15840 	qsort(s->rows + asize, s->nrows, sizeof (char *) * asize,
15841 	      typeinfosort);
15842     } else {
15843 	switch (sqltype) {
15844 	case SQL_CHAR:
15845 	    mktypeinfo(s, 1, asize, "char", SQL_CHAR, 10);
15846 	    break;
15847 	case SQL_VARCHAR:
15848 	    mktypeinfo(s, 1, asize, "varchar", SQL_VARCHAR, 1);
15849 	    break;
15850 	case SQL_TINYINT:
15851 	    mktypeinfo(s, 1, asize, "tinyint", SQL_TINYINT, 2);
15852 	    break;
15853 	case SQL_SMALLINT:
15854 	    mktypeinfo(s, 1, asize, "smallint", SQL_SMALLINT, 3);
15855 	    break;
15856 	case SQL_INTEGER:
15857 	    mktypeinfo(s, 1, asize, "integer", SQL_INTEGER, 4);
15858 	    break;
15859 	case SQL_FLOAT:
15860 	    mktypeinfo(s, 1, asize, "float", SQL_FLOAT, 5);
15861 	    break;
15862 	case SQL_DOUBLE:
15863 	    mktypeinfo(s, 1, asize, "double", SQL_DOUBLE, 6);
15864 	    break;
15865 #ifdef SQL_TYPE_DATE
15866 	case SQL_TYPE_DATE:
15867 	    mktypeinfo(s, 1, asize, "date", SQL_TYPE_DATE, 25);
15868 	    break;
15869 #endif
15870 	case SQL_DATE:
15871 	    mktypeinfo(s, 1, asize, "date", SQL_DATE, 7);
15872 	    break;
15873 #ifdef SQL_TYPE_TIME
15874 	case SQL_TYPE_TIME:
15875 	    mktypeinfo(s, 1, asize, "time", SQL_TYPE_TIME, 26);
15876 	    break;
15877 #endif
15878 	case SQL_TIME:
15879 	    mktypeinfo(s, 1, asize, "time", SQL_TIME, 8);
15880 	    break;
15881 #ifdef SQL_TYPE_TIMESTAMP
15882 	case SQL_TYPE_TIMESTAMP:
15883 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TYPE_TIMESTAMP, 27);
15884 	    break;
15885 #endif
15886 	case SQL_TIMESTAMP:
15887 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TIMESTAMP, 9);
15888 	    break;
15889 #ifdef SQL_LONGVARCHAR
15890 	case SQL_LONGVARCHAR:
15891 	    mktypeinfo(s, 1, asize, "longvarchar", SQL_LONGVARCHAR, 12);
15892 	    break;
15893 #endif
15894 	case SQL_VARBINARY:
15895 	    mktypeinfo(s, 1, asize, "varbinary", SQL_VARBINARY, 30);
15896 	    break;
15897 	case SQL_LONGVARBINARY:
15898 	    mktypeinfo(s, 1, asize, "longvarbinary", SQL_LONGVARBINARY, 31);
15899 	    break;
15900 #ifdef SQL_BIT
15901 	case SQL_BIT:
15902 	    mktypeinfo(s, 1, asize, "bit", SQL_BIT, 29);
15903 	    break;
15904 #endif
15905 #ifdef SQL_BIGINT
15906 	case SQL_BIGINT:
15907 	    mktypeinfo(s, 1, asize, "bigint", SQL_BIGINT, 28);
15908 	    break;
15909 #endif
15910 #ifdef WINTERFACE
15911 #ifdef SQL_WCHAR
15912 	case SQL_WCHAR:
15913 	    mktypeinfo(s, 1, asize, "wchar", SQL_WCHAR, 18);
15914 	    break;
15915 #endif
15916 #ifdef SQL_WVARCHAR
15917 	case SQL_WVARCHAR:
15918 	    mktypeinfo(s, 1, asize, "wvarchar", SQL_WVARCHAR, 19);
15919 	    break;
15920 #endif
15921 #ifdef SQL_WLONGVARCHAR
15922 	case SQL_WLONGVARCHAR:
15923 	    mktypeinfo(s, 1, asize, "longwvarchar", SQL_WLONGVARCHAR, 20);
15924 	    break;
15925 #endif
15926 #endif
15927 	default:
15928 	    s->nrows = 0;
15929 	}
15930     }
15931     return SQL_SUCCESS;
15932 }
15933 
15934 #ifndef WINTERFACE
15935 /**
15936  * Return data type information.
15937  * @param stmt statement handle
15938  * @param sqltype which type to retrieve
15939  * @result ODBC error code
15940  */
15941 
15942 SQLRETURN SQL_API
SQLGetTypeInfo(SQLHSTMT stmt,SQLSMALLINT sqltype)15943 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
15944 {
15945     SQLRETURN ret;
15946 
15947     HSTMT_LOCK(stmt);
15948     ret = drvgettypeinfo(stmt, sqltype);
15949     HSTMT_UNLOCK(stmt);
15950     return ret;
15951 }
15952 #endif
15953 
15954 #ifdef WINTERFACE
15955 /**
15956  * Return data type information (UNICODE version).
15957  * @param stmt statement handle
15958  * @param sqltype which type to retrieve
15959  * @result ODBC error code
15960  */
15961 
15962 SQLRETURN SQL_API
SQLGetTypeInfoW(SQLHSTMT stmt,SQLSMALLINT sqltype)15963 SQLGetTypeInfoW(SQLHSTMT stmt, SQLSMALLINT sqltype)
15964 {
15965     SQLRETURN ret;
15966 
15967     HSTMT_LOCK(stmt);
15968     ret = drvgettypeinfo(stmt, sqltype);
15969     HSTMT_UNLOCK(stmt);
15970     return ret;
15971 }
15972 #endif
15973 
15974 /**
15975  * Columns for result set of SQLStatistics().
15976  */
15977 
15978 static COL statSpec2[] = {
15979     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
15980     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
15981     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
15982     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
15983     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
15984     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
15985     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
15986     { "SYSTEM", "STATISTICS", "SEQ_IN_INDEX", SQL_SMALLINT, 50 },
15987     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
15988     { "SYSTEM", "STATISTICS", "COLLATION", SCOL_CHAR, 1 },
15989     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
15990     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
15991     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
15992 };
15993 
15994 static COL statSpec3[] = {
15995     { "SYSTEM", "STATISTICS", "TABLE_CAT", SCOL_VARCHAR, 50 },
15996     { "SYSTEM", "STATISTICS", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
15997     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
15998     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
15999     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
16000     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
16001     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
16002     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
16003     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
16004     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
16005     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
16006     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
16007     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
16008 };
16009 
16010 /**
16011  * Internal return statistic information on table indices.
16012  * @param stmt statement handle
16013  * @param cat catalog name/pattern or NULL
16014  * @param catLen length of catalog name/pattern or SQL_NTS
16015  * @param schema schema name/pattern or NULL
16016  * @param schemaLen length of schema name/pattern or SQL_NTS
16017  * @param table table name/pattern or NULL
16018  * @param tableLen length of table name/pattern or SQL_NTS
16019  * @param itype type of index information
16020  * @param resv reserved
16021  * @result ODBC error code
16022  */
16023 
16024 static SQLRETURN
drvstatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)16025 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
16026 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
16027 	      SQLCHAR *table, SQLSMALLINT tableLen,
16028 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
16029 {
16030     SQLRETURN sret;
16031     STMT *s;
16032     DBC *d;
16033     int i, asize, ret, nrows, ncols, offs, namec, uniquec, addipk = 0;
16034     PTRDIFF_T size;
16035     char **rowp, *errp = NULL, *sql, tname[512];
16036 
16037     sret = mkresultset(stmt, statSpec2, array_size(statSpec2),
16038 		       statSpec3, array_size(statSpec3), &asize);
16039     if (sret != SQL_SUCCESS) {
16040 	return sret;
16041     }
16042     s = (STMT *) stmt;
16043     d = (DBC *) s->dbc;
16044     if (!table || table[0] == '\0' || table[0] == '%') {
16045 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
16046 	return SQL_ERROR;
16047     }
16048     if (tableLen == SQL_NTS) {
16049 	size = sizeof (tname) - 1;
16050     } else {
16051 	size = min(sizeof (tname) - 1, tableLen);
16052     }
16053     strncpy(tname, (char *) table, size);
16054     tname[size] = '\0';
16055     unescpat(tname);
16056     sret = starttran(s);
16057     if (sret != SQL_SUCCESS) {
16058 	return sret;
16059     }
16060     /*
16061      * Try integer primary key (autoincrement) first
16062      */
16063     if (itype == SQL_INDEX_UNIQUE || itype == SQL_INDEX_ALL) {
16064 	rowp = 0;
16065 	ret = SQLITE_ERROR;
16066 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
16067 	if (sql) {
16068 	    dbtraceapi(d, "sqlite3_get_table", sql);
16069 	    ret = sqlite3_get_table(d->sqlite, sql, &rowp,
16070 				    &nrows, &ncols, NULL);
16071 	    sqlite3_free(sql);
16072 	}
16073 	if (ret == SQLITE_OK) {
16074 	    int colid, typec, npk = 0, npkint = 0;
16075 
16076 	    namec = findcol(rowp, ncols, "name");
16077 	    uniquec = findcol(rowp, ncols, "pk");
16078 	    typec = findcol(rowp, ncols, "type");
16079 	    colid = findcol(rowp, ncols, "cid");
16080 	    if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
16081 		goto noipk;
16082 	    }
16083 	    for (i = 1; i <= nrows; i++) {
16084 		if (*rowp[i * ncols + uniquec] != '0') {
16085 		    npk++;
16086 		    if (strlen(rowp[i * ncols + typec]) == 7 &&
16087 			strncasecmp(rowp[i * ncols + typec], "integer", 7)
16088 			== 0) {
16089 			npkint++;
16090 		    }
16091 		}
16092 	    }
16093 	    if (npkint == 1 && npk == npkint) {
16094 		addipk = 1;
16095 	    }
16096 	}
16097 noipk:
16098 	sqlite3_free_table(rowp);
16099     }
16100     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
16101     if (!sql) {
16102 	return nomem(s);
16103     }
16104     dbtraceapi(d, "sqlite3_get_table", sql);
16105     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
16106     sqlite3_free(sql);
16107     if (ret != SQLITE_OK) {
16108 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
16109 		errp ? errp : "unknown error", ret);
16110 	if (errp) {
16111 	    sqlite3_free(errp);
16112 	    errp = NULL;
16113 	}
16114 	return SQL_ERROR;
16115     }
16116     if (errp) {
16117 	sqlite3_free(errp);
16118 	errp = NULL;
16119     }
16120     size = 0;
16121     namec = findcol(rowp, ncols, "name");
16122     uniquec = findcol(rowp, ncols, "unique");
16123     if (namec < 0 || uniquec < 0) {
16124 	goto nodata;
16125     }
16126     for (i = 1; i <= nrows; i++) {
16127 	int nnrows, nncols;
16128 	char **rowpp;
16129 	int isuniq;
16130 
16131 	isuniq = *rowp[i * ncols + uniquec] != '0';
16132 	if (isuniq || itype == SQL_INDEX_ALL) {
16133 	    ret = SQLITE_ERROR;
16134 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
16135 				  rowp[i * ncols + namec]);
16136 	    if (sql) {
16137 		dbtraceapi(d, "sqlite3_get_table", sql);
16138 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
16139 					&nnrows, &nncols, NULL);
16140 		sqlite3_free(sql);
16141 	    }
16142 	    if (ret == SQLITE_OK) {
16143 		size += nnrows;
16144 		sqlite3_free_table(rowpp);
16145 	    }
16146 	}
16147     }
16148 nodata:
16149     if (addipk) {
16150 	size++;
16151     }
16152     if (size == 0) {
16153 	sqlite3_free_table(rowp);
16154 	return SQL_SUCCESS;
16155     }
16156     s->nrows = size;
16157     size = (size + 1) * asize;
16158     s->rows = xmalloc((size + 1) * sizeof (char *));
16159     if (!s->rows) {
16160 	s->nrows = 0;
16161 	return nomem(s);
16162     }
16163     s->rows[0] = (char *) size;
16164     s->rows += 1;
16165     memset(s->rows, 0, sizeof (char *) * size);
16166     s->rowfree = freerows;
16167     offs = 0;
16168     if (addipk) {
16169 	char **rowpp = 0;
16170 	int nrows2, ncols2;
16171 
16172 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
16173 	if (sql) {
16174 	    dbtraceapi(d, "sqlite3_get_table", sql);
16175 	    ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
16176 				    &nrows2, &ncols2, NULL);
16177 	    sqlite3_free(sql);
16178 	}
16179 	if (ret == SQLITE_OK) {
16180 	    int colid, typec, roffs, namecc, uniquecc;
16181 
16182 	    namecc = findcol(rowpp, ncols2, "name");
16183 	    uniquecc = findcol(rowpp, ncols2, "pk");
16184 	    typec = findcol(rowpp, ncols2, "type");
16185 	    colid = findcol(rowpp, ncols2, "cid");
16186 	    if (namecc < 0 || uniquecc < 0 || typec < 0 || colid < 0) {
16187 		addipk = 0;
16188 		s->nrows--;
16189 		goto nodata2;
16190 	    }
16191 	    for (i = 1; i <= nrows2; i++) {
16192 		if (*rowpp[i * ncols2 + uniquecc] != '0' &&
16193 		    strlen(rowpp[i * ncols2 + typec]) == 7 &&
16194 		    strncasecmp(rowpp[i * ncols2 + typec], "integer", 7)
16195 		    == 0) {
16196 		    break;
16197 		}
16198 	    }
16199 	    if (i > nrows2) {
16200 		addipk = 0;
16201 		s->nrows--;
16202 		goto nodata2;
16203 	    }
16204 	    roffs = s->ncols;
16205 #if defined(_WIN32) || defined(_WIN64)
16206 	    s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
16207 	    s->rows[roffs + 1] = xstrdup("");
16208 #else
16209 	    s->rows[roffs + 0] = xstrdup("");
16210 	    s->rows[roffs + 1] = xstrdup("");
16211 #endif
16212 	    s->rows[roffs + 2] = xstrdup(tname);
16213 	    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
16214 	    s->rows[roffs + 5] = xstrdup("sqlite_autoindex_0");
16215 	    s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
16216 	    s->rows[roffs + 7] = xstrdup("1");
16217 	    s->rows[roffs + 8] = xstrdup(rowpp[i * ncols2 + namecc]);
16218 	    s->rows[roffs + 9] = xstrdup("A");
16219 	}
16220 nodata2:
16221 	sqlite3_free_table(rowpp);
16222     }
16223     for (i = 1; i <= nrows; i++) {
16224 	int nnrows, nncols;
16225 	char **rowpp = 0;
16226 
16227 	if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
16228 	    int k;
16229 
16230 	    ret = SQLITE_ERROR;
16231 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
16232 				  rowp[i * ncols + namec]);
16233 	    if (sql) {
16234 		dbtraceapi(d, "sqlite3_get_table", sql);
16235 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
16236 					&nnrows, &nncols, NULL);
16237 		sqlite3_free(sql);
16238 	    }
16239 	    if (ret != SQLITE_OK) {
16240 		continue;
16241 	    }
16242 	    for (k = 0; nnrows && k < nncols; k++) {
16243 		if (strcmp(rowpp[k], "name") == 0) {
16244 		    int m;
16245 
16246 		    for (m = 1; m <= nnrows; m++) {
16247 			int roffs = (offs + addipk + m) * s->ncols;
16248 			int isuniq;
16249 
16250 			isuniq = *rowp[i * ncols + uniquec] != '0';
16251 			s->rows[roffs + 0] = xstrdup("");
16252 			s->rows[roffs + 1] = xstrdup("");
16253 			s->rows[roffs + 2] = xstrdup(tname);
16254 			if (isuniq) {
16255 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
16256 			} else {
16257 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
16258 			}
16259 			s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
16260 			s->rows[roffs + 6] =
16261 			    xstrdup(stringify(SQL_INDEX_OTHER));
16262 			s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
16263 			s->rows[roffs + 9] = xstrdup("A");
16264 		    }
16265 		} else if (strcmp(rowpp[k], "seqno") == 0) {
16266 		    int m;
16267 
16268 		    for (m = 1; m <= nnrows; m++) {
16269 			int roffs = (offs + addipk + m) * s->ncols;
16270 			int pos = m - 1;
16271 			char buf[32];
16272 
16273 			sscanf(rowpp[m * nncols + k], "%d", &pos);
16274 			sprintf(buf, "%d", pos + 1);
16275 			s->rows[roffs + 7] = xstrdup(buf);
16276 		    }
16277 		}
16278 	    }
16279 	    offs += nnrows;
16280 	    sqlite3_free_table(rowpp);
16281 	}
16282     }
16283     sqlite3_free_table(rowp);
16284     return SQL_SUCCESS;
16285 }
16286 
16287 #ifndef WINTERFACE
16288 /**
16289  * Return statistic information on table indices.
16290  * @param stmt statement handle
16291  * @param cat catalog name/pattern or NULL
16292  * @param catLen length of catalog name/pattern or SQL_NTS
16293  * @param schema schema name/pattern or NULL
16294  * @param schemaLen length of schema name/pattern or SQL_NTS
16295  * @param table table name/pattern or NULL
16296  * @param tableLen length of table name/pattern or SQL_NTS
16297  * @param itype type of index information
16298  * @param resv reserved
16299  * @result ODBC error code
16300  */
16301 
16302 SQLRETURN SQL_API
SQLStatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)16303 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
16304 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
16305 	      SQLCHAR *table, SQLSMALLINT tableLen,
16306 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
16307 {
16308 #if defined(_WIN32) || defined(_WIN64)
16309     char *c = NULL, *s = NULL, *t = NULL;
16310 #endif
16311     SQLRETURN ret;
16312 
16313     HSTMT_LOCK(stmt);
16314 #if defined(_WIN32) || defined(_WIN64)
16315     if (!((STMT *) stmt)->oemcp[0]) {
16316 	ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
16317 			    table, tableLen, itype, resv);
16318 	goto done2;
16319     }
16320     if (cat) {
16321 	c = wmb_to_utf_c((char *) cat, catLen);
16322 	if (!c) {
16323 	    ret = nomem((STMT *) stmt);
16324 	    goto done;
16325 	}
16326     }
16327     if (schema) {
16328 	s = wmb_to_utf_c((char *) schema, schemaLen);
16329 	if (!s) {
16330 	    ret = nomem((STMT *) stmt);
16331 	    goto done;
16332 	}
16333     }
16334     if (table) {
16335 	t = wmb_to_utf_c((char *) table, tableLen);
16336 	if (!t) {
16337 	    ret = nomem((STMT *) stmt);
16338 	    goto done;
16339 	}
16340     }
16341     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
16342 			(SQLCHAR *) t, SQL_NTS, itype, resv);
16343 #else
16344     ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
16345 			table, tableLen, itype, resv);
16346 #endif
16347 #if defined(_WIN32) || defined(_WIN64)
16348 done:
16349     uc_free(t);
16350     uc_free(s);
16351     uc_free(c);
16352 done2:
16353     ;
16354 #endif
16355     HSTMT_UNLOCK(stmt);
16356     return ret;
16357 }
16358 #endif
16359 
16360 #ifdef WINTERFACE
16361 /**
16362  * Return statistic information on table indices (UNICODE version).
16363  * @param stmt statement handle
16364  * @param cat catalog name/pattern or NULL
16365  * @param catLen length of catalog name/pattern or SQL_NTS
16366  * @param schema schema name/pattern or NULL
16367  * @param schemaLen length of schema name/pattern or SQL_NTS
16368  * @param table table name/pattern or NULL
16369  * @param tableLen length of table name/pattern or SQL_NTS
16370  * @param itype type of index information
16371  * @param resv reserved
16372  * @result ODBC error code
16373  */
16374 
16375 SQLRETURN SQL_API
SQLStatisticsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)16376 SQLStatisticsW(SQLHSTMT stmt, SQLWCHAR *cat, SQLSMALLINT catLen,
16377 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
16378 	       SQLWCHAR *table, SQLSMALLINT tableLen,
16379 	       SQLUSMALLINT itype, SQLUSMALLINT resv)
16380 {
16381     char *c = NULL, *s = NULL, *t = NULL;
16382     SQLRETURN ret;
16383 
16384     HSTMT_LOCK(stmt);
16385     if (cat) {
16386 	c = uc_to_utf_c(cat, catLen);
16387 	if (!c) {
16388 	    ret = nomem((STMT *) stmt);
16389 	    goto done;
16390 	}
16391     }
16392     if (schema) {
16393 	s = uc_to_utf_c(schema, schemaLen);
16394 	if (!s) {
16395 	    ret = nomem((STMT *) stmt);
16396 	    goto done;
16397 	}
16398     }
16399     if (table) {
16400 	t = uc_to_utf_c(table, tableLen);
16401 	if (!t) {
16402 	    ret = nomem((STMT *) stmt);
16403 	    goto done;
16404 	}
16405     }
16406     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
16407 			(SQLCHAR *) t, SQL_NTS, itype, resv);
16408 done:
16409     uc_free(t);
16410     uc_free(s);
16411     uc_free(c);
16412     HSTMT_UNLOCK(stmt);
16413     return ret;
16414 }
16415 #endif
16416 
16417 /**
16418  * Retrieve row data after fetch.
16419  * @param stmt statement handle
16420  * @param col column number, starting at 1
16421  * @param type output type
16422  * @param val output buffer
16423  * @param len length of output buffer
16424  * @param lenp output length
16425  * @result ODBC error code
16426  */
16427 
16428 SQLRETURN SQL_API
SQLGetData(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN len,SQLLEN * lenp)16429 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
16430 	   SQLPOINTER val, SQLLEN len, SQLLEN *lenp)
16431 {
16432     STMT *s;
16433     SQLRETURN ret = SQL_ERROR;
16434 
16435     HSTMT_LOCK(stmt);
16436     if (stmt == SQL_NULL_HSTMT) {
16437 	return SQL_INVALID_HANDLE;
16438     }
16439     s = (STMT *) stmt;
16440     if (col == 0 && s->bkmrk != SQL_UB_OFF) {
16441 	if (s->bkmrk == SQL_UB_ON && type == SQL_C_BOOKMARK) {
16442 	    *((SQLINTEGER *) val) = s->rowp;
16443 	    if (lenp) {
16444 		*lenp = sizeof (SQLINTEGER);
16445 	    }
16446 	    ret = SQL_SUCCESS;
16447 	    goto done;
16448 	} else if (s->bkmrk == SQL_UB_VARIABLE && type == SQL_C_VARBOOKMARK) {
16449 	    if (s->has_rowid >= 0) {
16450 		char **data, *endp = 0;
16451 
16452 		data = s->rows + s->ncols + (s->rowp * s->ncols)
16453 		     + s->has_rowid;
16454 #ifdef __osf__
16455 		*((sqlite_int64 *) val) = strtol(*data, &endp, 0);
16456 #else
16457 		*((sqlite_int64 *) val) = strtoll(*data, &endp, 0);
16458 #endif
16459 	    } else {
16460 		*((sqlite_int64 *) val) = s->rowp;
16461 	    }
16462 	    if (lenp) {
16463 		*lenp = sizeof (sqlite_int64);
16464 	    }
16465 	    ret = SQL_SUCCESS;
16466 	    goto done;
16467 	}
16468     }
16469     if (col < 1 || col > s->ncols) {
16470 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
16471 	goto done;
16472     }
16473     --col;
16474     ret = getrowdata(s, col, type, val, len, lenp, 1);
16475 done:
16476     HSTMT_UNLOCK(stmt);
16477     return ret;
16478 }
16479 
16480 /**
16481  * Internal: fetch and bind from statement's current row
16482  * @param s statement pointer
16483  * @param rsi rowset index
16484  * @result ODBC error code
16485  */
16486 
16487 static SQLRETURN
dofetchbind(STMT * s,int rsi)16488 dofetchbind(STMT *s, int rsi)
16489 {
16490     int ret, i, withinfo = 0;
16491 
16492     s->row_status0[rsi] = SQL_ROW_SUCCESS;
16493     if (s->bkmrk != SQL_UB_OFF && s->bkmrkcol.valp) {
16494 	int bsize = sizeof (SQLINTEGER);
16495 
16496 	if (s->bkmrkcol.type == SQL_C_VARBOOKMARK) {
16497 	    SQLPOINTER *val;
16498 
16499 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
16500 		val = (SQLPOINTER)
16501 		    ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
16502 	    } else {
16503 		val = (SQLPOINTER)
16504 		    ((char *) s->bkmrkcol.valp + s->bkmrkcol.max * rsi);
16505 	    }
16506 	    if (s->bind_offs) {
16507 		val = (SQLPOINTER) ((char *) val + *s->bind_offs);
16508 	    }
16509 	    if (s->has_rowid >= 0) {
16510 		char **data, *endp = 0;
16511 
16512 		data = s->rows + s->ncols + (s->rowp * s->ncols)
16513 		     + s->has_rowid;
16514 #ifdef __osf__
16515 		*(sqlite_int64 *) val = strtol(*data, &endp, 0);
16516 #else
16517 		*(sqlite_int64 *) val = strtoll(*data, &endp, 0);
16518 #endif
16519 	    } else {
16520 		*(sqlite_int64 *) val = s->rowp;
16521 	    }
16522 	    bsize = sizeof (sqlite_int64);
16523 	} else {
16524 	    SQLINTEGER *val;
16525 
16526 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
16527 		val = (SQLINTEGER *)
16528 		    ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
16529 	    } else {
16530 		val = (SQLINTEGER *) s->bkmrkcol.valp + rsi;
16531 	    }
16532 	    if (s->bind_offs) {
16533 		val = (SQLINTEGER *) ((char *) val + *s->bind_offs);
16534 	    }
16535 	    *val = s->rowp;
16536 	}
16537 	if (s->bkmrkcol.lenp) {
16538 	    SQLLEN *ival;
16539 
16540 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
16541 		ival = (SQLLEN *)
16542 		    ((char *) s->bkmrkcol.lenp + s->bind_type * rsi);
16543 	    } else {
16544 		ival = &s->bkmrkcol.lenp[rsi];
16545 	    }
16546 	    if (s->bind_offs) {
16547 		ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
16548 	    }
16549 	    *ival = bsize;
16550 	}
16551     }
16552     ret = SQL_SUCCESS;
16553     for (i = 0; s->bindcols && i < s->ncols; i++) {
16554 	BINDCOL *b = &s->bindcols[i];
16555 	SQLPOINTER dp = 0;
16556 	SQLLEN *lp = 0;
16557 
16558 	b->offs = 0;
16559 	if (b->valp) {
16560 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
16561 		dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
16562 	    } else {
16563 		dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
16564 	    }
16565 	    if (s->bind_offs) {
16566 		dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
16567 	    }
16568 	}
16569 	if (b->lenp) {
16570 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
16571 		lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
16572 	    } else {
16573 		lp = b->lenp + rsi;
16574 	    }
16575 	    if (s->bind_offs) {
16576 		lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
16577 	    }
16578 	}
16579 	if (dp || lp) {
16580 	    ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
16581 	    if (!SQL_SUCCEEDED(ret)) {
16582 		s->row_status0[rsi] = SQL_ROW_ERROR;
16583 		break;
16584 	    }
16585 	    if (ret != SQL_SUCCESS) {
16586 		withinfo = 1;
16587 #ifdef SQL_ROW_SUCCESS_WITH_INFO
16588 		s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
16589 #endif
16590 	    }
16591 	}
16592     }
16593     if (SQL_SUCCEEDED(ret)) {
16594 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
16595     }
16596     return ret;
16597 }
16598 
16599 /**
16600  * Internal fetch function for SQLFetchScroll() and SQLExtendedFetch().
16601  * @param stmt statement handle
16602  * @param orient fetch direction
16603  * @param offset offset for fetch direction
16604  * @result ODBC error code
16605  */
16606 
16607 static SQLRETURN
drvfetchscroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLINTEGER offset)16608 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
16609 {
16610     STMT *s;
16611     int i, withinfo = 0;
16612     SQLRETURN ret;
16613 
16614     if (stmt == SQL_NULL_HSTMT) {
16615 	return SQL_INVALID_HANDLE;
16616     }
16617     s = (STMT *) stmt;
16618     for (i = 0; i < s->rowset_size; i++) {
16619 	s->row_status0[i] = SQL_ROW_NOROW;
16620     }
16621     if (s->row_status) {
16622 	memcpy(s->row_status, s->row_status0,
16623 	       sizeof (SQLUSMALLINT) * s->rowset_size);
16624     }
16625     s->row_count0 = 0;
16626     if (s->row_count) {
16627 	*s->row_count = s->row_count0;
16628     }
16629     if (!s->bindcols) {
16630 	for (i = 0; i < s->rowset_size; i++) {
16631 	    s->row_status0[i] = SQL_ROW_ERROR;
16632 	}
16633 	ret = SQL_ERROR;
16634 	i = 0;
16635 	goto done2;
16636     }
16637     if (s->isselect != 1 && s->isselect != -1) {
16638 	setstat(s, -1, "no result set available", "24000");
16639 	ret = SQL_ERROR;
16640 	i = s->nrows;
16641 	goto done2;
16642     }
16643     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
16644 	setstat(s, -1, "wrong fetch direction", "01000");
16645 	ret = SQL_ERROR;
16646 	i = 0;
16647 	goto done2;
16648     }
16649     ret = SQL_SUCCESS;
16650     i = 0;
16651     if (((DBC *) (s->dbc))->cur_s3stmt == s && s->s3stmt) {
16652 	s->rowp = s->rowprs = 0;
16653 	for (; i < s->rowset_size; i++) {
16654 	    if (s->max_rows && s->s3stmt_rownum + 1 >= s->max_rows) {
16655 		ret = (i == 0) ? SQL_NO_DATA : SQL_SUCCESS;
16656 		break;
16657 	    }
16658 	    ret = s3stmt_step(s);
16659 	    if (ret != SQL_SUCCESS) {
16660 		s->row_status0[i] = SQL_ROW_ERROR;
16661 		break;
16662 	    }
16663 	    if (s->nrows < 1) {
16664 		break;
16665 	    }
16666 	    ret = dofetchbind(s, i);
16667 	    if (!SQL_SUCCEEDED(ret)) {
16668 		break;
16669 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
16670 		withinfo = 1;
16671 	    }
16672 	}
16673     } else if (s->rows) {
16674 	switch (orient) {
16675 	case SQL_FETCH_NEXT:
16676 	    if (s->nrows < 1) {
16677 		return SQL_NO_DATA;
16678 	    }
16679 	    if (s->rowp < 0) {
16680 		s->rowp = -1;
16681 	    }
16682 	    if (s->rowp >= s->nrows) {
16683 		s->rowp = s->rowprs = s->nrows;
16684 		return SQL_NO_DATA;
16685 	    }
16686 	    break;
16687 	case SQL_FETCH_PRIOR:
16688 	    if (s->nrows < 1 || s->rowp <= 0) {
16689 		s->rowp = s->rowprs = -1;
16690 		return SQL_NO_DATA;
16691 	    }
16692 	    s->rowp -= s->rowset_size + 1;
16693 	    if (s->rowp < -1) {
16694 		s->rowp = s->rowprs = -1;
16695 		return SQL_NO_DATA;
16696 	    }
16697 	    break;
16698 	case SQL_FETCH_FIRST:
16699 	    if (s->nrows < 1) {
16700 		return SQL_NO_DATA;
16701 	    }
16702 	    s->rowp = -1;
16703 	    break;
16704 	case SQL_FETCH_LAST:
16705 	    if (s->nrows < 1) {
16706 		return SQL_NO_DATA;
16707 	    }
16708 	    s->rowp = s->nrows - s->rowset_size;
16709 	    if (--s->rowp < -1) {
16710 		s->rowp = -1;
16711 	    }
16712 	    break;
16713 	case SQL_FETCH_ABSOLUTE:
16714 	    if (offset == 0) {
16715 		s->rowp = s->rowprs = -1;
16716 		return SQL_NO_DATA;
16717 	    } else if (offset < 0) {
16718 		if (0 - offset <= s->nrows) {
16719 		    s->rowp = s->nrows + offset - 1;
16720 		    break;
16721 		}
16722 		s->rowp = s->rowprs = -1;
16723 		return SQL_NO_DATA;
16724 	    } else if (offset > s->nrows) {
16725 		s->rowp = s->rowprs = s->nrows;
16726 		return SQL_NO_DATA;
16727 	    }
16728 	    s->rowp = offset - 1 - 1;
16729 	    break;
16730 	case SQL_FETCH_RELATIVE:
16731 	    if (offset >= 0) {
16732 		s->rowp += offset * s->rowset_size - 1;
16733 		if (s->rowp >= s->nrows) {
16734 		    s->rowp = s->rowprs = s->nrows;
16735 		    return SQL_NO_DATA;
16736 		}
16737 	    } else {
16738 		s->rowp += offset * s->rowset_size - 1;
16739 		if (s->rowp < -1) {
16740 		    s->rowp = s->rowprs = -1;
16741 		    return SQL_NO_DATA;
16742 		}
16743 	    }
16744 	    break;
16745 	case SQL_FETCH_BOOKMARK:
16746 	    if (s->bkmrk == SQL_UB_ON && !s->bkmrkptr) {
16747 		if (offset < 0 || offset >= s->nrows) {
16748 		    return SQL_NO_DATA;
16749 		}
16750 		s->rowp = offset - 1;
16751 		break;
16752 	    }
16753 	    if (s->bkmrk != SQL_UB_OFF && s->bkmrkptr) {
16754 		int rowp;
16755 
16756 		if (s->bkmrk == SQL_UB_VARIABLE) {
16757 		    if (s->has_rowid >= 0) {
16758 			sqlite_int64 bkmrk, rowid;
16759 
16760 			bkmrk = *(sqlite_int64 *) s->bkmrkptr;
16761 			for (rowp = 0; rowp < s->nrows; rowp++) {
16762 			    char **data, *endp = 0;
16763 
16764 			    data = s->rows + s->ncols + (rowp * s->ncols)
16765 				 + s->has_rowid;
16766 #ifdef __osf__
16767 			    rowid = strtol(*data, &endp, 0);
16768 #else
16769 			    rowid = strtoll(*data, &endp, 0);
16770 #endif
16771 			    if (rowid == bkmrk) {
16772 				break;
16773 			    }
16774 			}
16775 		    } else {
16776 			rowp = *(sqlite_int64 *) s->bkmrkptr;
16777 		    }
16778 		} else {
16779 		    rowp = *(int *) s->bkmrkptr;
16780 		}
16781 		if (rowp + offset < 0 || rowp + offset >= s->nrows) {
16782 		    return SQL_NO_DATA;
16783 		}
16784 		s->rowp = rowp + offset - 1;
16785 		break;
16786 	    }
16787 	    /* fall through */
16788 	default:
16789 	    s->row_status0[0] = SQL_ROW_ERROR;
16790 	    ret = SQL_ERROR;
16791 	    goto done;
16792 	}
16793 	s->rowprs = s->rowp + 1;
16794 	for (; i < s->rowset_size; i++) {
16795 	    ++s->rowp;
16796 	    if (s->rowp < 0 || s->rowp >= s->nrows) {
16797 		break;
16798 	    }
16799 	    ret = dofetchbind(s, i);
16800 	    if (!SQL_SUCCEEDED(ret)) {
16801 		break;
16802 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
16803 		withinfo = 1;
16804 	    }
16805 	}
16806     }
16807 done:
16808     if (i == 0) {
16809 	if (SQL_SUCCEEDED(ret)) {
16810 	    return SQL_NO_DATA;
16811 	}
16812 	return ret;
16813     }
16814     if (SQL_SUCCEEDED(ret)) {
16815 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
16816     }
16817 done2:
16818     if (s->row_status) {
16819 	memcpy(s->row_status, s->row_status0,
16820 	       sizeof (SQLUSMALLINT) * s->rowset_size);
16821     }
16822     s->row_count0 = i;
16823     if (s->row_count) {
16824 	*s->row_count = s->row_count0;
16825     }
16826     return ret;
16827 }
16828 
16829 /**
16830  * Fetch next result row.
16831  * @param stmt statement handle
16832  * @result ODBC error code
16833  */
16834 
16835 SQLRETURN SQL_API
SQLFetch(SQLHSTMT stmt)16836 SQLFetch(SQLHSTMT stmt)
16837 {
16838     SQLRETURN ret;
16839 
16840     HSTMT_LOCK(stmt);
16841     ret = drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
16842     HSTMT_UNLOCK(stmt);
16843     return ret;
16844 }
16845 
16846 /**
16847  * Fetch result row with scrolling.
16848  * @param stmt statement handle
16849  * @param orient fetch direction
16850  * @param offset offset for fetch direction
16851  * @result ODBC error code
16852  */
16853 
16854 SQLRETURN SQL_API
SQLFetchScroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLLEN offset)16855 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLLEN offset)
16856 {
16857     SQLRETURN ret;
16858 
16859     HSTMT_LOCK(stmt);
16860     ret = drvfetchscroll(stmt, orient, offset);
16861     HSTMT_UNLOCK(stmt);
16862     return ret;
16863 }
16864 
16865 /**
16866  * Fetch result row with scrolling and row status.
16867  * @param stmt statement handle
16868  * @param orient fetch direction
16869  * @param offset offset for fetch direction
16870  * @param rowcount output number of fetched rows
16871  * @param rowstatus array for row stati
16872  * @result ODBC error code
16873  */
16874 
16875 SQLRETURN SQL_API
SQLExtendedFetch(SQLHSTMT stmt,SQLUSMALLINT orient,SQLROWOFFSET offset,SQLROWSETSIZE * rowcount,SQLUSMALLINT * rowstatus)16876 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLROWOFFSET offset,
16877 		 SQLROWSETSIZE *rowcount, SQLUSMALLINT *rowstatus)
16878 {
16879     STMT *s;
16880     SQLRETURN ret;
16881     SQLUSMALLINT *rst;
16882     SQLINTEGER *bkmrkptr;
16883 
16884     HSTMT_LOCK(stmt);
16885     if (stmt == SQL_NULL_HSTMT) {
16886 	return SQL_INVALID_HANDLE;
16887     }
16888     s = (STMT *) stmt;
16889     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
16890     rst = s->row_status;
16891     s->row_status = 0;
16892     bkmrkptr = s->bkmrkptr;
16893     s->bkmrkptr = 0;
16894     ret = drvfetchscroll(stmt, orient, offset);
16895     s->row_status = rst;
16896     s->bkmrkptr = bkmrkptr;
16897     if (rowstatus) {
16898 	memcpy(rowstatus, s->row_status0,
16899 	       sizeof (SQLUSMALLINT) * s->rowset_size);
16900     }
16901     if (rowcount) {
16902 	*rowcount = s->row_count0;
16903     }
16904     HSTMT_UNLOCK(stmt);
16905     return ret;
16906 }
16907 
16908 /**
16909  * Return number of affected rows of HSTMT.
16910  * @param stmt statement handle
16911  * @param nrows output number of rows
16912  * @result ODBC error code
16913  */
16914 
16915 SQLRETURN SQL_API
SQLRowCount(SQLHSTMT stmt,SQLLEN * nrows)16916 SQLRowCount(SQLHSTMT stmt, SQLLEN *nrows)
16917 {
16918     STMT *s;
16919 
16920     HSTMT_LOCK(stmt);
16921     if (stmt == SQL_NULL_HSTMT) {
16922 	return SQL_INVALID_HANDLE;
16923     }
16924     s = (STMT *) stmt;
16925     if (nrows) {
16926 	*nrows = s->isselect ? 0 : s->nrows;
16927     }
16928     HSTMT_UNLOCK(stmt);
16929     return SQL_SUCCESS;
16930 }
16931 
16932 /**
16933  * Return number of columns of result set given HSTMT.
16934  * @param stmt statement handle
16935  * @param ncols output number of columns
16936  * @result ODBC error code
16937  */
16938 
16939 SQLRETURN SQL_API
SQLNumResultCols(SQLHSTMT stmt,SQLSMALLINT * ncols)16940 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
16941 {
16942     STMT *s;
16943 
16944     HSTMT_LOCK(stmt);
16945     if (stmt == SQL_NULL_HSTMT) {
16946 	return SQL_INVALID_HANDLE;
16947     }
16948     s = (STMT *) stmt;
16949     if (ncols) {
16950 	*ncols = s->ncols;
16951     }
16952     HSTMT_UNLOCK(stmt);
16953     return SQL_SUCCESS;
16954 }
16955 
16956 /**
16957  * Internal describe column information.
16958  * @param stmt statement handle
16959  * @param col column number, starting at 1
16960  * @param name buffer for column name
16961  * @param nameMax length of name buffer
16962  * @param nameLen output length of column name
16963  * @param type output SQL type
16964  * @param size output column size
16965  * @param digits output number of digits
16966  * @param nullable output NULL allowed indicator
16967  * @result ODBC error code
16968  */
16969 
16970 static SQLRETURN
drvdescribecol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)16971 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
16972 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
16973 	       SQLSMALLINT *type, SQLULEN *size,
16974 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
16975 {
16976     STMT *s;
16977     COL *c;
16978     int didname = 0;
16979 
16980     if (stmt == SQL_NULL_HSTMT) {
16981 	return SQL_INVALID_HANDLE;
16982     }
16983     s = (STMT *) stmt;
16984     if (!s->cols) {
16985 	setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
16986 	return SQL_ERROR;
16987     }
16988     if (col < 1 || col > s->ncols) {
16989 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
16990 	return SQL_ERROR;
16991     }
16992     c = s->cols + col - 1;
16993     if (name && nameMax > 0) {
16994 	strncpy((char *) name, c->column, nameMax);
16995 	name[nameMax - 1] = '\0';
16996 	didname = 1;
16997     }
16998     if (nameLen) {
16999 	if (didname) {
17000 	    *nameLen = strlen((char *) name);
17001 	} else {
17002 	    *nameLen = strlen(c->column);
17003 	}
17004     }
17005     if (type) {
17006 	*type = c->type;
17007 #ifdef WINTERFACE
17008 	if (s->nowchar[0] || s->nowchar[1]) {
17009 	    switch (c->type) {
17010 	    case SQL_WCHAR:
17011 		*type = SQL_CHAR;
17012 		break;
17013 	    case SQL_WVARCHAR:
17014 		*type = SQL_VARCHAR;
17015 		break;
17016 #ifdef SQL_LONGVARCHAR
17017 	    case SQL_WLONGVARCHAR:
17018 		*type = SQL_LONGVARCHAR;
17019 		break;
17020 #endif
17021 	    }
17022 	}
17023 #endif
17024     }
17025     if (size) {
17026 	*size = c->size;
17027     }
17028     if (digits) {
17029 	*digits = 0;
17030     }
17031     if (nullable) {
17032 	*nullable = 1;
17033     }
17034     return SQL_SUCCESS;
17035 }
17036 
17037 #ifndef WINTERFACE
17038 /**
17039  * Describe column information.
17040  * @param stmt statement handle
17041  * @param col column number, starting at 1
17042  * @param name buffer for column name
17043  * @param nameMax length of name buffer
17044  * @param nameLen output length of column name
17045  * @param type output SQL type
17046  * @param size output column size
17047  * @param digits output number of digits
17048  * @param nullable output NULL allowed indicator
17049  * @result ODBC error code
17050  */
17051 
17052 SQLRETURN SQL_API
SQLDescribeCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)17053 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
17054 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
17055 	       SQLSMALLINT *type, SQLULEN *size,
17056 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
17057 {
17058 #if defined(_WIN32) || defined(_WIN64)
17059     SQLSMALLINT len = 0;
17060 #endif
17061     SQLRETURN ret;
17062 
17063     HSTMT_LOCK(stmt);
17064 #if defined(_WIN32) || defined(_WIN64)
17065     if (!((STMT *) stmt)->oemcp[0]) {
17066 	ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
17067 			     type, size, digits, nullable);
17068 	goto done;
17069     }
17070     ret = drvdescribecol(stmt, col, name, nameMax,
17071 			 &len, type, size, digits, nullable);
17072     if (ret == SQL_SUCCESS) {
17073 	if (name) {
17074 	    if (len > 0) {
17075 		SQLCHAR *n = NULL;
17076 
17077 		n = (SQLCHAR *) utf_to_wmb((char *) name, len);
17078 		if (n) {
17079 		    strncpy((char *) name, (char *) n, nameMax);
17080 		    n[len] = 0;
17081 		    len = min(nameMax, strlen((char *) n));
17082 		    uc_free(n);
17083 		} else {
17084 		    len = 0;
17085 		}
17086 	    }
17087 	    if (len <= 0) {
17088 		len = 0;
17089 		if (nameMax > 0) {
17090 		    name[0] = 0;
17091 		}
17092 	    }
17093 	} else {
17094 	    STMT *s = (STMT *) stmt;
17095 	    COL *c = s->cols + col - 1;
17096 
17097 	    len = 0;
17098 	    if (c->column) {
17099 		len = strlen(c->column);
17100 	    }
17101 	}
17102 	if (nameLen) {
17103 	    *nameLen = len;
17104 	}
17105     }
17106 done:
17107     ;
17108 #else
17109     ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
17110 			 type, size, digits, nullable);
17111 #endif
17112     HSTMT_UNLOCK(stmt);
17113     return ret;
17114 }
17115 #endif
17116 
17117 #ifdef WINTERFACE
17118 /**
17119  * Describe column information (UNICODE version).
17120  * @param stmt statement handle
17121  * @param col column number, starting at 1
17122  * @param name buffer for column name
17123  * @param nameMax length of name buffer
17124  * @param nameLen output length of column name
17125  * @param type output SQL type
17126  * @param size output column size
17127  * @param digits output number of digits
17128  * @param nullable output NULL allowed indicator
17129  * @result ODBC error code
17130  */
17131 
17132 SQLRETURN SQL_API
SQLDescribeColW(SQLHSTMT stmt,SQLUSMALLINT col,SQLWCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)17133 SQLDescribeColW(SQLHSTMT stmt, SQLUSMALLINT col, SQLWCHAR *name,
17134 		SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
17135 		SQLSMALLINT *type, SQLULEN *size,
17136 		SQLSMALLINT *digits, SQLSMALLINT *nullable)
17137 {
17138     SQLRETURN ret;
17139     SQLSMALLINT len = 0;
17140 
17141     HSTMT_LOCK(stmt);
17142     ret = drvdescribecol(stmt, col, (SQLCHAR *) name,
17143 			 (SQLSMALLINT) (nameMax * sizeof (SQLWCHAR)),
17144 			 &len, type, size, digits, nullable);
17145     if (ret == SQL_SUCCESS) {
17146 	if (name) {
17147 	    if (len > 0) {
17148 		SQLWCHAR *n = NULL;
17149 
17150 		n = uc_from_utf((SQLCHAR *) name, len);
17151 		if (n) {
17152 		    uc_strncpy(name, n, nameMax);
17153 		    n[len] = 0;
17154 		    len = min(nameMax, uc_strlen(n));
17155 		    uc_free(n);
17156 		} else {
17157 		    len = 0;
17158 		}
17159 	    }
17160 	    if (len <= 0) {
17161 		len = 0;
17162 		if (nameMax > 0) {
17163 		    name[0] = 0;
17164 		}
17165 	    }
17166 	} else {
17167 	    STMT *s = (STMT *) stmt;
17168 	    COL *c = s->cols + col - 1;
17169 
17170 	    len = 0;
17171 	    if (c->column) {
17172 		len = strlen(c->column);
17173 	    }
17174 	}
17175 	if (nameLen) {
17176 	    *nameLen = len;
17177 	}
17178     }
17179     HSTMT_UNLOCK(stmt);
17180     return ret;
17181 }
17182 #endif
17183 
17184 /**
17185  * Internal retrieve column attributes.
17186  * @param stmt statement handle
17187  * @param col column number, starting at 1
17188  * @param id attribute id
17189  * @param val output buffer
17190  * @param valMax length of output buffer
17191  * @param valLen output length
17192  * @param val2 integer output buffer
17193  * @result ODBC error code
17194  */
17195 
17196 static SQLRETURN
drvcolattributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)17197 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17198 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17199 		 SQLLEN *val2)
17200 {
17201     STMT *s;
17202     COL *c;
17203     SQLSMALLINT dummy;
17204     char *valc = (char *) val;
17205 
17206     if (stmt == SQL_NULL_HSTMT) {
17207 	return SQL_INVALID_HANDLE;
17208     }
17209     s = (STMT *) stmt;
17210     if (!s->cols) {
17211 	return SQL_ERROR;
17212     }
17213     if (!valLen) {
17214 	valLen = &dummy;
17215     }
17216     if (id == SQL_COLUMN_COUNT) {
17217 	if (val2) {
17218 	    *val2 = s->ncols;
17219 	}
17220 	*valLen = sizeof (int);
17221 	return SQL_SUCCESS;
17222     }
17223     if (id == SQL_COLUMN_TYPE && col == 0) {
17224 	if (val2) {
17225 	    *val2 = SQL_INTEGER;
17226 	}
17227 	*valLen = sizeof (int);
17228 	return SQL_SUCCESS;
17229     }
17230 #ifdef SQL_DESC_OCTET_LENGTH
17231     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
17232 	if (val2) {
17233 	    *val2 = 4;
17234 	}
17235 	*valLen = sizeof (int);
17236 	return SQL_SUCCESS;
17237     }
17238 #endif
17239     if (col < 1 || col > s->ncols) {
17240 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
17241 	return SQL_ERROR;
17242     }
17243     c = s->cols + col - 1;
17244 
17245     switch (id) {
17246     case SQL_COLUMN_LABEL:
17247 	if (c->label) {
17248 	    if (valc && valMax > 0) {
17249 		strncpy(valc, c->label, valMax);
17250 		valc[valMax - 1] = '\0';
17251 	    }
17252 	    *valLen = strlen(c->label);
17253 	    goto checkLen;
17254 	}
17255 	/* fall through */
17256     case SQL_COLUMN_NAME:
17257     case SQL_DESC_NAME:
17258 	if (valc && valMax > 0) {
17259 	    strncpy(valc, c->column, valMax);
17260 	    valc[valMax - 1] = '\0';
17261 	}
17262 	*valLen = strlen(c->column);
17263 checkLen:
17264 	if (*valLen >= valMax) {
17265 	    setstat(s, -1, "data right truncated", "01004");
17266 	    return SQL_SUCCESS_WITH_INFO;
17267 	}
17268 	return SQL_SUCCESS;
17269 #ifdef SQL_DESC_BASE_COLUMN_NAME
17270      case SQL_DESC_BASE_COLUMN_NAME:
17271 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
17272 	    if (valc && valMax > 0) {
17273 		valc[0] = '\0';
17274 	    }
17275 	    *valLen = 0;
17276 	} else if (valc && valMax > 0) {
17277 	    strncpy(valc, c->column, valMax);
17278 	    valc[valMax - 1] = '\0';
17279 	    *valLen = strlen(c->column);
17280 	}
17281 	goto checkLen;
17282 #endif
17283     case SQL_COLUMN_TYPE:
17284     case SQL_DESC_TYPE:
17285 #ifdef WINTERFACE
17286 	{
17287 	    int type = c->type;
17288 
17289 	    if (s->nowchar[0] || s->nowchar[1]) {
17290 		switch (type) {
17291 		case SQL_WCHAR:
17292 		    type = SQL_CHAR;
17293 		    break;
17294 		case SQL_WVARCHAR:
17295 		    type = SQL_VARCHAR;
17296 		    break;
17297 #ifdef SQL_LONGVARCHAR
17298 		case SQL_WLONGVARCHAR:
17299 		    type = SQL_LONGVARCHAR;
17300 		    break;
17301 		}
17302 	    }
17303 	    if (val2) {
17304 		*val2 = type;
17305 	    }
17306 #endif
17307 	}
17308 #else
17309 	if (val2) {
17310 	    *val2 = c->type;
17311 	}
17312 #endif
17313 	*valLen = sizeof (int);
17314 	return SQL_SUCCESS;
17315     case SQL_COLUMN_DISPLAY_SIZE:
17316 	if (val2) {
17317 	    *val2 = c->size;
17318 	}
17319 	*valLen = sizeof (int);
17320 	return SQL_SUCCESS;
17321     case SQL_COLUMN_UNSIGNED:
17322 	if (val2) {
17323 	    *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
17324 	}
17325 	*valLen = sizeof (int);
17326 	return SQL_SUCCESS;
17327     case SQL_COLUMN_SCALE:
17328     case SQL_DESC_SCALE:
17329 	if (val2) {
17330 	    *val2 = c->scale;
17331 	}
17332 	*valLen = sizeof (int);
17333 	return SQL_SUCCESS;
17334     case SQL_COLUMN_PRECISION:
17335     case SQL_DESC_PRECISION:
17336 	if (val2) {
17337 	    switch (c->type) {
17338 	    case SQL_SMALLINT:
17339 		*val2 = 5;
17340 		break;
17341 	    case SQL_INTEGER:
17342 		*val2 = 10;
17343 		break;
17344 	    case SQL_FLOAT:
17345 	    case SQL_REAL:
17346 	    case SQL_DOUBLE:
17347 		*val2 = 15;
17348 		break;
17349 	    case SQL_DATE:
17350 		*val2 = 0;
17351 		break;
17352 	    case SQL_TIME:
17353 		*val2 = 0;
17354 		break;
17355 #ifdef SQL_TYPE_TIMESTAMP
17356 	    case SQL_TYPE_TIMESTAMP:
17357 #endif
17358 	    case SQL_TIMESTAMP:
17359 		*val2 = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
17360 		break;
17361 	    default:
17362 		*val2 = c->prec;
17363 		break;
17364 	    }
17365 	}
17366 	*valLen = sizeof (int);
17367 	return SQL_SUCCESS;
17368     case SQL_COLUMN_MONEY:
17369 	if (val2) {
17370 	    *val2 = SQL_FALSE;
17371 	}
17372 	*valLen = sizeof (int);
17373 	return SQL_SUCCESS;
17374     case SQL_COLUMN_AUTO_INCREMENT:
17375 	if (val2) {
17376 	    *val2 = c->autoinc;
17377 	}
17378 	*valLen = sizeof (int);
17379 	return SQL_SUCCESS;
17380     case SQL_COLUMN_LENGTH:
17381     case SQL_DESC_LENGTH:
17382 	if (val2) {
17383 	    *val2 = c->size;
17384 	}
17385 	*valLen = sizeof (int);
17386 	return SQL_SUCCESS;
17387     case SQL_COLUMN_NULLABLE:
17388     case SQL_DESC_NULLABLE:
17389 	if (val2) {
17390 	    *val2 = c->notnull;
17391 	}
17392 	*valLen = sizeof (int);
17393 	return SQL_SUCCESS;
17394     case SQL_COLUMN_SEARCHABLE:
17395 	if (val2) {
17396 	    *val2 = SQL_SEARCHABLE;
17397 	}
17398 	*valLen = sizeof (int);
17399 	return SQL_SUCCESS;
17400     case SQL_COLUMN_CASE_SENSITIVE:
17401 	if (val2) {
17402 	    *val2 = SQL_TRUE;
17403 	}
17404 	*valLen = sizeof (int);
17405 	return SQL_SUCCESS;
17406     case SQL_COLUMN_UPDATABLE:
17407 	if (val2) {
17408 	    *val2 = SQL_TRUE;
17409 	}
17410 	*valLen = sizeof (int);
17411 	return SQL_SUCCESS;
17412     case SQL_DESC_COUNT:
17413 	if (val2) {
17414 	    *val2 = s->ncols;
17415 	}
17416 	*valLen = sizeof (int);
17417 	return SQL_SUCCESS;
17418     case SQL_COLUMN_TYPE_NAME: {
17419 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
17420 
17421 #ifdef WINTERFACE
17422 	if (c->type == SQL_WCHAR ||
17423 	    c->type == SQL_WVARCHAR ||
17424 	    c->type == SQL_WLONGVARCHAR) {
17425 	    if (!(s->nowchar[0] || s->nowchar[1])) {
17426 		if (strcasecmp(tn, "varchar") == 0) {
17427 		    tn = "wvarchar";
17428 		}
17429 	    }
17430 	}
17431 #endif
17432 	if (valc && valMax > 0) {
17433 	    strncpy(valc, tn, valMax);
17434 	    valc[valMax - 1] = '\0';
17435 	    p = strchr(valc, '(');
17436 	    if (p) {
17437 		*p = '\0';
17438 		while (p > valc && ISSPACE(p[-1])) {
17439 		    --p;
17440 		    *p = '\0';
17441 		}
17442 	    }
17443 	    *valLen = strlen(valc);
17444 	} else {
17445 	    *valLen = strlen(tn);
17446 	    p = strchr(tn, '(');
17447 	    if (p) {
17448 		*valLen = p - tn;
17449 		while (p > tn && ISSPACE(p[-1])) {
17450 		    --p;
17451 		    *valLen -= 1;
17452 		}
17453 	    }
17454 	}
17455 	goto checkLen;
17456     }
17457     case SQL_COLUMN_OWNER_NAME:
17458     case SQL_COLUMN_QUALIFIER_NAME: {
17459 	char *z = "";
17460 
17461 	if (valc && valMax > 0) {
17462 	    strncpy(valc, z, valMax);
17463 	    valc[valMax - 1] = '\0';
17464 	}
17465 	*valLen = strlen(z);
17466 	goto checkLen;
17467     }
17468     case SQL_COLUMN_TABLE_NAME:
17469 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
17470     case SQL_DESC_TABLE_NAME:
17471 #endif
17472 #ifdef SQL_DESC_BASE_TABLE_NAME
17473     case SQL_DESC_BASE_TABLE_NAME:
17474 #endif
17475 	if (valc && valMax > 0) {
17476 	    strncpy(valc, c->table, valMax);
17477 	    valc[valMax - 1] = '\0';
17478 	}
17479 	*valLen = strlen(c->table);
17480 	goto checkLen;
17481 #ifdef SQL_DESC_NUM_PREC_RADIX
17482     case SQL_DESC_NUM_PREC_RADIX:
17483 	if (val2) {
17484 	    switch (c->type) {
17485 #ifdef WINTERFACE
17486 	    case SQL_WCHAR:
17487 	    case SQL_WVARCHAR:
17488 #ifdef SQL_LONGVARCHAR
17489 	    case SQL_WLONGVARCHAR:
17490 #endif
17491 #endif
17492 	    case SQL_CHAR:
17493 	    case SQL_VARCHAR:
17494 #ifdef SQL_LONGVARCHAR
17495 	    case SQL_LONGVARCHAR:
17496 #endif
17497 	    case SQL_BINARY:
17498 	    case SQL_VARBINARY:
17499 	    case SQL_LONGVARBINARY:
17500 		*val2 = 0;
17501 		break;
17502 	    default:
17503 		*val2 = 2;
17504 	    }
17505 	}
17506 	*valLen = sizeof (int);
17507 	return SQL_SUCCESS;
17508 #endif
17509     }
17510     setstat(s, -1, "unsupported column attributes %d", "HY091", id);
17511     return SQL_ERROR;
17512 }
17513 
17514 #ifndef WINTERFACE
17515 /**
17516  * Retrieve column attributes.
17517  * @param stmt statement handle
17518  * @param col column number, starting at 1
17519  * @param id attribute id
17520  * @param val output buffer
17521  * @param valMax length of output buffer
17522  * @param valLen output length
17523  * @param val2 integer output buffer
17524  * @result ODBC error code
17525  */
17526 
17527 SQLRETURN SQL_API
SQLColAttributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)17528 SQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17529 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17530 		 SQLLEN *val2)
17531 {
17532 #if defined(_WIN32) || defined(_WIN64)
17533     SQLSMALLINT len = 0;
17534 #endif
17535     SQLRETURN ret;
17536 
17537     HSTMT_LOCK(stmt);
17538 #if defined(_WIN32) || defined(_WIN64)
17539     if (!((STMT *) stmt)->oemcp[0]) {
17540 	ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
17541 	goto done;
17542     }
17543     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
17544     if (SQL_SUCCEEDED(ret)) {
17545 	char *v = NULL;
17546 
17547 	switch (id) {
17548 	case SQL_COLUMN_LABEL:
17549 	case SQL_COLUMN_NAME:
17550 	case SQL_DESC_NAME:
17551 	case SQL_COLUMN_TYPE_NAME:
17552 	case SQL_COLUMN_OWNER_NAME:
17553 	case SQL_COLUMN_QUALIFIER_NAME:
17554 	case SQL_COLUMN_TABLE_NAME:
17555 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
17556 	case SQL_DESC_TABLE_NAME:
17557 #endif
17558 #ifdef SQL_DESC_BASE_COLUMN_NAME
17559 	case SQL_DESC_BASE_COLUMN_NAME:
17560 #endif
17561 #ifdef SQL_DESC_BASE_TABLE_NAME
17562     case SQL_DESC_BASE_TABLE_NAME:
17563 #endif
17564 	    if (val && valMax > 0) {
17565 		int vmax = valMax;
17566 
17567 		v = utf_to_wmb((char *) val, SQL_NTS);
17568 		if (v) {
17569 		    strncpy(val, v, vmax);
17570 		    len = min(vmax, strlen(v));
17571 		    uc_free(v);
17572 		}
17573 		if (vmax > 0) {
17574 		    v = (char *) val;
17575 		    v[vmax - 1] = '\0';
17576 		}
17577 	    }
17578 	    if (len <= 0) {
17579 		len = 0;
17580 	    }
17581 	    break;
17582 	}
17583 	if (valLen) {
17584 	    *valLen = len;
17585 	}
17586     }
17587 done:
17588     ;
17589 #else
17590     ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
17591 #endif
17592     HSTMT_UNLOCK(stmt);
17593     return ret;
17594 }
17595 #endif
17596 
17597 #ifdef WINTERFACE
17598 /**
17599  * Retrieve column attributes (UNICODE version).
17600  * @param stmt statement handle
17601  * @param col column number, starting at 1
17602  * @param id attribute id
17603  * @param val output buffer
17604  * @param valMax length of output buffer
17605  * @param valLen output length
17606  * @param val2 integer output buffer
17607  * @result ODBC error code
17608  */
17609 
17610 SQLRETURN SQL_API
SQLColAttributesW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)17611 SQLColAttributesW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17612 		  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17613 		  SQLLEN *val2)
17614 {
17615     SQLRETURN ret;
17616     SQLSMALLINT len = 0;
17617 
17618     HSTMT_LOCK(stmt);
17619     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
17620     if (SQL_SUCCEEDED(ret)) {
17621 	SQLWCHAR *v = NULL;
17622 
17623 	switch (id) {
17624 	case SQL_COLUMN_LABEL:
17625 	case SQL_COLUMN_NAME:
17626 	case SQL_DESC_NAME:
17627 	case SQL_COLUMN_TYPE_NAME:
17628 	case SQL_COLUMN_OWNER_NAME:
17629 	case SQL_COLUMN_QUALIFIER_NAME:
17630 	case SQL_COLUMN_TABLE_NAME:
17631 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
17632 	case SQL_DESC_TABLE_NAME:
17633 #endif
17634 #ifdef SQL_DESC_BASE_COLUMN_NAME
17635 	case SQL_DESC_BASE_COLUMN_NAME:
17636 #endif
17637 #ifdef SQL_DESC_BASE_TABLE_NAME
17638     case SQL_DESC_BASE_TABLE_NAME:
17639 #endif
17640 	    if (val && valMax > 0) {
17641 		int vmax = valMax / sizeof (SQLWCHAR);
17642 
17643 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
17644 		if (v) {
17645 		    uc_strncpy(val, v, vmax);
17646 		    len = min(vmax, uc_strlen(v));
17647 		    uc_free(v);
17648 		    len *= sizeof (SQLWCHAR);
17649 		}
17650 		if (vmax > 0) {
17651 		    v = (SQLWCHAR *) val;
17652 		    v[vmax - 1] = '\0';
17653 		}
17654 	    }
17655 	    if (len <= 0) {
17656 		len = 0;
17657 	    }
17658 	    break;
17659 	}
17660 	if (valLen) {
17661 	    *valLen = len;
17662 	}
17663     }
17664     HSTMT_UNLOCK(stmt);
17665     return ret;
17666 }
17667 #endif
17668 
17669 /**
17670  * Internal retrieve column attributes.
17671  * @param stmt statement handle
17672  * @param col column number, starting at 1
17673  * @param id attribute id
17674  * @param val output buffer
17675  * @param valMax length of output buffer
17676  * @param valLen output length
17677  * @param val2 integer output buffer
17678  * @result ODBC error code
17679  */
17680 
17681 static SQLRETURN
drvcolattribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLPOINTER val2)17682 drvcolattribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17683 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17684 		SQLPOINTER val2)
17685 {
17686     STMT *s;
17687     COL *c;
17688     int v = 0;
17689     char *valc = (char *) val;
17690     SQLSMALLINT dummy;
17691 
17692     if (stmt == SQL_NULL_HSTMT) {
17693 	return SQL_INVALID_HANDLE;
17694     }
17695     s = (STMT *) stmt;
17696     if (!s->cols) {
17697 	return SQL_ERROR;
17698     }
17699     if (col < 1 || col > s->ncols) {
17700 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
17701 	return SQL_ERROR;
17702     }
17703     if (!valLen) {
17704 	valLen = &dummy;
17705     }
17706     c = s->cols + col - 1;
17707     switch (id) {
17708     case SQL_DESC_COUNT:
17709 	v = s->ncols;
17710 	break;
17711     case SQL_DESC_CATALOG_NAME:
17712 	if (valc && valMax > 0) {
17713 	    strncpy(valc, c->db, valMax);
17714 	    valc[valMax - 1] = '\0';
17715 	}
17716 	*valLen = strlen(c->db);
17717 checkLen:
17718 	if (*valLen >= valMax) {
17719 	    setstat(s, -1, "data right truncated", "01004");
17720 	    return SQL_SUCCESS_WITH_INFO;
17721 	}
17722 	break;
17723     case SQL_COLUMN_LENGTH:
17724     case SQL_DESC_LENGTH:
17725 	v = c->size;
17726 	break;
17727     case SQL_COLUMN_LABEL:
17728 	if (c->label) {
17729 	    if (valc && valMax > 0) {
17730 		strncpy(valc, c->label, valMax);
17731 		valc[valMax - 1] = '\0';
17732 	    }
17733 	    *valLen = strlen(c->label);
17734 	    goto checkLen;
17735 	}
17736 	/* fall through */
17737     case SQL_COLUMN_NAME:
17738     case SQL_DESC_NAME:
17739 	if (valc && valMax > 0) {
17740 	    strncpy(valc, c->column, valMax);
17741 	    valc[valMax - 1] = '\0';
17742 	}
17743 	*valLen = strlen(c->column);
17744 	goto checkLen;
17745     case SQL_DESC_SCHEMA_NAME: {
17746 	char *z = "";
17747 
17748 	if (valc && valMax > 0) {
17749 	    strncpy(valc, z, valMax);
17750 	    valc[valMax - 1] = '\0';
17751 	}
17752 	*valLen = strlen(z);
17753 	goto checkLen;
17754     }
17755 #ifdef SQL_DESC_BASE_COLUMN_NAME
17756     case SQL_DESC_BASE_COLUMN_NAME:
17757 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
17758 	    valc[0] = '\0';
17759 	    *valLen = 0;
17760 	} else if (valc && valMax > 0) {
17761 	    strncpy(valc, c->column, valMax);
17762 	    valc[valMax - 1] = '\0';
17763 	    *valLen = strlen(c->column);
17764 	}
17765 	goto checkLen;
17766 #endif
17767     case SQL_DESC_TYPE_NAME: {
17768 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
17769 
17770 #ifdef WINTERFACE
17771 	if (c->type == SQL_WCHAR ||
17772 	    c->type == SQL_WVARCHAR ||
17773 	    c->type == SQL_WLONGVARCHAR) {
17774 	    if (!(s->nowchar[0] || s->nowchar[1])) {
17775 		if (strcasecmp(tn, "varchar") == 0) {
17776 		    tn = "wvarchar";
17777 		}
17778 	    }
17779 	}
17780 #endif
17781 	if (valc && valMax > 0) {
17782 	    strncpy(valc, tn, valMax);
17783 	    valc[valMax - 1] = '\0';
17784 	    p = strchr(valc, '(');
17785 	    if (p) {
17786 		*p = '\0';
17787 		while (p > valc && ISSPACE(p[-1])) {
17788 		    --p;
17789 		    *p = '\0';
17790 		}
17791 	    }
17792 	    *valLen = strlen(valc);
17793 	} else {
17794 	    *valLen = strlen(tn);
17795 	    p = strchr(tn, '(');
17796 	    if (p) {
17797 		*valLen = p - tn;
17798 		while (p > tn && ISSPACE(p[-1])) {
17799 		    --p;
17800 		    *valLen -= 1;
17801 		}
17802 	    }
17803 	}
17804 	goto checkLen;
17805     }
17806     case SQL_DESC_OCTET_LENGTH:
17807 	v = c->size;
17808 #ifdef WINTERFACE
17809 	if (c->type == SQL_WCHAR ||
17810 	    c->type == SQL_WVARCHAR ||
17811 	    c->type == SQL_WLONGVARCHAR) {
17812 	    if (!(s->nowchar[0] || s->nowchar[1])) {
17813 		v *= sizeof (SQLWCHAR);
17814 	    }
17815 	}
17816 #endif
17817 	break;
17818 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
17819     case SQL_COLUMN_TABLE_NAME:
17820 #endif
17821 #ifdef SQL_DESC_BASE_TABLE_NAME
17822     case SQL_DESC_BASE_TABLE_NAME:
17823 #endif
17824     case SQL_DESC_TABLE_NAME:
17825 	if (valc && valMax > 0) {
17826 	    strncpy(valc, c->table, valMax);
17827 	    valc[valMax - 1] = '\0';
17828 	}
17829 	*valLen = strlen(c->table);
17830 	goto checkLen;
17831     case SQL_DESC_TYPE:
17832 	v = c->type;
17833 #ifdef WINTERFACE
17834 	if (s->nowchar[0] || s->nowchar[1]) {
17835 	    switch (v) {
17836 	    case SQL_WCHAR:
17837 		v = SQL_CHAR;
17838 		break;
17839 	    case SQL_WVARCHAR:
17840 		v = SQL_VARCHAR;
17841 		break;
17842 #ifdef SQL_LONGVARCHAR
17843 	    case SQL_WLONGVARCHAR:
17844 		v = SQL_LONGVARCHAR;
17845 		break;
17846 #endif
17847 	    }
17848 	}
17849 #endif
17850 	break;
17851     case SQL_DESC_CONCISE_TYPE:
17852 	switch (c->type) {
17853 	case SQL_INTEGER:
17854 	    v = SQL_C_LONG;
17855 	    break;
17856 	case SQL_TINYINT:
17857 	    v = SQL_C_TINYINT;
17858 	    break;
17859 	case SQL_SMALLINT:
17860 	    v = SQL_C_SHORT;
17861 	    break;
17862 	case SQL_FLOAT:
17863 	    v = SQL_C_FLOAT;
17864 	    break;
17865 	case SQL_DOUBLE:
17866 	    v = SQL_C_DOUBLE;
17867 	    break;
17868 	case SQL_TIMESTAMP:
17869 	    v = SQL_C_TIMESTAMP;
17870 	    break;
17871 	case SQL_TIME:
17872 	    v = SQL_C_TIME;
17873 	    break;
17874 	case SQL_DATE:
17875 	    v = SQL_C_DATE;
17876 	    break;
17877 #ifdef SQL_C_TYPE_TIMESTAMP
17878 	case SQL_TYPE_TIMESTAMP:
17879 	    v = SQL_C_TYPE_TIMESTAMP;
17880 	    break;
17881 #endif
17882 #ifdef SQL_C_TYPE_TIME
17883 	case SQL_TYPE_TIME:
17884 	    v = SQL_C_TYPE_TIME;
17885 	    break;
17886 #endif
17887 #ifdef SQL_C_TYPE_DATE
17888 	case SQL_TYPE_DATE:
17889 	    v = SQL_C_TYPE_DATE;
17890 	    break;
17891 #endif
17892 #ifdef SQL_BIT
17893 	case SQL_BIT:
17894 	    v = SQL_C_BIT;
17895 	    break;
17896 #endif
17897 #ifdef SQL_BIGINT
17898 	case SQL_BIGINT:
17899 	    v = SQL_C_SBIGINT;
17900 	    break;
17901 #endif
17902 	default:
17903 #ifdef WINTERFACE
17904 	    v = (s->nowchar[0] || s->nowchar[1]) ? SQL_C_CHAR : SQL_C_WCHAR;
17905 #else
17906 	    v = SQL_C_CHAR;
17907 #endif
17908 	    break;
17909 	}
17910 	break;
17911     case SQL_DESC_UPDATABLE:
17912 	v = SQL_TRUE;
17913 	break;
17914     case SQL_COLUMN_DISPLAY_SIZE:
17915 	v = c->size;
17916 	break;
17917     case SQL_COLUMN_UNSIGNED:
17918 	v = c->nosign ? SQL_TRUE : SQL_FALSE;
17919 	break;
17920     case SQL_COLUMN_SEARCHABLE:
17921 	v = SQL_SEARCHABLE;
17922 	break;
17923     case SQL_COLUMN_SCALE:
17924     case SQL_DESC_SCALE:
17925 	v = c->scale;
17926 	break;
17927     case SQL_COLUMN_PRECISION:
17928     case SQL_DESC_PRECISION:
17929 	switch (c->type) {
17930 	case SQL_SMALLINT:
17931 	    v = 5;
17932 	    break;
17933 	case SQL_INTEGER:
17934 	    v = 10;
17935 	    break;
17936 	case SQL_FLOAT:
17937 	case SQL_REAL:
17938 	case SQL_DOUBLE:
17939 	    v = 15;
17940 	    break;
17941 	case SQL_DATE:
17942 	    v = 0;
17943 	    break;
17944 	case SQL_TIME:
17945 	    v = 0;
17946 	    break;
17947 #ifdef SQL_TYPE_TIMESTAMP
17948 	case SQL_TYPE_TIMESTAMP:
17949 #endif
17950 	case SQL_TIMESTAMP:
17951 	    v = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
17952 	    break;
17953 	default:
17954 	    v = c->prec;
17955 	    break;
17956 	}
17957 	break;
17958     case SQL_COLUMN_MONEY:
17959 	v = SQL_FALSE;
17960 	break;
17961     case SQL_COLUMN_AUTO_INCREMENT:
17962 	v = c->autoinc;
17963 	break;
17964     case SQL_DESC_NULLABLE:
17965 	v = c->notnull;
17966 	break;
17967 #ifdef SQL_DESC_NUM_PREC_RADIX
17968     case SQL_DESC_NUM_PREC_RADIX:
17969 	switch (c->type) {
17970 #ifdef WINTERFACE
17971 	case SQL_WCHAR:
17972 	case SQL_WVARCHAR:
17973 #ifdef SQL_LONGVARCHAR
17974 	case SQL_WLONGVARCHAR:
17975 #endif
17976 #endif
17977 	case SQL_CHAR:
17978 	case SQL_VARCHAR:
17979 #ifdef SQL_LONGVARCHAR
17980 	case SQL_LONGVARCHAR:
17981 #endif
17982 	case SQL_BINARY:
17983 	case SQL_VARBINARY:
17984 	case SQL_LONGVARBINARY:
17985 	    v = 0;
17986 	    break;
17987 	default:
17988 	    v = 2;
17989 	}
17990 	break;
17991 #endif
17992     default:
17993 	setstat(s, -1, "unsupported column attribute %d", "HY091", id);
17994 	return SQL_ERROR;
17995     }
17996     if (val2) {
17997 	*(SQLLEN *) val2 = v;
17998     }
17999     return SQL_SUCCESS;
18000 }
18001 
18002 #ifndef WINTERFACE
18003 /**
18004  * Retrieve column attributes.
18005  * @param stmt statement handle
18006  * @param col column number, starting at 1
18007  * @param id attribute id
18008  * @param val output buffer
18009  * @param valMax length of output buffer
18010  * @param valLen output length
18011  * @param val2 integer output buffer
18012  * @result ODBC error code
18013  */
18014 
18015 SQLRETURN SQL_API
SQLColAttribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)18016 SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
18017 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
18018 		COLATTRIBUTE_LAST_ARG_TYPE val2)
18019 {
18020 #if defined(_WIN32) || defined(_WIN64)
18021     SQLSMALLINT len = 0;
18022 #endif
18023     SQLRETURN ret;
18024 
18025     HSTMT_LOCK(stmt);
18026 #if defined(_WIN32) || defined(_WIN64)
18027     if (!((STMT *) stmt)->oemcp[0]) {
18028 	ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
18029 			      (SQLPOINTER) val2);
18030 	goto done;
18031     }
18032     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
18033 			  (SQLPOINTER) val2);
18034     if (SQL_SUCCEEDED(ret)) {
18035 	char *v = NULL;
18036 
18037 	switch (id) {
18038 	case SQL_DESC_SCHEMA_NAME:
18039 	case SQL_DESC_CATALOG_NAME:
18040 	case SQL_COLUMN_LABEL:
18041 	case SQL_DESC_NAME:
18042 	case SQL_DESC_TABLE_NAME:
18043 #ifdef SQL_DESC_BASE_TABLE_NAME
18044 	case SQL_DESC_BASE_TABLE_NAME:
18045 #endif
18046 #ifdef SQL_DESC_BASE_COLUMN_NAME
18047 	case SQL_DESC_BASE_COLUMN_NAME:
18048 #endif
18049 	case SQL_DESC_TYPE_NAME:
18050 	    if (val && valMax > 0) {
18051 		int vmax = valMax;
18052 
18053 		v = utf_to_wmb((char *) val, SQL_NTS);
18054 		if (v) {
18055 		    strncpy(val, v, vmax);
18056 		    len = min(vmax, strlen(v));
18057 		    uc_free(v);
18058 		}
18059 		if (vmax > 0) {
18060 		    v = (char *) val;
18061 		    v[vmax - 1] = '\0';
18062 		}
18063 	    }
18064 	    if (len <= 0) {
18065 		len = 0;
18066 	    }
18067 	    break;
18068 	}
18069 	if (valLen) {
18070 	    *valLen = len;
18071 	}
18072     }
18073 done:
18074     ;
18075 #else
18076     ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
18077 			  (SQLPOINTER) val2);
18078 #endif
18079     HSTMT_UNLOCK(stmt);
18080     return ret;
18081 }
18082 #endif
18083 
18084 #ifdef WINTERFACE
18085 /**
18086  * Retrieve column attributes (UNICODE version).
18087  * @param stmt statement handle
18088  * @param col column number, starting at 1
18089  * @param id attribute id
18090  * @param val output buffer
18091  * @param valMax length of output buffer
18092  * @param valLen output length
18093  * @param val2 integer output buffer
18094  * @result ODBC error code
18095  */
18096 
18097 SQLRETURN SQL_API
SQLColAttributeW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)18098 SQLColAttributeW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
18099 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
18100 		 COLATTRIBUTE_LAST_ARG_TYPE val2)
18101 {
18102     SQLRETURN ret;
18103     SQLSMALLINT len = 0;
18104 
18105     HSTMT_LOCK(stmt);
18106     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
18107 			  (SQLPOINTER) val2);
18108     if (SQL_SUCCEEDED(ret)) {
18109 	SQLWCHAR *v = NULL;
18110 
18111 	switch (id) {
18112 	case SQL_DESC_SCHEMA_NAME:
18113 	case SQL_DESC_CATALOG_NAME:
18114 	case SQL_COLUMN_LABEL:
18115 	case SQL_DESC_NAME:
18116 	case SQL_DESC_TABLE_NAME:
18117 #ifdef SQL_DESC_BASE_TABLE_NAME
18118 	case SQL_DESC_BASE_TABLE_NAME:
18119 #endif
18120 #ifdef SQL_DESC_BASE_COLUMN_NAME
18121 	case SQL_DESC_BASE_COLUMN_NAME:
18122 #endif
18123 	case SQL_DESC_TYPE_NAME:
18124 	    if (val && valMax > 0) {
18125 		int vmax = valMax / sizeof (SQLWCHAR);
18126 
18127 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
18128 		if (v) {
18129 		    uc_strncpy(val, v, vmax);
18130 		    len = min(vmax, uc_strlen(v));
18131 		    uc_free(v);
18132 		    len *= sizeof (SQLWCHAR);
18133 		}
18134 		if (vmax > 0) {
18135 		    v = (SQLWCHAR *) val;
18136 		    v[vmax - 1] = '\0';
18137 		}
18138 	    }
18139 	    if (len <= 0) {
18140 		len = 0;
18141 	    }
18142 	    break;
18143 	}
18144 	if (valLen) {
18145 	    *valLen = len;
18146 	}
18147     }
18148     HSTMT_UNLOCK(stmt);
18149     return ret;
18150 }
18151 #endif
18152 
18153 /**
18154  * Internal return last HDBC or HSTMT error message.
18155  * @param env environment handle or NULL
18156  * @param dbc database connection handle or NULL
18157  * @param stmt statement handle or NULL
18158  * @param sqlState output buffer for SQL state
18159  * @param nativeErr output buffer for native error code
18160  * @param errmsg output buffer for error message
18161  * @param errmax length of output buffer for error message
18162  * @param errlen output length of error message
18163  * @result ODBC error code
18164  */
18165 
18166 static SQLRETURN
drverror(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)18167 drverror(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
18168 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
18169 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
18170 {
18171     SQLCHAR dummy0[6];
18172     SQLINTEGER dummy1;
18173     SQLSMALLINT dummy2;
18174 
18175     if (env == SQL_NULL_HENV &&
18176 	dbc == SQL_NULL_HDBC &&
18177 	stmt == SQL_NULL_HSTMT) {
18178 	return SQL_INVALID_HANDLE;
18179     }
18180     if (sqlState) {
18181 	sqlState[0] = '\0';
18182     } else {
18183 	sqlState = dummy0;
18184     }
18185     if (!nativeErr) {
18186 	nativeErr = &dummy1;
18187     }
18188     *nativeErr = 0;
18189     if (!errlen) {
18190 	errlen = &dummy2;
18191     }
18192     *errlen = 0;
18193     if (errmsg) {
18194 	if (errmax > 0) {
18195 	    errmsg[0] = '\0';
18196 	}
18197     } else {
18198 	errmsg = dummy0;
18199 	errmax = 0;
18200     }
18201     if (stmt) {
18202 	STMT *s = (STMT *) stmt;
18203 
18204 	HSTMT_LOCK(stmt);
18205 	if (s->logmsg[0] == '\0') {
18206 	    HSTMT_UNLOCK(stmt);
18207 	    goto noerr;
18208 	}
18209 	*nativeErr = s->naterr;
18210 	strcpy((char *) sqlState, s->sqlstate);
18211 	if (errmax == SQL_NTS) {
18212 	    strcpy((char *) errmsg, "[SQLite]");
18213 	    strcat((char *) errmsg, (char *) s->logmsg);
18214 	    *errlen = strlen((char *) errmsg);
18215 	} else {
18216 	    strncpy((char *) errmsg, "[SQLite]", errmax);
18217 	    if (errmax - 8 > 0) {
18218 		strncpy((char *) errmsg + 8, (char *) s->logmsg, errmax - 8);
18219 	    }
18220 	    *errlen = min(strlen((char *) s->logmsg) + 8, errmax);
18221 	}
18222 	s->logmsg[0] = '\0';
18223 	HSTMT_UNLOCK(stmt);
18224 	return SQL_SUCCESS;
18225     }
18226     if (dbc) {
18227 	DBC *d = (DBC *) dbc;
18228 
18229 	HDBC_LOCK(dbc);
18230 	if (d->magic != DBC_MAGIC || d->logmsg[0] == '\0') {
18231 	    HDBC_UNLOCK(dbc);
18232 	    goto noerr;
18233 	}
18234 	*nativeErr = d->naterr;
18235 	strcpy((char *) sqlState, d->sqlstate);
18236 	if (errmax == SQL_NTS) {
18237 	    strcpy((char *) errmsg, "[SQLite]");
18238 	    strcat((char *) errmsg, (char *) d->logmsg);
18239 	    *errlen = strlen((char *) errmsg);
18240 	} else {
18241 	    strncpy((char *) errmsg, "[SQLite]", errmax);
18242 	    if (errmax - 8 > 0) {
18243 		strncpy((char *) errmsg + 8, (char *) d->logmsg, errmax - 8);
18244 	    }
18245 	    *errlen = min(strlen((char *) d->logmsg) + 8, errmax);
18246 	}
18247 	d->logmsg[0] = '\0';
18248 	HDBC_UNLOCK(dbc);
18249 	return SQL_SUCCESS;
18250     }
18251 noerr:
18252     sqlState[0] = '\0';
18253     errmsg[0] = '\0';
18254     *nativeErr = 0;
18255     *errlen = 0;
18256     return SQL_NO_DATA;
18257 }
18258 
18259 #ifndef WINTERFACE
18260 /**
18261  * Return last HDBC or HSTMT error message.
18262  * @param env environment handle or NULL
18263  * @param dbc database connection handle or NULL
18264  * @param stmt statement handle or NULL
18265  * @param sqlState output buffer for SQL state
18266  * @param nativeErr output buffer for native error code
18267  * @param errmsg output buffer for error message
18268  * @param errmax length of output buffer for error message
18269  * @param errlen output length of error message
18270  * @result ODBC error code
18271  */
18272 
18273 SQLRETURN SQL_API
SQLError(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)18274 SQLError(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
18275 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
18276 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
18277 {
18278     return drverror(env, dbc, stmt, sqlState, nativeErr,
18279 		    errmsg, errmax, errlen);
18280 }
18281 #endif
18282 
18283 #ifdef WINTERFACE
18284 /**
18285  * Return last HDBC or HSTMT error message (UNICODE version).
18286  * @param env environment handle or NULL
18287  * @param dbc database connection handle or NULL
18288  * @param stmt statement handle or NULL
18289  * @param sqlState output buffer for SQL state
18290  * @param nativeErr output buffer for native error code
18291  * @param errmsg output buffer for error message
18292  * @param errmax length of output buffer for error message
18293  * @param errlen output length of error message
18294  * @result ODBC error code
18295  */
18296 
18297 SQLRETURN SQL_API
SQLErrorW(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLWCHAR * sqlState,SQLINTEGER * nativeErr,SQLWCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)18298 SQLErrorW(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
18299 	  SQLWCHAR *sqlState, SQLINTEGER *nativeErr,
18300 	  SQLWCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
18301 {
18302     char state[16];
18303     SQLSMALLINT len = 0;
18304     SQLRETURN ret;
18305 
18306     ret = drverror(env, dbc, stmt, (SQLCHAR *) state, nativeErr,
18307 		   (SQLCHAR *) errmsg, errmax, &len);
18308     if (ret == SQL_SUCCESS) {
18309 	if (sqlState) {
18310 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlState,
18311 			    6 * sizeof (SQLWCHAR));
18312 	}
18313 	if (errmsg) {
18314 	    if (len > 0) {
18315 		SQLWCHAR *e = NULL;
18316 
18317 		e = uc_from_utf((SQLCHAR *) errmsg, len);
18318 		if (e) {
18319 		    if (errmax > 0) {
18320 			uc_strncpy(errmsg, e, errmax);
18321 			e[len] = 0;
18322 			len = min(errmax, uc_strlen(e));
18323 		    } else {
18324 			len = uc_strlen(e);
18325 		    }
18326 		    uc_free(e);
18327 		} else {
18328 		    len = 0;
18329 		}
18330 	    }
18331 	    if (len <= 0) {
18332 		len = 0;
18333 		if (errmax > 0) {
18334 		    errmsg[0] = 0;
18335 		}
18336 	    }
18337 	} else {
18338 	    len = 0;
18339 	}
18340 	if (errlen) {
18341 	    *errlen = len;
18342 	}
18343     } else if (ret == SQL_NO_DATA) {
18344 	if (sqlState) {
18345 	    sqlState[0] = 0;
18346 	}
18347 	if (errmsg) {
18348 	    if (errmax > 0) {
18349 		errmsg[0] = 0;
18350 	    }
18351 	}
18352 	if (errlen) {
18353 	    *errlen = 0;
18354 	}
18355     }
18356     return ret;
18357 }
18358 #endif
18359 
18360 /**
18361  * Return information for more result sets.
18362  * @param stmt statement handle
18363  * @result ODBC error code
18364  */
18365 
18366 SQLRETURN SQL_API
SQLMoreResults(SQLHSTMT stmt)18367 SQLMoreResults(SQLHSTMT stmt)
18368 {
18369     HSTMT_LOCK(stmt);
18370     if (stmt == SQL_NULL_HSTMT) {
18371 	return SQL_INVALID_HANDLE;
18372     }
18373     HSTMT_UNLOCK(stmt);
18374     return SQL_NO_DATA;
18375 }
18376 
18377 /**
18378  * Internal function to setup column name/type information
18379  * @param s statement poiner
18380  * @param s3stmt SQLite3 statement pointer
18381  * @param ncolsp pointer to preinitialized number of columns
18382  * @result ODBC error code
18383  */
18384 
18385 static SQLRETURN
setupdyncols(STMT * s,sqlite3_stmt * s3stmt,int * ncolsp)18386 setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp)
18387 {
18388     int ncols = *ncolsp, guessed_types = 0;
18389     SQLRETURN ret = SQL_SUCCESS;
18390 
18391     if (ncols > 0) {
18392 	int i;
18393 	PTRDIFF_T size;
18394 	char *p;
18395 	COL *dyncols;
18396 	DBC *d = (DBC *) s->dbc;
18397 	const char *colname, *typename;
18398 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
18399 	char *tblname;
18400 #endif
18401 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
18402 	char *dbname;
18403 #endif
18404 
18405 	for (i = size = 0; i < ncols; i++) {
18406 	    colname = sqlite3_column_name(s3stmt, i);
18407 	    size += 3 + 3 * strlen(colname);
18408 	}
18409 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
18410 	tblname = (char *) size;
18411 	for (i = 0; i < ncols; i++) {
18412 	    p = (char *) sqlite3_column_table_name(s3stmt, i);
18413 	    size += 2 + (p ? strlen(p) : 0);
18414 	}
18415 #endif
18416 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
18417 	dbname = (char *) size;
18418 	for (i = 0; i < ncols; i++) {
18419 	    p = (char *) sqlite3_column_database_name(s3stmt, i);
18420 	    size += 2 + (p ? strlen(p) : 0);
18421 	}
18422 #endif
18423 	dyncols = xmalloc(ncols * sizeof (COL) + size);
18424 	if (!dyncols) {
18425 	    freedyncols(s);
18426 	    *ncolsp = 0;
18427 	    ret = SQL_ERROR;
18428 	} else {
18429 	    p = (char *) (dyncols + ncols);
18430 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
18431 	    tblname = p + (PTRDIFF_T) tblname;
18432 #endif
18433 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
18434 	    dbname = p + (PTRDIFF_T) dbname;
18435 #endif
18436 	    for (i = 0; i < ncols; i++) {
18437 		char *q;
18438 
18439 		colname = sqlite3_column_name(s3stmt, i);
18440 		if (d->trace) {
18441 		    fprintf(d->trace, "-- column %d name: '%s'\n",
18442 			    i + 1, colname);
18443 		    fflush(d->trace);
18444 		}
18445 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
18446 		q = (char *) sqlite3_column_table_name(s3stmt, i);
18447 		strcpy(tblname, q ? q : "");
18448 		if (d->trace) {
18449 		    fprintf(d->trace, "-- table %d name: '%s'\n",
18450 			    i + 1, tblname);
18451 		    fflush(d->trace);
18452 		}
18453 		dyncols[i].table = tblname;
18454 		tblname += strlen(tblname) + 1;
18455 #endif
18456 #if defined(HAVE_SQLITE3COLUMNDATABASENAME) && (HAVE_SQLITE3COLUMNDATABASENAME)
18457 		q = (char *) sqlite3_column_database_name(s3stmt, i);
18458 		strcpy(dbname, q ? q : "");
18459 		if (d->trace) {
18460 		    fprintf(d->trace, "-- database %d name: '%s'\n",
18461 			    i + 1, dbname);
18462 		    fflush(d->trace);
18463 		}
18464 		dyncols[i].db = dbname;
18465 		dbname += strlen(dbname) + 1;
18466 #else
18467 		dyncols[i].db = ((DBC *) (s->dbc))->dbname;
18468 #endif
18469 		typename = s3stmt_coltype(s3stmt, i, d, &guessed_types);
18470 		strcpy(p, colname);
18471 		dyncols[i].label = p;
18472 		p += strlen(p) + 1;
18473 		q = strchr(colname, '.');
18474 		if (q) {
18475 		    char *q2 = strchr(q + 1, '.');
18476 
18477 		    /* SQLite 3.3.4 produces view.table.column sometimes */
18478 		    if (q2) {
18479 			q = q2;
18480 		    }
18481 		}
18482 		if (q) {
18483 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
18484 		    dyncols[i].table = p;
18485 #endif
18486 		    strncpy(p, colname, q - colname);
18487 		    p[q - colname] = '\0';
18488 		    p += strlen(p) + 1;
18489 		    strcpy(p, q + 1);
18490 		    dyncols[i].column = p;
18491 		    p += strlen(p) + 1;
18492 		} else {
18493 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
18494 		    dyncols[i].table = "";
18495 #endif
18496 		    strcpy(p, colname);
18497 		    dyncols[i].column = p;
18498 		    p += strlen(p) + 1;
18499 		}
18500 		if (s->longnames) {
18501 		    dyncols[i].column = dyncols[i].label;
18502 		}
18503 #ifdef SQL_LONGVARCHAR
18504 		dyncols[i].type = SQL_LONGVARCHAR;
18505 		dyncols[i].size = 65535;
18506 #else
18507 		dyncols[i].type = SQL_VARCHAR;
18508 		dyncols[i].size = 255;
18509 #endif
18510 		dyncols[i].index = i;
18511 		dyncols[i].scale = 0;
18512 		dyncols[i].prec = 0;
18513 		dyncols[i].nosign = 1;
18514 		dyncols[i].autoinc = SQL_FALSE;
18515 		dyncols[i].notnull = SQL_NULLABLE;
18516 		dyncols[i].ispk = -1;
18517 		dyncols[i].isrowid = -1;
18518 #ifdef FULL_METADATA
18519 		s3stmt_addmeta(s3stmt, i, d, &dyncols[i]);
18520 #endif
18521 		dyncols[i].typename = xstrdup(typename);
18522 	    }
18523 	    freedyncols(s);
18524 	    s->dyncols = s->cols = dyncols;
18525 	    s->dcols = ncols;
18526 	    fixupdyncols(s, d);
18527 	    s->guessed_types = guessed_types;
18528 	}
18529     }
18530     return ret;
18531 }
18532 
18533 /**
18534  * Internal query preparation used by SQLPrepare() and SQLExecDirect().
18535  * @param stmt statement handle
18536  * @param query query string
18537  * @param queryLen length of query string or SQL_NTS
18538  * @result ODBC error code
18539  */
18540 
18541 static SQLRETURN
drvprepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)18542 drvprepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
18543 {
18544     STMT *s;
18545     DBC *d;
18546     char *errp = NULL;
18547     SQLRETURN sret;
18548 
18549     if (stmt == SQL_NULL_HSTMT) {
18550 	return SQL_INVALID_HANDLE;
18551     }
18552     s = (STMT *) stmt;
18553     if (s->dbc == SQL_NULL_HDBC) {
18554 noconn:
18555 	return noconn(s);
18556     }
18557     d = s->dbc;
18558     if (!d->sqlite) {
18559 	goto noconn;
18560     }
18561     s3stmt_end(s);
18562     s3stmt_drop(s);
18563     sret = starttran(s);
18564     if (sret != SQL_SUCCESS) {
18565 	return sret;
18566     }
18567     freep(&s->query);
18568     s->query = (SQLCHAR *) fixupsql((char *) query, queryLen,
18569 				    (d->version >= 0x030805),
18570 				    &s->nparams, &s->isselect, &errp);
18571     if (!s->query) {
18572 	if (errp) {
18573 	    setstat(s, -1, "%s", (*s->ov3) ? "HY000" : "S1000", errp);
18574 	    return SQL_ERROR;
18575 	}
18576 	return nomem(s);
18577     }
18578     errp = NULL;
18579     freeresult(s, -1);
18580     if (s->isselect == 1) {
18581 	int ret, ncols, nretry = 0;
18582 	const char *rest;
18583 	sqlite3_stmt *s3stmt = NULL;
18584 
18585 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
18586 	dbtraceapi(d, "sqlite3_prepare_v2", (char *) s->query);
18587 #else
18588 	dbtraceapi(d, "sqlite3_prepare", (char *) s->query);
18589 #endif
18590 	do {
18591 	    s3stmt = NULL;
18592 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
18593 	    ret = sqlite3_prepare_v2(d->sqlite, (char *) s->query, -1,
18594 				     &s3stmt, &rest);
18595 #else
18596 	    ret = sqlite3_prepare(d->sqlite, (char *) s->query, -1,
18597 				  &s3stmt, &rest);
18598 #endif
18599 	    if (ret != SQLITE_OK) {
18600 		if (s3stmt) {
18601 		    sqlite3_finalize(s3stmt);
18602 		    s3stmt = NULL;
18603 		}
18604 	    }
18605 	} while (ret == SQLITE_SCHEMA && (++nretry) < 2);
18606 	dbtracerc(d, ret, NULL);
18607 	if (ret != SQLITE_OK) {
18608 	    if (s3stmt) {
18609 		dbtraceapi(d, "sqlite3_finalize", 0);
18610 		sqlite3_finalize(s3stmt);
18611 	    }
18612 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
18613 		    sqlite3_errmsg(d->sqlite), ret);
18614 	    return SQL_ERROR;
18615 	}
18616 	if (sqlite3_bind_parameter_count(s3stmt) != s->nparams) {
18617 	    dbtraceapi(d, "sqlite3_finalize", 0);
18618 	    sqlite3_finalize(s3stmt);
18619 	    setstat(s, SQLITE_ERROR, "parameter marker count incorrect",
18620 		    (*s->ov3) ? "HY000" : "S1000");
18621 	    return SQL_ERROR;
18622 	}
18623 	ncols = sqlite3_column_count(s3stmt);
18624 	s->guessed_types = 0;
18625 	setupdyncols(s, s3stmt, &ncols);
18626 	s->ncols = ncols;
18627 	s->s3stmt = s3stmt;
18628     }
18629     mkbindcols(s, s->ncols);
18630     s->paramset_count = 0;
18631     return SQL_SUCCESS;
18632 }
18633 
18634 /**
18635  * Internal query execution used by SQLExecute() and SQLExecDirect().
18636  * @param stmt statement handle
18637  * @param initial false when called from SQLPutData()
18638  * @result ODBC error code
18639  */
18640 
18641 static SQLRETURN
drvexecute(SQLHSTMT stmt,int initial)18642 drvexecute(SQLHSTMT stmt, int initial)
18643 {
18644     STMT *s;
18645     DBC *d;
18646     char *errp = NULL;
18647     int rc, i, ncols = 0, nrows = 0, busy_count;
18648     SQLRETURN ret;
18649 
18650     if (stmt == SQL_NULL_HSTMT) {
18651 	return SQL_INVALID_HANDLE;
18652     }
18653     s = (STMT *) stmt;
18654     if (s->dbc == SQL_NULL_HDBC) {
18655 noconn:
18656 	return noconn(s);
18657     }
18658     d = (DBC *) s->dbc;
18659     if (!d->sqlite) {
18660 	goto noconn;
18661     }
18662     if (!s->query) {
18663 	setstat(s, -1, "no query prepared", (*s->ov3) ? "HY000" : "S1000");
18664 	return SQL_ERROR;
18665     }
18666     if (s->nbindparms < s->nparams) {
18667 unbound:
18668 	setstat(s, -1, "unbound parameters in query",
18669 		(*s->ov3) ? "HY000" : "S1000");
18670 	return SQL_ERROR;
18671     }
18672     for (i = 0; i < s->nparams; i++) {
18673 	BINDPARM *p = &s->bindparms[i];
18674 
18675 	if (!p->bound) {
18676 	    goto unbound;
18677 	}
18678 	if (initial) {
18679 	    SQLLEN *lenp = p->lenp;
18680 
18681 	    if (lenp && *lenp < 0 && *lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
18682 		*lenp != SQL_NTS && *lenp != SQL_NULL_DATA &&
18683 		*lenp != SQL_DATA_AT_EXEC) {
18684 		setstat(s, -1, "invalid length reference", "HY009");
18685 		return SQL_ERROR;
18686 	    }
18687 	    if (lenp && (*lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
18688 			 *lenp == SQL_DATA_AT_EXEC)) {
18689 		p->need = 1;
18690 		p->offs = 0;
18691 		p->len = 0;
18692 	    }
18693 	}
18694     }
18695     ret = starttran(s);
18696     if (ret != SQL_SUCCESS) {
18697 	goto cleanup;
18698     }
18699     busy_count = 0;
18700 again:
18701     s3stmt_end(s);
18702     if (initial) {
18703 	/* fixup data-at-execution parameters and alloc'ed blobs */
18704 	s->pdcount = -1;
18705 	for (i = 0; i < s->nparams; i++) {
18706 	    BINDPARM *p = &s->bindparms[i];
18707 
18708 	    if (p->param == p->parbuf) {
18709 		p->param = NULL;
18710 	    }
18711 	    freep(&p->parbuf);
18712 	    if (p->need <= 0 &&
18713 		p->lenp && (*p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
18714 			    *p->lenp == SQL_DATA_AT_EXEC)) {
18715 		p->need = 1;
18716 		p->offs = 0;
18717 		p->len = 0;
18718 	    }
18719 	}
18720     }
18721     if (s->nparams) {
18722 	for (i = 0; i < s->nparams; i++) {
18723 	    ret = setupparam(s, (char *) s->query, i);
18724 	    if (ret != SQL_SUCCESS) {
18725 		goto cleanup;
18726 	    }
18727 	}
18728     }
18729     freeresult(s, 0);
18730     if (s->isselect == 1 && !d->intrans &&
18731 	s->curtype == SQL_CURSOR_FORWARD_ONLY &&
18732 	d->step_enable && s->nparams == 0 && d->cur_s3stmt == NULL) {
18733 	s->nrows = -1;
18734 	ret = s3stmt_start(s);
18735 	if (ret == SQL_SUCCESS) {
18736 	    goto done2;
18737 	}
18738     }
18739     rc = drvgettable(s, s->s3stmt ? NULL : (char *) s->query, &s->rows,
18740 		     &s->nrows, &ncols, &errp, s->nparams, s->bindparms);
18741     dbtracerc(d, rc, errp);
18742     if (rc == SQLITE_BUSY) {
18743 	if (busy_handler((void *) d, ++busy_count)) {
18744 	    if (errp) {
18745 		sqlite3_free(errp);
18746 		errp = NULL;
18747 	    }
18748 	    for (i = 0; i < s->nparams; i++) {
18749 		BINDPARM *p = &s->bindparms[i];
18750 
18751 		if (p->param == p->parbuf) {
18752 		    p->param = NULL;
18753 		}
18754 		freep(&p->parbuf);
18755 		if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
18756 				 *p->lenp != SQL_DATA_AT_EXEC)) {
18757 		    p->param = p->param0;
18758 		}
18759 		p->lenp = p->lenp0;
18760 	    }
18761 	    s->nrows = 0;
18762 	    goto again;
18763 	}
18764     }
18765     if (rc != SQLITE_OK) {
18766 	setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
18767 		errp ? errp : "unknown error", rc);
18768 	if (errp) {
18769 	    sqlite3_free(errp);
18770 	    errp = NULL;
18771 	}
18772 	ret = SQL_ERROR;
18773 	goto cleanup;
18774     }
18775     if (errp) {
18776 	sqlite3_free(errp);
18777 	errp = NULL;
18778     }
18779     s->rowfree = freerows;
18780     if (s->isselect <= 0 || s->isselect > 1) {
18781 	/*
18782 	 * INSERT/UPDATE/DELETE or DDL results are immediately released.
18783 	 */
18784 	freeresult(s, -1);
18785 	nrows += sqlite3_changes(d->sqlite);
18786 	s->nrows = nrows;
18787 	goto done;
18788     }
18789     if (s->ncols != ncols) {
18790 	/*
18791 	 * Weird result.
18792 	 */
18793 	setstat(s, -1, "broken result set %d/%d",
18794 		(*s->ov3) ? "HY000" : "S1000", s->ncols, ncols);
18795 	ret = SQL_ERROR;
18796 	goto cleanup;
18797     }
18798 done:
18799     mkbindcols(s, s->ncols);
18800 done2:
18801     ret = SQL_SUCCESS;
18802     s->rowp = s->rowprs = -1;
18803     s->paramset_count++;
18804     s->paramset_nrows = s->nrows;
18805     if (s->paramset_count < s->paramset_size) {
18806 	for (i = 0; i < s->nparams; i++) {
18807 	    BINDPARM *p = &s->bindparms[i];
18808 
18809 	    if (p->param == p->parbuf) {
18810 		p->param = NULL;
18811 	    }
18812 	    freep(&p->parbuf);
18813 	    if (p->lenp0 &&
18814 		s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
18815 		p->lenp = (SQLLEN *) ((char *) p->lenp0 +
18816 				      s->paramset_count * s->parm_bind_type);
18817 	    } else if (p->lenp0 && p->inc > 0) {
18818 		p->lenp = p->lenp0 + s->paramset_count;
18819 	    }
18820 	    if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
18821 			     *p->lenp != SQL_DATA_AT_EXEC)) {
18822 		if (p->param0 &&
18823 		    s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
18824 		    p->param = (char *) p->param0 +
18825 			s->paramset_count * s->parm_bind_type;
18826 		} else if (p->param0 && p->inc > 0) {
18827 		    p->param = (char *) p->param0 +
18828 			s->paramset_count * p->inc;
18829 		}
18830 	    } else if (p->lenp && (*p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
18831 				   *p->lenp == SQL_DATA_AT_EXEC)) {
18832 		p->need = 1;
18833 		p->offs = 0;
18834 		p->len = 0;
18835 	    }
18836 	}
18837 	goto again;
18838     }
18839 cleanup:
18840     if (ret != SQL_NEED_DATA) {
18841 	for (i = 0; i < s->nparams; i++) {
18842 	    BINDPARM *p = &s->bindparms[i];
18843 
18844 	    if (p->param == p->parbuf) {
18845 		p->param = NULL;
18846 	    }
18847 	    freep(&p->parbuf);
18848 	    if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
18849 			     *p->lenp != SQL_DATA_AT_EXEC)) {
18850 		p->param = p->param0;
18851 	    }
18852 	    p->lenp = p->lenp0;
18853 	}
18854 	s->nrows = s->paramset_nrows;
18855 	if (s->parm_proc) {
18856 	    *s->parm_proc = s->paramset_count;
18857 	}
18858 	s->paramset_count = 0;
18859 	s->paramset_nrows = 0;
18860     }
18861     /*
18862      * For INSERT/UPDATE/DELETE statements change the return code
18863      * to SQL_NO_DATA if the number of rows affected was 0.
18864      */
18865     if (*s->ov3 && s->isselect == 0 &&
18866 	ret == SQL_SUCCESS && nrows == 0) {
18867 	ret = SQL_NO_DATA;
18868     }
18869     return ret;
18870 }
18871 
18872 #ifndef WINTERFACE
18873 /**
18874  * Prepare HSTMT.
18875  * @param stmt statement handle
18876  * @param query query string
18877  * @param queryLen length of query string or SQL_NTS
18878  * @result ODBC error code
18879  */
18880 
18881 SQLRETURN SQL_API
SQLPrepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)18882 SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
18883 {
18884     SQLRETURN ret;
18885 #if defined(_WIN32) || defined(_WIN64)
18886     char *q;
18887 #endif
18888 
18889     HSTMT_LOCK(stmt);
18890 #if defined(_WIN32) || defined(_WIN64)
18891     if (!((STMT *) stmt)->oemcp[0]) {
18892 	ret = drvprepare(stmt, query, queryLen);
18893 	goto done;
18894     }
18895     q = wmb_to_utf_c((char *) query, queryLen);
18896     if (!q) {
18897 	ret = nomem((STMT *) stmt);
18898 	goto done;
18899     }
18900     query = (SQLCHAR *) q;
18901     queryLen = SQL_NTS;
18902 #endif
18903     ret = drvprepare(stmt, query, queryLen);
18904 #if defined(_WIN32) || defined(_WIN64)
18905     uc_free(q);
18906 done:
18907     ;
18908 #endif
18909     HSTMT_UNLOCK(stmt);
18910     return ret;
18911 }
18912 #endif
18913 
18914 #ifdef WINTERFACE
18915 /**
18916  * Prepare HSTMT (UNICODE version).
18917  * @param stmt statement handle
18918  * @param query query string
18919  * @param queryLen length of query string or SQL_NTS
18920  * @result ODBC error code
18921  */
18922 
18923 SQLRETURN SQL_API
SQLPrepareW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)18924 SQLPrepareW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
18925 {
18926     SQLRETURN ret;
18927     char *q = uc_to_utf_c(query, queryLen);
18928 
18929     HSTMT_LOCK(stmt);
18930     if (!q) {
18931 	ret = nomem((STMT *) stmt);
18932 	goto done;
18933     }
18934     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
18935     uc_free(q);
18936 done:
18937     HSTMT_UNLOCK(stmt);
18938     return ret;
18939 }
18940 #endif
18941 
18942 /**
18943  * Execute query.
18944  * @param stmt statement handle
18945  * @result ODBC error code
18946  */
18947 
18948 SQLRETURN SQL_API
SQLExecute(SQLHSTMT stmt)18949 SQLExecute(SQLHSTMT stmt)
18950 {
18951     SQLRETURN ret;
18952 
18953     HSTMT_LOCK(stmt);
18954     ret = drvexecute(stmt, 1);
18955     HSTMT_UNLOCK(stmt);
18956     return ret;
18957 }
18958 
18959 #ifndef WINTERFACE
18960 /**
18961  * Execute query directly.
18962  * @param stmt statement handle
18963  * @param query query string
18964  * @param queryLen length of query string or SQL_NTS
18965  * @result ODBC error code
18966  */
18967 
18968 SQLRETURN SQL_API
SQLExecDirect(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)18969 SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
18970 {
18971     SQLRETURN ret;
18972 #if defined(_WIN32) || defined(_WIN64)
18973     char *q;
18974 #endif
18975 
18976     HSTMT_LOCK(stmt);
18977 #if defined(_WIN32) || defined(_WIN64)
18978     if (!((STMT *) stmt)->oemcp[0]) {
18979 	ret = drvprepare(stmt, query, queryLen);
18980 	if (ret == SQL_SUCCESS) {
18981 	    ret = drvexecute(stmt, 1);
18982 	}
18983 	goto done;
18984     }
18985     q = wmb_to_utf_c((char *) query, queryLen);
18986     if (!q) {
18987 	ret = nomem((STMT *) stmt);
18988 	goto done;
18989     }
18990     query = (SQLCHAR *) q;
18991     queryLen = SQL_NTS;
18992 #endif
18993     ret = drvprepare(stmt, query, queryLen);
18994     if (ret == SQL_SUCCESS) {
18995 	ret = drvexecute(stmt, 1);
18996     }
18997 #if defined(_WIN32) || defined(_WIN64)
18998     uc_free(q);
18999 done:
19000     ;
19001 #endif
19002     HSTMT_UNLOCK(stmt);
19003     return ret;
19004 }
19005 #endif
19006 
19007 #ifdef WINTERFACE
19008 /**
19009  * Execute query directly (UNICODE version).
19010  * @param stmt statement handle
19011  * @param query query string
19012  * @param queryLen length of query string or SQL_NTS
19013  * @result ODBC error code
19014  */
19015 
19016 SQLRETURN SQL_API
SQLExecDirectW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)19017 SQLExecDirectW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
19018 {
19019     SQLRETURN ret;
19020     char *q = uc_to_utf_c(query, queryLen);
19021 
19022     HSTMT_LOCK(stmt);
19023     if (!q) {
19024 	ret = nomem((STMT *) stmt);
19025 	goto done;
19026     }
19027     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
19028     uc_free(q);
19029     if (ret == SQL_SUCCESS) {
19030 	ret = drvexecute(stmt, 1);
19031     }
19032 done:
19033     HSTMT_UNLOCK(stmt);
19034     return ret;
19035 }
19036 #endif
19037 
19038 
19039 #if defined(_WIN32) || defined(_WIN64)
19040 #ifndef WITHOUT_DRIVERMGR
19041 
19042 /*
19043  * Windows configuration dialog stuff.
19044  */
19045 
19046 #include <windowsx.h>
19047 #include <winuser.h>
19048 
19049 #define MAXPATHLEN      (259+1)           /* Max path length */
19050 #define MAXKEYLEN       (15+1)            /* Max keyword length */
19051 #define MAXDESC         (255+1)           /* Max description length */
19052 #define MAXDSNAME       (255+1)           /* Max data source name length */
19053 #define MAXTONAME       (32+1)            /* Max timeout length */
19054 #define MAXDBNAME       MAXPATHLEN
19055 
19056 /* Attribute key indexes into an array of Attr structs, see below */
19057 
19058 #define KEY_DSN 		0
19059 #define KEY_DESC		1
19060 #define KEY_DBNAME		2
19061 #define KEY_BUSY		3
19062 #define KEY_DRIVER		4
19063 #define KEY_STEPAPI		5
19064 #define KEY_SYNCP		6
19065 #define KEY_NOTXN		7
19066 #define KEY_SHORTNAM		8
19067 #define KEY_LONGNAM		9
19068 #define KEY_NOCREAT	       10
19069 #define KEY_NOWCHAR	       11
19070 #define KEY_LOADEXT	       12
19071 #define KEY_JMODE              13
19072 #define KEY_FKSUPPORT          14
19073 #define KEY_OEMCP              15
19074 #define KEY_BIGINT             16
19075 #define KEY_PASSWD             17
19076 #define KEY_JDCONV             18
19077 #define NUMOFKEYS	       19
19078 
19079 typedef struct {
19080     BOOL supplied;
19081     char attr[MAXPATHLEN*4];
19082 } ATTR;
19083 
19084 typedef struct {
19085     SQLHWND parent;
19086     LPCSTR  driver;
19087     ATTR    attr[NUMOFKEYS];
19088     char    DSN[MAXDSNAME];
19089     BOOL    newDSN;
19090     BOOL    defDSN;
19091 } SETUPDLG;
19092 
19093 static struct {
19094     char *key;
19095     int ikey;
19096 } attrLookup[] = {
19097     { "DSN", KEY_DSN },
19098     { "DESC", KEY_DESC },
19099     { "Description", KEY_DESC},
19100     { "Database", KEY_DBNAME },
19101     { "Timeout", KEY_BUSY },
19102     { "Driver", KEY_DRIVER },
19103     { "StepAPI", KEY_STEPAPI },
19104     { "SyncPragma", KEY_SYNCP },
19105     { "NoTXN", KEY_NOTXN },
19106     { "ShortNames", KEY_SHORTNAM },
19107     { "LongNames", KEY_LONGNAM },
19108     { "NoCreat", KEY_NOCREAT },
19109     { "NoWCHAR", KEY_NOWCHAR },
19110     { "LoadExt", KEY_LOADEXT },
19111     { "JournalMode", KEY_JMODE },
19112     { "FKSupport", KEY_FKSUPPORT },
19113     { "OEMCP", KEY_OEMCP },
19114     { "BigInt", KEY_BIGINT },
19115     { "PWD", KEY_PASSWD },
19116     { "JDConv", KEY_JDCONV },
19117     { NULL, 0 }
19118 };
19119 
19120 /**
19121  * Setup dialog data from datasource attributes.
19122  * @param attribs attribute string
19123  * @param setupdlg pointer to dialog data
19124  */
19125 
19126 static void
ParseAttributes(LPCSTR attribs,SETUPDLG * setupdlg)19127 ParseAttributes(LPCSTR attribs, SETUPDLG *setupdlg)
19128 {
19129     char *str = (char *) attribs, *start, key[MAXKEYLEN];
19130     int elem, nkey;
19131 
19132     while (*str) {
19133 	start = str;
19134 	if ((str = strchr(str, '=')) == NULL) {
19135 	    return;
19136 	}
19137 	elem = -1;
19138 	nkey = str - start;
19139 	if (nkey < sizeof (key)) {
19140 	    int i;
19141 
19142 	    memcpy(key, start, nkey);
19143 	    key[nkey] = '\0';
19144 	    for (i = 0; attrLookup[i].key; i++) {
19145 		if (strcasecmp(attrLookup[i].key, key) == 0) {
19146 		    elem = attrLookup[i].ikey;
19147 		    break;
19148 		}
19149 	    }
19150 	}
19151 	start = ++str;
19152 	while (*str && *str != ';') {
19153 	    ++str;
19154 	}
19155 	if (elem >= 0) {
19156 	    int end = min(str - start, sizeof (setupdlg->attr[elem].attr) - 1);
19157 
19158 	    setupdlg->attr[elem].supplied = TRUE;
19159 	    memcpy(setupdlg->attr[elem].attr, start, end);
19160 	    setupdlg->attr[elem].attr[end] = '\0';
19161 	}
19162 	++str;
19163     }
19164 }
19165 
19166 /**
19167  * Set datasource attributes in registry.
19168  * @param parent handle of parent window
19169  * @param setupdlg pointer to dialog data
19170  * @result true or false
19171  */
19172 
19173 static BOOL
SetDSNAttributes(HWND parent,SETUPDLG * setupdlg)19174 SetDSNAttributes(HWND parent, SETUPDLG *setupdlg)
19175 {
19176     char *dsn = setupdlg->attr[KEY_DSN].attr;
19177 
19178     if (setupdlg->newDSN && strlen(dsn) == 0) {
19179 	return FALSE;
19180     }
19181     if (!SQLWriteDSNToIni(dsn, setupdlg->driver)) {
19182 	if (parent) {
19183 	    char buf[MAXPATHLEN], msg[MAXPATHLEN];
19184 
19185 	    LoadString(hModule, IDS_BADDSN, buf, sizeof (buf));
19186 	    wsprintf(msg, buf, dsn);
19187 	    LoadString(hModule, IDS_MSGTITLE, buf, sizeof (buf));
19188 	    MessageBox(parent, msg, buf,
19189 		       MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
19190 		       MB_SETFOREGROUND);
19191 	}
19192 	return FALSE;
19193     }
19194     if (parent || setupdlg->attr[KEY_DESC].supplied) {
19195 	SQLWritePrivateProfileString(dsn, "Description",
19196 				     setupdlg->attr[KEY_DESC].attr,
19197 				     ODBC_INI);
19198     }
19199     if (parent || setupdlg->attr[KEY_DBNAME].supplied) {
19200 	SQLWritePrivateProfileString(dsn, "Database",
19201 				     setupdlg->attr[KEY_DBNAME].attr,
19202 				     ODBC_INI);
19203     }
19204     if (parent || setupdlg->attr[KEY_BUSY].supplied) {
19205 	SQLWritePrivateProfileString(dsn, "Timeout",
19206 				     setupdlg->attr[KEY_BUSY].attr,
19207 				     ODBC_INI);
19208     }
19209     if (parent || setupdlg->attr[KEY_STEPAPI].supplied) {
19210 	SQLWritePrivateProfileString(dsn, "StepAPI",
19211 				     setupdlg->attr[KEY_STEPAPI].attr,
19212 				     ODBC_INI);
19213     }
19214     if (parent || setupdlg->attr[KEY_SYNCP].supplied) {
19215 	SQLWritePrivateProfileString(dsn, "SyncPragma",
19216 				     setupdlg->attr[KEY_SYNCP].attr,
19217 				     ODBC_INI);
19218     }
19219     if (parent || setupdlg->attr[KEY_NOTXN].supplied) {
19220 	SQLWritePrivateProfileString(dsn, "NoTXN",
19221 				     setupdlg->attr[KEY_NOTXN].attr,
19222 				     ODBC_INI);
19223     }
19224     if (parent || setupdlg->attr[KEY_SHORTNAM].supplied) {
19225 	SQLWritePrivateProfileString(dsn, "ShortNames",
19226 				     setupdlg->attr[KEY_SHORTNAM].attr,
19227 				     ODBC_INI);
19228     }
19229     if (parent || setupdlg->attr[KEY_LONGNAM].supplied) {
19230 	SQLWritePrivateProfileString(dsn, "LongNames",
19231 				     setupdlg->attr[KEY_LONGNAM].attr,
19232 				     ODBC_INI);
19233     }
19234     if (parent || setupdlg->attr[KEY_NOCREAT].supplied) {
19235 	SQLWritePrivateProfileString(dsn, "NoCreat",
19236 				     setupdlg->attr[KEY_NOCREAT].attr,
19237 				     ODBC_INI);
19238     }
19239     if (parent || setupdlg->attr[KEY_NOWCHAR].supplied) {
19240 	SQLWritePrivateProfileString(dsn, "NoWCHAR",
19241 				     setupdlg->attr[KEY_NOWCHAR].attr,
19242 				     ODBC_INI);
19243     }
19244     if (parent || setupdlg->attr[KEY_FKSUPPORT].supplied) {
19245 	SQLWritePrivateProfileString(dsn, "FKSupport",
19246 				     setupdlg->attr[KEY_FKSUPPORT].attr,
19247 				     ODBC_INI);
19248     }
19249     if (parent || setupdlg->attr[KEY_OEMCP].supplied) {
19250 	SQLWritePrivateProfileString(dsn, "OEMCP",
19251 				     setupdlg->attr[KEY_OEMCP].attr,
19252 				     ODBC_INI);
19253     }
19254     if (parent || setupdlg->attr[KEY_LOADEXT].supplied) {
19255 	SQLWritePrivateProfileString(dsn, "LoadExt",
19256 				     setupdlg->attr[KEY_LOADEXT].attr,
19257 				     ODBC_INI);
19258     }
19259     if (parent || setupdlg->attr[KEY_BIGINT].supplied) {
19260 	SQLWritePrivateProfileString(dsn, "BigInt",
19261 				     setupdlg->attr[KEY_BIGINT].attr,
19262 				     ODBC_INI);
19263     }
19264     if (parent || setupdlg->attr[KEY_JDCONV].supplied) {
19265 	SQLWritePrivateProfileString(dsn, "JDConv",
19266 				     setupdlg->attr[KEY_JDCONV].attr,
19267 				     ODBC_INI);
19268     }
19269     if (parent || setupdlg->attr[KEY_PASSWD].supplied) {
19270 	SQLWritePrivateProfileString(dsn, "PWD",
19271 				     setupdlg->attr[KEY_PASSWD].attr,
19272 				     ODBC_INI);
19273     }
19274     if (setupdlg->attr[KEY_DSN].supplied &&
19275 	strcasecmp(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr)) {
19276 	SQLRemoveDSNFromIni(setupdlg->DSN);
19277     }
19278     return TRUE;
19279 }
19280 
19281 /**
19282  * Get datasource attributes from registry.
19283  * @param setupdlg pointer to dialog data
19284  */
19285 
19286 static void
GetAttributes(SETUPDLG * setupdlg)19287 GetAttributes(SETUPDLG *setupdlg)
19288 {
19289     char *dsn = setupdlg->attr[KEY_DSN].attr;
19290 
19291     if (!setupdlg->attr[KEY_DESC].supplied) {
19292 	SQLGetPrivateProfileString(dsn, "Description", "",
19293 				   setupdlg->attr[KEY_DESC].attr,
19294 				   sizeof (setupdlg->attr[KEY_DESC].attr),
19295 				   ODBC_INI);
19296     }
19297     if (!setupdlg->attr[KEY_DBNAME].supplied) {
19298 	SQLGetPrivateProfileString(dsn, "Database", "",
19299 				   setupdlg->attr[KEY_DBNAME].attr,
19300 				   sizeof (setupdlg->attr[KEY_DBNAME].attr),
19301 				   ODBC_INI);
19302     }
19303     if (!setupdlg->attr[KEY_BUSY].supplied) {
19304 	SQLGetPrivateProfileString(dsn, "Timeout", "100000",
19305 				   setupdlg->attr[KEY_BUSY].attr,
19306 				   sizeof (setupdlg->attr[KEY_BUSY].attr),
19307 				   ODBC_INI);
19308     }
19309     if (!setupdlg->attr[KEY_STEPAPI].supplied) {
19310 	SQLGetPrivateProfileString(dsn, "StepAPI", "0",
19311 				   setupdlg->attr[KEY_STEPAPI].attr,
19312 				   sizeof (setupdlg->attr[KEY_STEPAPI].attr),
19313 				   ODBC_INI);
19314     }
19315     if (!setupdlg->attr[KEY_SYNCP].supplied) {
19316 	SQLGetPrivateProfileString(dsn, "SyncPragma", "NORMAL",
19317 				   setupdlg->attr[KEY_SYNCP].attr,
19318 				   sizeof (setupdlg->attr[KEY_SYNCP].attr),
19319 				   ODBC_INI);
19320     }
19321     if (!setupdlg->attr[KEY_NOTXN].supplied) {
19322 	SQLGetPrivateProfileString(dsn, "NoTXN", "",
19323 				   setupdlg->attr[KEY_NOTXN].attr,
19324 				   sizeof (setupdlg->attr[KEY_NOTXN].attr),
19325 				   ODBC_INI);
19326     }
19327     if (!setupdlg->attr[KEY_SHORTNAM].supplied) {
19328 	SQLGetPrivateProfileString(dsn, "ShortNames", "",
19329 				   setupdlg->attr[KEY_SHORTNAM].attr,
19330 				   sizeof (setupdlg->attr[KEY_SHORTNAM].attr),
19331 				   ODBC_INI);
19332     }
19333     if (!setupdlg->attr[KEY_LONGNAM].supplied) {
19334 	SQLGetPrivateProfileString(dsn, "LongNames", "",
19335 				   setupdlg->attr[KEY_LONGNAM].attr,
19336 				   sizeof (setupdlg->attr[KEY_LONGNAM].attr),
19337 				   ODBC_INI);
19338     }
19339     if (!setupdlg->attr[KEY_NOCREAT].supplied) {
19340 	SQLGetPrivateProfileString(dsn, "NoCreat", "",
19341 				   setupdlg->attr[KEY_NOCREAT].attr,
19342 				   sizeof (setupdlg->attr[KEY_NOCREAT].attr),
19343 				   ODBC_INI);
19344     }
19345     if (!setupdlg->attr[KEY_NOWCHAR].supplied) {
19346 	SQLGetPrivateProfileString(dsn, "NoWCHAR", "",
19347 				   setupdlg->attr[KEY_NOWCHAR].attr,
19348 				   sizeof (setupdlg->attr[KEY_NOWCHAR].attr),
19349 				   ODBC_INI);
19350     }
19351     if (!setupdlg->attr[KEY_FKSUPPORT].supplied) {
19352 	SQLGetPrivateProfileString(dsn, "FKSupport", "",
19353 				   setupdlg->attr[KEY_FKSUPPORT].attr,
19354 				   sizeof (setupdlg->attr[KEY_FKSUPPORT].attr),
19355 				   ODBC_INI);
19356     }
19357     if (!setupdlg->attr[KEY_OEMCP].supplied) {
19358 	SQLGetPrivateProfileString(dsn, "OEMCP", "",
19359 				   setupdlg->attr[KEY_OEMCP].attr,
19360 				   sizeof (setupdlg->attr[KEY_OEMCP].attr),
19361 				   ODBC_INI);
19362     }
19363     if (!setupdlg->attr[KEY_LOADEXT].supplied) {
19364 	SQLGetPrivateProfileString(dsn, "LoadExt", "",
19365 				   setupdlg->attr[KEY_LOADEXT].attr,
19366 				   sizeof (setupdlg->attr[KEY_LOADEXT].attr),
19367 				   ODBC_INI);
19368     }
19369     if (!setupdlg->attr[KEY_JMODE].supplied) {
19370 	SQLGetPrivateProfileString(dsn, "JournalMode", "",
19371 				   setupdlg->attr[KEY_JMODE].attr,
19372 				   sizeof (setupdlg->attr[KEY_JMODE].attr),
19373 				   ODBC_INI);
19374     }
19375     if (!setupdlg->attr[KEY_BIGINT].supplied) {
19376 	SQLGetPrivateProfileString(dsn, "BigInt", "",
19377 				   setupdlg->attr[KEY_BIGINT].attr,
19378 				   sizeof (setupdlg->attr[KEY_BIGINT].attr),
19379 				   ODBC_INI);
19380     }
19381     if (!setupdlg->attr[KEY_PASSWD].supplied) {
19382 	SQLGetPrivateProfileString(dsn, "PWD", "",
19383 				   setupdlg->attr[KEY_PASSWD].attr,
19384 				   sizeof (setupdlg->attr[KEY_PASSWD].attr),
19385 				   ODBC_INI);
19386     }
19387     if (!setupdlg->attr[KEY_JDCONV].supplied) {
19388 	SQLGetPrivateProfileString(dsn, "JDConv", "",
19389 				   setupdlg->attr[KEY_JDCONV].attr,
19390 				   sizeof (setupdlg->attr[KEY_JDCONV].attr),
19391 				   ODBC_INI);
19392     }
19393 }
19394 
19395 /**
19396  * Open file dialog for selection of SQLite database file.
19397  * @param hdlg handle of originating dialog window
19398  */
19399 
19400 static void
GetDBFile(HWND hdlg)19401 GetDBFile(HWND hdlg)
19402 {
19403 #ifdef _WIN64
19404     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
19405 #else
19406     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
19407 #endif
19408     OPENFILENAME ofn;
19409 
19410     memset(&ofn, 0, sizeof (ofn));
19411     ofn.lStructSize = sizeof (ofn);
19412     ofn.hwndOwner = hdlg;
19413 #ifdef _WIN64
19414     ofn.hInstance = (HINSTANCE) GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
19415 #else
19416     ofn.hInstance = (HINSTANCE) GetWindowLong(hdlg, GWL_HINSTANCE);
19417 #endif
19418     ofn.lpstrFile = (LPTSTR) setupdlg->attr[KEY_DBNAME].attr;
19419     ofn.nMaxFile = MAXPATHLEN;
19420     ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
19421 		OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_FILEMUSTEXIST;
19422     if (GetOpenFileName(&ofn)) {
19423 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
19424 	setupdlg->attr[KEY_DBNAME].supplied = TRUE;
19425     }
19426 }
19427 
19428 /**
19429  * Dialog procedure for ConfigDSN().
19430  * @param hdlg handle of dialog window
19431  * @param wmsg type of message
19432  * @param wparam wparam of message
19433  * @param lparam lparam of message
19434  * @result true or false
19435  */
19436 
19437 static BOOL CALLBACK
ConfigDlgProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)19438 ConfigDlgProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
19439 {
19440     SETUPDLG *setupdlg = NULL;
19441     WORD index;
19442 
19443     switch (wmsg) {
19444     case WM_INITDIALOG:
19445 #ifdef _WIN64
19446 	SetWindowLongPtr(hdlg, DWLP_USER, lparam);
19447 #else
19448 	SetWindowLong(hdlg, DWL_USER, lparam);
19449 #endif
19450 	setupdlg = (SETUPDLG *) lparam;
19451 	GetAttributes(setupdlg);
19452 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
19453 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
19454 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
19455 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
19456 	SetDlgItemText(hdlg, IDC_LOADEXT, setupdlg->attr[KEY_LOADEXT].attr);
19457 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
19458 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
19459 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
19460 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
19461 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
19462 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
19463 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
19464 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
19465 	SendDlgItemMessage(hdlg, IDC_LOADEXT, EM_LIMITTEXT,
19466 			   (WPARAM) (MAXPATHLEN*4 - 1), (LPARAM) 0);
19467 	CheckDlgButton(hdlg, IDC_STEPAPI,
19468 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
19469 		       BST_CHECKED : BST_UNCHECKED);
19470 	CheckDlgButton(hdlg, IDC_NOTXN,
19471 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
19472 		       BST_CHECKED : BST_UNCHECKED);
19473 	CheckDlgButton(hdlg, IDC_SHORTNAM,
19474 		       getbool(setupdlg->attr[KEY_SHORTNAM].attr) ?
19475 		       BST_CHECKED : BST_UNCHECKED);
19476 	CheckDlgButton(hdlg, IDC_LONGNAM,
19477 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
19478 		       BST_CHECKED : BST_UNCHECKED);
19479 	CheckDlgButton(hdlg, IDC_NOCREAT,
19480 		       getbool(setupdlg->attr[KEY_NOCREAT].attr) ?
19481 		       BST_CHECKED : BST_UNCHECKED);
19482 	CheckDlgButton(hdlg, IDC_NOWCHAR,
19483 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
19484 		       BST_CHECKED : BST_UNCHECKED);
19485 	CheckDlgButton(hdlg, IDC_FKSUPPORT,
19486 		       getbool(setupdlg->attr[KEY_FKSUPPORT].attr) ?
19487 		       BST_CHECKED : BST_UNCHECKED);
19488 	CheckDlgButton(hdlg, IDC_OEMCP,
19489 		       getbool(setupdlg->attr[KEY_OEMCP].attr) ?
19490 		       BST_CHECKED : BST_UNCHECKED);
19491 	CheckDlgButton(hdlg, IDC_BIGINT,
19492 		       getbool(setupdlg->attr[KEY_BIGINT].attr) ?
19493 		       BST_CHECKED : BST_UNCHECKED);
19494 	CheckDlgButton(hdlg, IDC_JDCONV,
19495 		       getbool(setupdlg->attr[KEY_JDCONV].attr) ?
19496 		       BST_CHECKED : BST_UNCHECKED);
19497 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19498 			   CB_LIMITTEXT, (WPARAM) 10, (LPARAM) 0);
19499 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19500 			   CB_ADDSTRING, 0, (LPARAM) "NORMAL");
19501 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19502 			   CB_ADDSTRING, 0, (LPARAM) "OFF");
19503 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19504 			   CB_ADDSTRING, 0, (LPARAM) "FULL");
19505 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19506 			   CB_SELECTSTRING, (WPARAM) -1,
19507 			   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
19508 	if (setupdlg->defDSN) {
19509 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
19510 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
19511 	}
19512 	return TRUE;
19513     case WM_COMMAND:
19514 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
19515 	case IDC_DSNAME:
19516 	    if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) {
19517 		char item[MAXDSNAME];
19518 
19519 		EnableWindow(GetDlgItem(hdlg, IDOK),
19520 			     GetDlgItemText(hdlg, IDC_DSNAME,
19521 					    item, sizeof (item)));
19522 		return TRUE;
19523 	    }
19524 	    break;
19525 	case IDC_BROWSE:
19526 	    GetDBFile(hdlg);
19527 	    break;
19528 	case IDOK:
19529 #ifdef _WIN64
19530 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
19531 #else
19532 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
19533 #endif
19534 	    if (!setupdlg->defDSN) {
19535 		GetDlgItemText(hdlg, IDC_DSNAME,
19536 			       setupdlg->attr[KEY_DSN].attr,
19537 			       sizeof (setupdlg->attr[KEY_DSN].attr));
19538 	    }
19539 	    GetDlgItemText(hdlg, IDC_DESC,
19540 			   setupdlg->attr[KEY_DESC].attr,
19541 			   sizeof (setupdlg->attr[KEY_DESC].attr));
19542 	    GetDlgItemText(hdlg, IDC_DBNAME,
19543 			   setupdlg->attr[KEY_DBNAME].attr,
19544 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
19545 	    GetDlgItemText(hdlg, IDC_TONAME,
19546 			   setupdlg->attr[KEY_BUSY].attr,
19547 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
19548 	    GetDlgItemText(hdlg, IDC_LOADEXT,
19549 			   setupdlg->attr[KEY_LOADEXT].attr,
19550 			   sizeof (setupdlg->attr[KEY_LOADEXT].attr));
19551 	    index = SendDlgItemMessage(hdlg, IDC_SYNCP,
19552 				       CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
19553 	    if (index != (WORD) CB_ERR) {
19554 		SendDlgItemMessage(hdlg, IDC_SYNCP,
19555 				   CB_GETLBTEXT, index,
19556 				   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
19557 	    }
19558 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
19559 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
19560 		   "1" : "0");
19561 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
19562 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
19563 		   "1" : "0");
19564 	    strcpy(setupdlg->attr[KEY_SHORTNAM].attr,
19565 		   (IsDlgButtonChecked(hdlg, IDC_SHORTNAM) == BST_CHECKED) ?
19566 		   "1" : "0");
19567 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
19568 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
19569 		   "1" : "0");
19570 	    strcpy(setupdlg->attr[KEY_NOCREAT].attr,
19571 		   (IsDlgButtonChecked(hdlg, IDC_NOCREAT) == BST_CHECKED) ?
19572 		   "1" : "0");
19573 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
19574 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
19575 		   "1" : "0");
19576 	    strcpy(setupdlg->attr[KEY_FKSUPPORT].attr,
19577 		   (IsDlgButtonChecked(hdlg, IDC_FKSUPPORT) == BST_CHECKED) ?
19578 		   "1" : "0");
19579 	    strcpy(setupdlg->attr[KEY_OEMCP].attr,
19580 		   (IsDlgButtonChecked(hdlg, IDC_OEMCP) == BST_CHECKED) ?
19581 		   "1" : "0");
19582 	    strcpy(setupdlg->attr[KEY_BIGINT].attr,
19583 		   (IsDlgButtonChecked(hdlg, IDC_BIGINT) == BST_CHECKED) ?
19584 		   "1" : "0");
19585 	    strcpy(setupdlg->attr[KEY_JDCONV].attr,
19586 		   (IsDlgButtonChecked(hdlg, IDC_JDCONV) == BST_CHECKED) ?
19587 		   "1" : "0");
19588 	    SetDSNAttributes(hdlg, setupdlg);
19589 	    /* FALL THROUGH */
19590 	case IDCANCEL:
19591 	    EndDialog(hdlg, wparam);
19592 	    return TRUE;
19593 	}
19594 	break;
19595     }
19596     return FALSE;
19597 }
19598 
19599 /**
19600  * ODBC INSTAPI procedure for DSN configuration.
19601  * @param hwnd parent window handle
19602  * @param request type of request
19603  * @param driver driver name
19604  * @param attribs attribute string of DSN
19605  * @result true or false
19606  */
19607 
19608 BOOL INSTAPI
ConfigDSN(HWND hwnd,WORD request,LPCSTR driver,LPCSTR attribs)19609 ConfigDSN(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attribs)
19610 {
19611     BOOL success;
19612     SETUPDLG *setupdlg;
19613 
19614     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
19615     if (setupdlg == NULL) {
19616 	return FALSE;
19617     }
19618     memset(setupdlg, 0, sizeof (SETUPDLG));
19619     if (attribs) {
19620 	ParseAttributes(attribs, setupdlg);
19621     }
19622     if (setupdlg->attr[KEY_DSN].supplied) {
19623 	strcpy(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr);
19624     } else {
19625 	setupdlg->DSN[0] = '\0';
19626     }
19627     if (request == ODBC_REMOVE_DSN) {
19628 	if (!setupdlg->attr[KEY_DSN].supplied) {
19629 	    success = FALSE;
19630 	} else {
19631 	    success = SQLRemoveDSNFromIni(setupdlg->attr[KEY_DSN].attr);
19632 	}
19633     } else {
19634 	setupdlg->parent = hwnd;
19635 	setupdlg->driver = driver;
19636 	setupdlg->newDSN = request == ODBC_ADD_DSN;
19637 	setupdlg->defDSN = strcasecmp(setupdlg->attr[KEY_DSN].attr,
19638 				      "Default") == 0;
19639 	if (hwnd) {
19640 	    success = DialogBoxParam(hModule, MAKEINTRESOURCE(CONFIGDSN),
19641 				     hwnd, (DLGPROC) ConfigDlgProc,
19642 				     (LPARAM) setupdlg) == IDOK;
19643 	} else if (setupdlg->attr[KEY_DSN].supplied) {
19644 	    success = SetDSNAttributes(hwnd, setupdlg);
19645 	} else {
19646 	    success = FALSE;
19647 	}
19648     }
19649     xfree(setupdlg);
19650     return success;
19651 }
19652 
19653 /**
19654  * Dialog procedure for SQLDriverConnect().
19655  * @param hdlg handle of dialog window
19656  * @param wmsg type of message
19657  * @param wparam wparam of message
19658  * @param lparam lparam of message
19659  * @result true or false
19660  */
19661 
19662 static BOOL CALLBACK
DriverConnectProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)19663 DriverConnectProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
19664 {
19665     SETUPDLG *setupdlg;
19666     WORD index;
19667 
19668     switch (wmsg) {
19669     case WM_INITDIALOG:
19670 #ifdef _WIN64
19671 	SetWindowLongPtr(hdlg, DWLP_USER, lparam);
19672 #else
19673 	SetWindowLong(hdlg, DWL_USER, lparam);
19674 #endif
19675 	setupdlg = (SETUPDLG *) lparam;
19676 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
19677 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
19678 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
19679 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
19680 	SetDlgItemText(hdlg, IDC_LOADEXT, setupdlg->attr[KEY_LOADEXT].attr);
19681 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
19682 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
19683 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
19684 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
19685 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
19686 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
19687 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
19688 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
19689 	SendDlgItemMessage(hdlg, IDC_LOADEXT, EM_LIMITTEXT,
19690 			   (WPARAM) (MAXPATHLEN*4 - 1), (LPARAM) 0);
19691 	CheckDlgButton(hdlg, IDC_STEPAPI,
19692 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
19693 		       BST_CHECKED : BST_UNCHECKED);
19694 	CheckDlgButton(hdlg, IDC_NOTXN,
19695 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
19696 		       BST_CHECKED : BST_UNCHECKED);
19697 	CheckDlgButton(hdlg, IDC_SHORTNAM,
19698 		       getbool(setupdlg->attr[KEY_SHORTNAM].attr) ?
19699 		       BST_CHECKED : BST_UNCHECKED);
19700 	CheckDlgButton(hdlg, IDC_LONGNAM,
19701 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
19702 		       BST_CHECKED : BST_UNCHECKED);
19703 	CheckDlgButton(hdlg, IDC_NOCREAT,
19704 		       getbool(setupdlg->attr[KEY_NOCREAT].attr) ?
19705 		       BST_CHECKED : BST_UNCHECKED);
19706 	CheckDlgButton(hdlg, IDC_NOWCHAR,
19707 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
19708 		       BST_CHECKED : BST_UNCHECKED);
19709 	CheckDlgButton(hdlg, IDC_FKSUPPORT,
19710 		       getbool(setupdlg->attr[KEY_FKSUPPORT].attr) ?
19711 		       BST_CHECKED : BST_UNCHECKED);
19712 	CheckDlgButton(hdlg, IDC_OEMCP,
19713 		       getbool(setupdlg->attr[KEY_OEMCP].attr) ?
19714 		       BST_CHECKED : BST_UNCHECKED);
19715 	CheckDlgButton(hdlg, IDC_BIGINT,
19716 		       getbool(setupdlg->attr[KEY_BIGINT].attr) ?
19717 		       BST_CHECKED : BST_UNCHECKED);
19718 	CheckDlgButton(hdlg, IDC_JDCONV,
19719 		       getbool(setupdlg->attr[KEY_JDCONV].attr) ?
19720 		       BST_CHECKED : BST_UNCHECKED);
19721 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19722 			   CB_LIMITTEXT, (WPARAM) 10, (LPARAM) 0);
19723 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19724 			   CB_ADDSTRING, 0, (LPARAM) "NORMAL");
19725 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19726 			   CB_ADDSTRING, 0, (LPARAM) "OFF");
19727 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19728 			   CB_ADDSTRING, 0, (LPARAM) "FULL");
19729 	SendDlgItemMessage(hdlg, IDC_SYNCP,
19730 			   CB_SELECTSTRING, (WORD) -1,
19731 			   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
19732 	if (setupdlg->defDSN) {
19733 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
19734 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
19735 	}
19736 	return TRUE;
19737     case WM_COMMAND:
19738 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
19739 	case IDC_BROWSE:
19740 	    GetDBFile(hdlg);
19741 	    break;
19742 	case IDOK:
19743 #ifdef _WIN64
19744 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
19745 #else
19746 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
19747 #endif
19748 	    GetDlgItemText(hdlg, IDC_DSNAME,
19749 			   setupdlg->attr[KEY_DSN].attr,
19750 			   sizeof (setupdlg->attr[KEY_DSN].attr));
19751 	    GetDlgItemText(hdlg, IDC_DBNAME,
19752 			   setupdlg->attr[KEY_DBNAME].attr,
19753 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
19754 	    GetDlgItemText(hdlg, IDC_TONAME,
19755 			   setupdlg->attr[KEY_BUSY].attr,
19756 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
19757 	    GetDlgItemText(hdlg, IDC_LOADEXT,
19758 			   setupdlg->attr[KEY_LOADEXT].attr,
19759 			   sizeof (setupdlg->attr[KEY_LOADEXT].attr));
19760 	    index = SendDlgItemMessage(hdlg, IDC_SYNCP,
19761 				       CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
19762 	    if (index != (WORD) CB_ERR) {
19763 		SendDlgItemMessage(hdlg, IDC_SYNCP,
19764 				   CB_GETLBTEXT, index,
19765 				   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
19766 	    }
19767 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
19768 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
19769 		   "1" : "0");
19770 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
19771 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
19772 		   "1" : "0");
19773 	    strcpy(setupdlg->attr[KEY_SHORTNAM].attr,
19774 		   (IsDlgButtonChecked(hdlg, IDC_SHORTNAM) == BST_CHECKED) ?
19775 		   "1" : "0");
19776 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
19777 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
19778 		   "1" : "0");
19779 	    strcpy(setupdlg->attr[KEY_NOCREAT].attr,
19780 		   (IsDlgButtonChecked(hdlg, IDC_NOCREAT) == BST_CHECKED) ?
19781 		   "1" : "0");
19782 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
19783 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
19784 		   "1" : "0");
19785 	    strcpy(setupdlg->attr[KEY_FKSUPPORT].attr,
19786 		   (IsDlgButtonChecked(hdlg, IDC_FKSUPPORT) == BST_CHECKED) ?
19787 		   "1" : "0");
19788 	    strcpy(setupdlg->attr[KEY_OEMCP].attr,
19789 		   (IsDlgButtonChecked(hdlg, IDC_OEMCP) == BST_CHECKED) ?
19790 		   "1" : "0");
19791 	    strcpy(setupdlg->attr[KEY_BIGINT].attr,
19792 		   (IsDlgButtonChecked(hdlg, IDC_BIGINT) == BST_CHECKED) ?
19793 		   "1" : "0");
19794 	    strcpy(setupdlg->attr[KEY_JDCONV].attr,
19795 		   (IsDlgButtonChecked(hdlg, IDC_JDCONV) == BST_CHECKED) ?
19796 		   "1" : "0");
19797 	    /* FALL THROUGH */
19798 	case IDCANCEL:
19799 	    EndDialog(hdlg, GET_WM_COMMAND_ID(wparam, lparam) == IDOK);
19800 	    return TRUE;
19801 	}
19802     }
19803     return FALSE;
19804 }
19805 
19806 /**
19807  * Internal connect using a driver connection string.
19808  * @param dbc database connection handle
19809  * @param hwnd parent window handle
19810  * @param connIn driver connect input string
19811  * @param connInLen length of driver connect input string or SQL_NTS
19812  * @param connOut driver connect output string
19813  * @param connOutMax length of driver connect output string
19814  * @param connOutLen output length of driver connect output string
19815  * @param drvcompl completion type
19816  * @result ODBC error code
19817  */
19818 
19819 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)19820 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
19821 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
19822 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
19823 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
19824 {
19825     BOOL maybeprompt, prompt = FALSE, defaultdsn = FALSE;
19826     DBC *d;
19827     SETUPDLG *setupdlg;
19828     SQLRETURN ret;
19829     char *dsn = NULL, *driver = NULL, *dbname = NULL;
19830 
19831     if (dbc == SQL_NULL_HDBC) {
19832 	return SQL_INVALID_HANDLE;
19833     }
19834     d = (DBC *) dbc;
19835     if (d->sqlite) {
19836 	setstatd(d, -1, "connection already established", "08002");
19837 	return SQL_ERROR;
19838     }
19839     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
19840     if (setupdlg == NULL) {
19841 	return SQL_ERROR;
19842     }
19843     memset(setupdlg, 0, sizeof (SETUPDLG));
19844     maybeprompt = drvcompl == SQL_DRIVER_COMPLETE ||
19845 	drvcompl == SQL_DRIVER_COMPLETE_REQUIRED;
19846     if (connIn == NULL || !connInLen ||
19847 	(connInLen == SQL_NTS && !connIn[0])) {
19848 	prompt = TRUE;
19849     } else {
19850 	ParseAttributes((LPCSTR) connIn, setupdlg);
19851 	if (!setupdlg->attr[KEY_DSN].attr[0] &&
19852 	    drvcompl == SQL_DRIVER_COMPLETE_REQUIRED) {
19853 	    strcpy(setupdlg->attr[KEY_DSN].attr, "DEFAULT");
19854 	    defaultdsn = TRUE;
19855 	}
19856 	GetAttributes(setupdlg);
19857 	if (drvcompl == SQL_DRIVER_PROMPT ||
19858 	    (maybeprompt &&
19859 	     !setupdlg->attr[KEY_DBNAME].attr[0])) {
19860 	    prompt = TRUE;
19861 	}
19862     }
19863 retry:
19864     if (prompt) {
19865 	short dlgret;
19866 
19867 	setupdlg->defDSN = setupdlg->attr[KEY_DRIVER].attr[0] != '\0';
19868 	dlgret = DialogBoxParam(hModule, MAKEINTRESOURCE(DRIVERCONNECT),
19869 				hwnd, (DLGPROC) DriverConnectProc,
19870 				(LPARAM) setupdlg);
19871 
19872 	if (!dlgret || dlgret == -1) {
19873 	    xfree(setupdlg);
19874 	    return SQL_NO_DATA;
19875 	}
19876     }
19877     dsn = setupdlg->attr[KEY_DSN].attr;
19878     driver = setupdlg->attr[KEY_DRIVER].attr;
19879     dbname = setupdlg->attr[KEY_DBNAME].attr;
19880     if (connOut || connOutLen) {
19881 	char buf[SQL_MAX_MESSAGE_LENGTH * 8];
19882 	int len, count;
19883 	char dsn_0 = (dsn && !defaultdsn) ? dsn[0] : '\0';
19884 	char drv_0 = driver ? driver[0] : '\0';
19885 
19886 	buf[0] = '\0';
19887 	count = snprintf(buf, sizeof (buf),
19888 			 "%s%s%s%s%s%sDatabase=%s;StepAPI=%s;"
19889 			 "SyncPragma=%s;NoTXN=%s;Timeout=%s;"
19890 			 "ShortNames=%s;LongNames=%s;"
19891 			 "NoCreat=%s;NoWCHAR=%s;"
19892 			 "FKSupport=%s;JournalMode=%s;OEMCP=%s;LoadExt=%s;"
19893 			 "BigInt=%s;JDConv=%s;PWD=%s",
19894 			 dsn_0 ? "DSN=" : "",
19895 			 dsn_0 ? dsn : "",
19896 			 dsn_0 ? ";" : "",
19897 			 drv_0 ? "Driver=" : "",
19898 			 drv_0 ? driver : "",
19899 			 drv_0 ? ";" : "",
19900 			 dbname ? dbname : "",
19901 			 setupdlg->attr[KEY_STEPAPI].attr,
19902 			 setupdlg->attr[KEY_SYNCP].attr,
19903 			 setupdlg->attr[KEY_NOTXN].attr,
19904 			 setupdlg->attr[KEY_BUSY].attr,
19905 			 setupdlg->attr[KEY_SHORTNAM].attr,
19906 			 setupdlg->attr[KEY_LONGNAM].attr,
19907 			 setupdlg->attr[KEY_NOCREAT].attr,
19908 			 setupdlg->attr[KEY_NOWCHAR].attr,
19909 			 setupdlg->attr[KEY_FKSUPPORT].attr,
19910 			 setupdlg->attr[KEY_JMODE].attr,
19911 			 setupdlg->attr[KEY_OEMCP].attr,
19912 			 setupdlg->attr[KEY_LOADEXT].attr,
19913 			 setupdlg->attr[KEY_BIGINT].attr,
19914 			 setupdlg->attr[KEY_JDCONV].attr,
19915 			 setupdlg->attr[KEY_PASSWD].attr);
19916 	if (count < 0) {
19917 	    buf[sizeof (buf) - 1] = '\0';
19918 	}
19919 	len = min(connOutMax - 1, strlen(buf));
19920 	if (connOut) {
19921 	    strncpy((char *) connOut, buf, len);
19922 	    connOut[len] = '\0';
19923 	}
19924 	if (connOutLen) {
19925 	    *connOutLen = len;
19926 	}
19927     }
19928     if (dsn[0]) {
19929 	char tracef[SQL_MAX_MESSAGE_LENGTH];
19930 
19931 	tracef[0] = '\0';
19932 	SQLGetPrivateProfileString(setupdlg->attr[KEY_DSN].attr,
19933 				   "tracefile", "", tracef,
19934 				   sizeof (tracef), ODBC_INI);
19935 	if (tracef[0] != '\0') {
19936 	    d->trace = fopen(tracef, "a");
19937 	}
19938     }
19939     d->nowchar = getbool(setupdlg->attr[KEY_NOWCHAR].attr);
19940     d->shortnames = getbool(setupdlg->attr[KEY_SHORTNAM].attr);
19941     d->longnames = getbool(setupdlg->attr[KEY_LONGNAM].attr);
19942     d->nocreat = getbool(setupdlg->attr[KEY_NOCREAT].attr);
19943     d->fksupport = getbool(setupdlg->attr[KEY_FKSUPPORT].attr);
19944     d->oemcp = getbool(setupdlg->attr[KEY_OEMCP].attr);
19945     d->dobigint = getbool(setupdlg->attr[KEY_BIGINT].attr);
19946     d->jdconv = getbool(setupdlg->attr[KEY_JDCONV].attr);
19947     d->pwdLen = strlen(setupdlg->attr[KEY_PASSWD].attr);
19948     d->pwd = (d->pwdLen > 0) ? setupdlg->attr[KEY_PASSWD].attr : NULL;
19949     ret = dbopen(d, dbname ? dbname : "", 0,
19950 		 dsn ? dsn : "",
19951 		 setupdlg->attr[KEY_STEPAPI].attr,
19952 		 setupdlg->attr[KEY_SYNCP].attr,
19953 		 setupdlg->attr[KEY_NOTXN].attr,
19954 		 setupdlg->attr[KEY_JMODE].attr,
19955 		 setupdlg->attr[KEY_BUSY].attr);
19956     if (ret != SQL_SUCCESS) {
19957 	if (maybeprompt && !prompt) {
19958 	    prompt = TRUE;
19959 	    goto retry;
19960 	}
19961     }
19962     memset(setupdlg->attr[KEY_PASSWD].attr, 0,
19963 	   sizeof (setupdlg->attr[KEY_PASSWD].attr));
19964     if (ret == SQL_SUCCESS) {
19965 	dbloadext(d, setupdlg->attr[KEY_LOADEXT].attr);
19966     }
19967     xfree(setupdlg);
19968     return ret;
19969 }
19970 
19971 #endif /* WITHOUT_DRIVERMGR */
19972 #endif /* _WIN32 || _WIN64 */
19973 
19974 #ifndef WINTERFACE
19975 /**
19976  * Connect using a driver connection string.
19977  * @param dbc database connection handle
19978  * @param hwnd parent window handle
19979  * @param connIn driver connect input string
19980  * @param connInLen length of driver connect input string or SQL_NTS
19981  * @param connOut driver connect output string
19982  * @param connOutMax length of driver connect output string
19983  * @param connOutLen output length of driver connect output string
19984  * @param drvcompl completion type
19985  * @result ODBC error code
19986  */
19987 
19988 SQLRETURN SQL_API
SQLDriverConnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)19989 SQLDriverConnect(SQLHDBC dbc, SQLHWND hwnd,
19990 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
19991 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
19992 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
19993 {
19994     SQLRETURN ret;
19995 
19996     HDBC_LOCK(dbc);
19997     ret = drvdriverconnect(dbc, hwnd, connIn, connInLen,
19998 			   connOut, connOutMax, connOutLen, drvcompl);
19999     HDBC_UNLOCK(dbc);
20000     return ret;
20001 }
20002 #endif
20003 
20004 #ifdef WINTERFACE
20005 /**
20006  * Connect using a driver connection string (UNICODE version).
20007  * @param dbc database connection handle
20008  * @param hwnd parent window handle
20009  * @param connIn driver connect input string
20010  * @param connInLen length of driver connect input string or SQL_NTS
20011  * @param connOut driver connect output string
20012  * @param connOutMax length of driver connect output string
20013  * @param connOutLen output length of driver connect output string
20014  * @param drvcompl completion type
20015  * @result ODBC error code
20016  */
20017 
20018 SQLRETURN SQL_API
SQLDriverConnectW(SQLHDBC dbc,SQLHWND hwnd,SQLWCHAR * connIn,SQLSMALLINT connInLen,SQLWCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)20019 SQLDriverConnectW(SQLHDBC dbc, SQLHWND hwnd,
20020 		  SQLWCHAR *connIn, SQLSMALLINT connInLen,
20021 		  SQLWCHAR *connOut, SQLSMALLINT connOutMax,
20022 		  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
20023 {
20024     SQLRETURN ret;
20025     char *ci = NULL;
20026     SQLSMALLINT len = 0;
20027 
20028     HDBC_LOCK(dbc);
20029     if (connIn) {
20030 #if defined(_WIN32) || defined(_WIN64)
20031 	if (connInLen == SQL_NTS) {
20032 	    connInLen = -1;
20033 	}
20034 	ci = uc_to_wmb(connIn, connInLen);
20035 #else
20036 	ci = uc_to_utf(connIn, connInLen);
20037 #endif
20038 	if (!ci) {
20039 	    DBC *d = (DBC *) dbc;
20040 
20041 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
20042 	    HDBC_UNLOCK(dbc);
20043 	    return SQL_ERROR;
20044 	}
20045     }
20046     ret = drvdriverconnect(dbc, hwnd, (SQLCHAR *) ci, SQL_NTS,
20047 			   (SQLCHAR *) connOut, connOutMax, &len, drvcompl);
20048     HDBC_UNLOCK(dbc);
20049     uc_free(ci);
20050     if (ret == SQL_SUCCESS) {
20051 	SQLWCHAR *co = NULL;
20052 
20053 	if (connOut) {
20054 	    if (len > 0) {
20055 #if defined(_WIN32) || defined(_WIN64)
20056 		co = wmb_to_uc((char *) connOut, len);
20057 #else
20058 		co = uc_from_utf((SQLCHAR *) connOut, len);
20059 #endif
20060 		if (co) {
20061 		    uc_strncpy(connOut, co, connOutMax / sizeof (SQLWCHAR));
20062 		    len = min(connOutMax / sizeof (SQLWCHAR), uc_strlen(co));
20063 		    uc_free(co);
20064 		} else {
20065 		    len = 0;
20066 		}
20067 	    }
20068 	    if (len <= 0) {
20069 		len = 0;
20070 		connOut[0] = 0;
20071 	    }
20072 	} else {
20073 	    len = 0;
20074 	}
20075 	if (connOutLen) {
20076 	    *connOutLen = len;
20077 	}
20078     }
20079     return ret;
20080 }
20081 #endif
20082 
20083 #if defined(_WIN32) || defined(_WIN64)
20084 
20085 /**
20086  * DLL initializer for WIN32.
20087  * @param hinst instance handle
20088  * @param reason reason code for entry point
20089  * @param reserved
20090  * @result always true
20091  */
20092 
20093 BOOL APIENTRY
LibMain(HANDLE hinst,DWORD reason,LPVOID reserved)20094 LibMain(HANDLE hinst, DWORD reason, LPVOID reserved)
20095 {
20096     static int initialized = 0;
20097 
20098     switch (reason) {
20099     case DLL_PROCESS_ATTACH:
20100 	if (!initialized++) {
20101 	    hModule = hinst;
20102 #ifdef WINTERFACE
20103 	    /* MS Access hack part 1 (reserved error -7748) */
20104 	    statSpec2P = statSpec2;
20105 	    statSpec3P = statSpec3;
20106 #endif
20107 #ifdef SQLITE_DYNLOAD
20108 	    dls_init();
20109 #endif
20110 #ifdef SQLITE_HAS_CODEC
20111 	    sqlite3_activate_see(SQLITE_ACTIVATION_KEY);
20112 #endif
20113 	}
20114 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
20115 	nvfs_init();
20116 #endif
20117 	break;
20118     case DLL_THREAD_ATTACH:
20119 	break;
20120     case DLL_PROCESS_DETACH:
20121 	if (--initialized <= 0) {
20122 #ifdef SQLITE_DYNLOAD
20123 	    dls_fini();
20124 #endif
20125 	}
20126 	break;
20127     case DLL_THREAD_DETACH:
20128 	break;
20129     default:
20130 	break;
20131     }
20132     return TRUE;
20133 }
20134 
20135 /**
20136  * DLL entry point for WIN32.
20137  * @param hinst instance handle
20138  * @param reason reason code for entry point
20139  * @param reserved
20140  * @result always true
20141  */
20142 
20143 int __stdcall
DllMain(HANDLE hinst,DWORD reason,LPVOID reserved)20144 DllMain(HANDLE hinst, DWORD reason, LPVOID reserved)
20145 {
20146     return LibMain(hinst, reason, reserved);
20147 }
20148 
20149 #ifndef WITHOUT_INSTALLER
20150 
20151 /**
20152  * Handler for driver installer/uninstaller error messages.
20153  * @param name name of API function for which to show error messages
20154  * @result true when error message retrieved
20155  */
20156 
20157 static BOOL
InUnError(char * name)20158 InUnError(char *name)
20159 {
20160     WORD err = 1;
20161     DWORD code;
20162     char errmsg[301];
20163     WORD errlen, errmax = sizeof (errmsg) - 1;
20164     int sqlret;
20165     BOOL ret = FALSE;
20166 
20167     do {
20168 	errmsg[0] = '\0';
20169 	sqlret = SQLInstallerError(err, &code, errmsg, errmax, &errlen);
20170 	if (SQL_SUCCEEDED(sqlret)) {
20171 	    MessageBox(NULL, errmsg, name,
20172 		       MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
20173 	    ret = TRUE;
20174 	}
20175 	err++;
20176     } while (sqlret != SQL_NO_DATA);
20177     return ret;
20178 }
20179 
20180 /**
20181  * Built in driver installer/uninstaller.
20182  * @param remove true for uninstall
20183  * @param cmdline command line string of rundll32
20184  */
20185 
20186 static BOOL
InUn(int remove,char * cmdline)20187 InUn(int remove, char *cmdline)
20188 {
20189 #ifdef SQLITE_HAS_CODEC
20190     static char *drivername = "SQLite3 ODBC Driver (SEE)";
20191     static char *dsname = "SQLite3 SEE Datasource";
20192 #else
20193     static char *drivername = "SQLite3 ODBC Driver";
20194     static char *dsname = "SQLite3 Datasource";
20195 #endif
20196     char *dllname, *p;
20197     char dllbuf[301], path[301], driver[300], attr[300], inst[400];
20198     WORD pathmax = sizeof (path) - 1, pathlen;
20199     DWORD usecnt, mincnt;
20200     int quiet = 0;
20201 
20202     dllbuf[0] = '\0';
20203     GetModuleFileName(hModule, dllbuf, sizeof (dllbuf));
20204     p = strrchr(dllbuf, '\\');
20205     dllname = p ? (p + 1) : dllbuf;
20206     quiet = cmdline && strstr(cmdline, "quiet");
20207     if (SQLInstallDriverManager(path, pathmax, &pathlen)) {
20208 	sprintf(driver, "%s;Driver=%s;Setup=%s;",
20209 		drivername, dllname, dllname);
20210 	p = driver;
20211 	while (*p) {
20212 	    if (*p == ';') {
20213 		*p = '\0';
20214 	    }
20215 	    ++p;
20216 	}
20217 	usecnt = 0;
20218 	path[0] = '\0';
20219 	SQLInstallDriverEx(driver, NULL, path, pathmax, NULL,
20220 			   ODBC_INSTALL_INQUIRY, &usecnt);
20221 	pathlen = strlen(path);
20222 	while (pathlen > 0 && path[pathlen - 1] == '\\') {
20223 	    --pathlen;
20224 	    path[pathlen] = '\0';
20225 	}
20226 	sprintf(driver, "%s;Driver=%s\\%s;Setup=%s\\%s;",
20227 		drivername, path, dllname, path, dllname);
20228 	p = driver;
20229 	while (*p) {
20230 	    if (*p == ';') {
20231 		*p = '\0';
20232 	    }
20233 	    ++p;
20234 	}
20235 	sprintf(inst, "%s\\%s", path, dllname);
20236 	if (!remove && usecnt > 0) {
20237 	    /* first install try: copy over driver dll, keeping DSNs */
20238 	    if (GetFileAttributesA(dllbuf) != INVALID_FILE_ATTRIBUTES &&
20239 		CopyFile(dllbuf, inst, 0)) {
20240 		if (!quiet) {
20241 		    char buf[512];
20242 
20243 		    sprintf(buf, "%s replaced.", drivername);
20244 		    MessageBox(NULL, buf, "Info",
20245 			       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
20246 			       MB_SETFOREGROUND);
20247 		}
20248 		return TRUE;
20249 	    }
20250 	}
20251 	mincnt = remove ? 1 : 0;
20252 	while (usecnt != mincnt) {
20253 	    if (!SQLRemoveDriver(driver, TRUE, &usecnt)) {
20254 		break;
20255 	    }
20256 	}
20257 	if (remove) {
20258 	    if (usecnt && !SQLRemoveDriver(driver, TRUE, &usecnt)) {
20259 		InUnError("SQLRemoveDriver");
20260 		return FALSE;
20261 	    }
20262 	    if (!usecnt) {
20263 		char buf[512];
20264 
20265 		DeleteFile(inst);
20266 		if (!quiet) {
20267 		    sprintf(buf, "%s uninstalled.", drivername);
20268 		    MessageBox(NULL, buf, "Info",
20269 			       MB_ICONINFORMATION |MB_OK | MB_TASKMODAL |
20270 			       MB_SETFOREGROUND);
20271 		}
20272 	    }
20273 	    sprintf(attr, "DSN=%s;Database=;", dsname);
20274 	    p = attr;
20275 	    while (*p) {
20276 		if (*p == ';') {
20277 		    *p = '\0';
20278 		}
20279 		++p;
20280 	    }
20281 	    SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
20282 	    return TRUE;
20283 	}
20284 	if (GetFileAttributesA(dllbuf) == INVALID_FILE_ATTRIBUTES) {
20285 	    return FALSE;
20286 	}
20287 	if (strcasecmp(dllbuf, inst) != 0 && !CopyFile(dllbuf, inst, 0)) {
20288 	    char buf[512];
20289 
20290 	    sprintf(buf, "Copy %s to %s failed.", dllbuf, inst);
20291 	    MessageBox(NULL, buf, "CopyFile",
20292 		       MB_ICONSTOP |MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
20293 	    return FALSE;
20294 	}
20295 	if (!SQLInstallDriverEx(driver, path, path, pathmax, &pathlen,
20296 				ODBC_INSTALL_COMPLETE, &usecnt)) {
20297 	    InUnError("SQLInstallDriverEx");
20298 	    return FALSE;
20299 	}
20300 	sprintf(attr, "DSN=%s;Database=;", dsname);
20301 	p = attr;
20302 	while (*p) {
20303 	    if (*p == ';') {
20304 		*p = '\0';
20305 	    }
20306 	    ++p;
20307 	}
20308 	SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
20309 	if (!SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, drivername, attr)) {
20310 	    InUnError("SQLConfigDataSource");
20311 	    return FALSE;
20312 	}
20313 	if (!quiet) {
20314 	    char buf[512];
20315 
20316 	    sprintf(buf, "%s installed.", drivername);
20317 	    MessageBox(NULL, buf, "Info",
20318 		       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
20319 		       MB_SETFOREGROUND);
20320 	}
20321     } else {
20322 	InUnError("SQLInstallDriverManager");
20323 	return FALSE;
20324     }
20325     return TRUE;
20326 }
20327 
20328 /**
20329  * RunDLL32 entry point for driver installation.
20330  * @param hwnd window handle of caller
20331  * @param hinst of this DLL
20332  * @param lpszCmdLine rundll32 command line tail
20333  * @param nCmdShow ignored
20334  */
20335 
20336 void CALLBACK
install(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)20337 install(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
20338 {
20339     InUn(0, lpszCmdLine);
20340 }
20341 
20342 /**
20343  * RunDLL32 entry point for driver uninstallation.
20344  * @param hwnd window handle of caller
20345  * @param hinst of this DLL
20346  * @param lpszCmdLine rundll32 command line tail
20347  * @param nCmdShow ignored
20348  */
20349 
20350 void CALLBACK
uninstall(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)20351 uninstall(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
20352 {
20353     InUn(1, lpszCmdLine);
20354 }
20355 
20356 #endif /* WITHOUT_INSTALLER */
20357 
20358 #ifndef WITHOUT_SHELL
20359 
20360 /**
20361  * Setup argv vector from string
20362  * @param argcp pointer to argc
20363  * @param argvp pointer to argv
20364  * @param cmdline command line string
20365  * @param argv0 0th element for argv or NULL, must be static
20366  */
20367 
20368 static void
setargv(int * argcp,char *** argvp,char * cmdline,char * argv0)20369 setargv(int *argcp, char ***argvp, char *cmdline, char *argv0)
20370 {
20371     char *p, *arg, *argspace, **argv;
20372     int argc, size, inquote, copy, slashes;
20373 
20374     size = 2 + (argv0 ? 1 : 0);
20375     for (p = cmdline; *p != '\0'; p++) {
20376 	if (ISSPACE(*p)) {
20377 	    size++;
20378 	    while (ISSPACE(*p)) {
20379 		p++;
20380 	    }
20381 	    if (*p == '\0') {
20382 		break;
20383 	    }
20384 	}
20385     }
20386     argspace = malloc(size * sizeof (char *) + strlen(cmdline) + 1);
20387     argv = (char **) argspace;
20388     argspace += size * sizeof (char *);
20389     size--;
20390     argc = 0;
20391     if (argv0) {
20392 	argv[argc++] = argv0;
20393     }
20394     p = cmdline;
20395     for (; argc < size; argc++) {
20396 	argv[argc] = arg = argspace;
20397 	while (ISSPACE(*p)) {
20398 	    p++;
20399 	}
20400 	if (*p == '\0') {
20401 	    break;
20402 	}
20403 	inquote = 0;
20404 	slashes = 0;
20405 	while (1) {
20406 	    copy = 1;
20407 	    while (*p == '\\') {
20408 		slashes++;
20409 		p++;
20410 	    }
20411 	    if (*p == '"') {
20412 		if ((slashes & 1) == 0) {
20413 		    copy = 0;
20414 		    if (inquote && p[1] == '"') {
20415 			p++;
20416 			copy = 1;
20417 		    } else {
20418 			inquote = !inquote;
20419 		    }
20420 		}
20421 		slashes >>= 1;
20422 	    }
20423 	    while (slashes) {
20424 		*arg = '\\';
20425 		arg++;
20426 		slashes--;
20427 	    }
20428 	    if (*p == '\0' || (!inquote && ISSPACE(*p))) {
20429 		break;
20430 	    }
20431 	    if (copy != 0) {
20432 		*arg = *p;
20433 		arg++;
20434 	    }
20435 	    p++;
20436 	}
20437 	*arg = '\0';
20438 	argspace = arg + 1;
20439     }
20440     argv[argc] = 0;
20441     *argcp = argc;
20442     *argvp = argv;
20443 }
20444 
20445 /**
20446  * RunDLL32 entry point for SQLite shell
20447  * @param hwnd window handle of caller
20448  * @param hinst of this DLL
20449  * @param lpszCmdLine rundll32 command line tail
20450  * @param nCmdShow ignored
20451  */
20452 
20453 void CALLBACK
shell(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)20454 shell(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
20455 {
20456     int argc, needcon = 0;
20457     char **argv;
20458     extern int sqlite3_main(int, char **);
20459     static const char *name = "SQLite3 Shell";
20460     DWORD ftype0, ftype1, ftype2;
20461 
20462     ftype0 = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
20463     ftype1 = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
20464     ftype2 = GetFileType(GetStdHandle(STD_ERROR_HANDLE));
20465     if (ftype0 != FILE_TYPE_DISK && ftype0 != FILE_TYPE_CHAR &&
20466 	ftype0 != FILE_TYPE_PIPE) {
20467 	fclose(stdin);
20468 	++needcon;
20469 	ftype0 = FILE_TYPE_UNKNOWN;
20470     }
20471     if (ftype1 != FILE_TYPE_DISK && ftype1 != FILE_TYPE_CHAR &&
20472 	ftype1 != FILE_TYPE_PIPE) {
20473 	fclose(stdout);
20474 	++needcon;
20475 	ftype1 = FILE_TYPE_UNKNOWN;
20476     }
20477     if (ftype2 != FILE_TYPE_DISK && ftype2 != FILE_TYPE_CHAR &&
20478 	ftype2 != FILE_TYPE_PIPE) {
20479 	fclose(stderr);
20480 	++needcon;
20481 	ftype2 = FILE_TYPE_UNKNOWN;
20482     }
20483     if (needcon > 0) {
20484 	AllocConsole();
20485 	SetConsoleTitle(name);
20486     }
20487     if (ftype0 == FILE_TYPE_UNKNOWN) {
20488 	freopen("CONIN$", "r", stdin);
20489     }
20490     if (ftype1 == FILE_TYPE_UNKNOWN) {
20491 	freopen("CONOUT$", "w", stdout);
20492     }
20493     if (ftype2 == FILE_TYPE_UNKNOWN) {
20494 	freopen("CONOUT$", "w", stderr);
20495     }
20496     setargv(&argc, &argv, lpszCmdLine, (char *) name);
20497 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
20498     nvfs_init();
20499 #endif
20500     sqlite3_main(argc, argv);
20501 }
20502 
20503 #endif /* WITHOUT_SHELL */
20504 
20505 #endif /* _WIN32 || _WIN64 */
20506 
20507 #if defined(HAVE_ODBCINSTEXT_H) && (HAVE_ODBCINSTEXT_H)
20508 
20509 /*
20510  * unixODBC property page for this driver,
20511  * may or may not work depending on unixODBC version.
20512  */
20513 
20514 #include <odbcinstext.h>
20515 
20516 int
ODBCINSTGetProperties(HODBCINSTPROPERTY prop)20517 ODBCINSTGetProperties(HODBCINSTPROPERTY prop)
20518 {
20519     static const char *instYN[] = { "No", "Yes", NULL };
20520     static const char *syncPragma[] = { "NORMAL", "OFF", "FULL", NULL };
20521     static const char *jmPragma[] = {
20522 	"DELETE", "PERSIST", "OFF", "TRUNCATE", "MEMORY", "WAL", NULL
20523     };
20524 
20525     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20526     prop = prop->pNext;
20527     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20528     prop->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
20529     strncpy(prop->szName, "Database", INI_MAX_PROPERTY_NAME);
20530     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
20531     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20532     prop = prop->pNext;
20533     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20534     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
20535     strncpy(prop->szName, "Timeout", INI_MAX_PROPERTY_NAME);
20536     strncpy(prop->szValue, "100000", INI_MAX_PROPERTY_VALUE);
20537     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20538     prop = prop->pNext;
20539     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20540     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20541     prop->aPromptData = malloc(sizeof (instYN));
20542     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20543     strncpy(prop->szName, "StepAPI", INI_MAX_PROPERTY_NAME);
20544     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20545     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20546     prop = prop->pNext;
20547     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20548     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20549     prop->aPromptData = malloc(sizeof (instYN));
20550     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20551     strncpy(prop->szName, "ShortNames", INI_MAX_PROPERTY_NAME);
20552     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20553     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20554     prop = prop->pNext;
20555     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20556     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20557     prop->aPromptData = malloc(sizeof (instYN));
20558     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20559     strncpy(prop->szName, "LongNames", INI_MAX_PROPERTY_NAME);
20560     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20561     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20562     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20563     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20564     prop->aPromptData = malloc(sizeof (instYN));
20565     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20566     strncpy(prop->szName, "NoCreat", INI_MAX_PROPERTY_NAME);
20567     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20568 #ifdef WINTERFACE
20569     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20570     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20571     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20572     prop->aPromptData = malloc(sizeof (instYN));
20573     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20574     strncpy(prop->szName, "NoWCHAR", INI_MAX_PROPERTY_NAME);
20575     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20576 #endif
20577     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20578     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20579     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20580     prop->aPromptData = malloc(sizeof (instYN));
20581     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20582     strncpy(prop->szName, "FKSupport", INI_MAX_PROPERTY_NAME);
20583     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20584     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20585     prop = prop->pNext;
20586     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20587     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20588     prop->aPromptData = malloc(sizeof (syncPragma));
20589     memcpy(prop->aPromptData, syncPragma, sizeof (syncPragma));
20590     strncpy(prop->szName, "SyncPragma", INI_MAX_PROPERTY_NAME);
20591     strncpy(prop->szValue, "NORMAL", INI_MAX_PROPERTY_VALUE);
20592     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20593     prop = prop->pNext;
20594     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20595     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20596     prop->aPromptData = malloc(sizeof (jmPragma));
20597     memcpy(prop->aPromptData, jmPragma, sizeof (jmPragma));
20598     strncpy(prop->szName, "JournalMode", INI_MAX_PROPERTY_NAME);
20599     strncpy(prop->szValue, "DELETE", INI_MAX_PROPERTY_VALUE);
20600     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20601     prop = prop->pNext;
20602     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20603     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
20604     strncpy(prop->szName, "LoadExt", INI_MAX_PROPERTY_NAME);
20605     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
20606     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
20607     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
20608     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
20609     prop->aPromptData = malloc(sizeof (instYN));
20610     memcpy(prop->aPromptData, instYN, sizeof (instYN));
20611     strncpy(prop->szName, "BigInt", INI_MAX_PROPERTY_NAME);
20612     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
20613     return 1;
20614 }
20615 
20616 #endif /* HAVE_ODBCINSTEXT_H */
20617 
20618 #ifdef SQLITE_DYNLOAD
20619 
20620 /*
20621  * SQLite3 shared library/DLL stubs.
20622  */
20623 
20624 static void
dls_void(void)20625 dls_void(void)
20626 {
20627 }
20628 
20629 static int
dls_error(void)20630 dls_error(void)
20631 {
20632     return SQLITE_ERROR;
20633 }
20634 
20635 static int
dls_0(void)20636 dls_0(void)
20637 {
20638     return 0;
20639 }
20640 
20641 static sqlite_int64
dls_0LL(void)20642 dls_0LL(void)
20643 {
20644     return 0;
20645 }
20646 
20647 static double
dls_00(void)20648 dls_00(void)
20649 {
20650     return 0;
20651 }
20652 
20653 static void *
dls_null(void)20654 dls_null(void)
20655 {
20656     return NULL;
20657 }
20658 
20659 static const char *
dls_empty(void)20660 dls_empty(void)
20661 {
20662     return "";
20663 }
20664 
20665 static int
dls_snull(void)20666 dls_snull(void)
20667 {
20668     return SQLITE_NULL;
20669 }
20670 
20671 #define DLS_ENT(name, func)						\
20672     { "sqlite3_" #name, offsetof(struct dl_sqlite3_funcs, name),	\
20673       (void *) func }
20674 
20675 #define DLS_ENT3(name, off, func)					\
20676     { "sqlite3_" #name, offsetof(struct dl_sqlite3_funcs, off),		\
20677       (void *) func }
20678 
20679 #define DLS_END { NULL, 0, NULL }
20680 
20681 static struct {
20682     const char *name;
20683     int offset;
20684     void *func;
20685 } dls_nametab[] = {
20686     DLS_ENT(activate_see, dls_void),
20687     DLS_ENT(bind_blob, dls_error),
20688     DLS_ENT(bind_double, dls_error),
20689     DLS_ENT(bind_int, dls_error),
20690     DLS_ENT(bind_int64, dls_error),
20691     DLS_ENT(bind_null, dls_error),
20692     DLS_ENT(bind_parameter_count, dls_0),
20693     DLS_ENT(bind_text, dls_error),
20694     DLS_ENT(busy_handler, dls_error),
20695     DLS_ENT(changes, dls_0),
20696     DLS_ENT(close, dls_error),
20697     DLS_ENT(column_blob, dls_null),
20698     DLS_ENT(column_bytes, dls_0),
20699     DLS_ENT(column_count, dls_0),
20700     DLS_ENT(column_database_name, dls_empty),
20701     DLS_ENT(column_decltype, dls_empty),
20702     DLS_ENT(column_double, dls_00),
20703     DLS_ENT(column_name, dls_empty),
20704     DLS_ENT(column_origin_name, dls_null),
20705     DLS_ENT(column_table_name, dls_null),
20706     DLS_ENT(column_text, dls_null),
20707     DLS_ENT(column_type, dls_snull),
20708     DLS_ENT(create_function, dls_error),
20709     DLS_ENT(enable_load_extension, dls_error),
20710     DLS_ENT(errcode, dls_error),
20711     DLS_ENT(errmsg, dls_empty),
20712     DLS_ENT(exec, dls_error),
20713     DLS_ENT(finalize, dls_error),
20714     DLS_ENT(free, free),
20715     DLS_ENT(free_table, dls_void),
20716     DLS_ENT(get_table, dls_error),
20717     DLS_ENT(interrupt, dls_void),
20718     DLS_ENT(key, dls_error),
20719     DLS_ENT(last_insert_rowid, dls_0LL),
20720     DLS_ENT(libversion, dls_empty),
20721     DLS_ENT(load_extension, dls_error),
20722     DLS_ENT(malloc, malloc),
20723     DLS_ENT(mprintf, dls_null),
20724     DLS_ENT(open, dls_error),
20725     DLS_ENT(open16, dls_error),
20726     DLS_ENT(open_v2, dls_error),
20727     DLS_ENT(prepare, dls_error),
20728     DLS_ENT(prepare_v2, dls_error),
20729     DLS_ENT(profile, dls_null),
20730     DLS_ENT(realloc, realloc),
20731     DLS_ENT(rekey, dls_error),
20732     DLS_ENT(reset, dls_error),
20733     DLS_ENT(result_blob, dls_void),
20734     DLS_ENT(result_error, dls_void),
20735     DLS_ENT(result_int, dls_void),
20736     DLS_ENT(result_null, dls_void),
20737     DLS_ENT(step, dls_error),
20738 #if defined(_WIN32) || defined(_WIN64)
20739     DLS_ENT3(strnicmp, xstrnicmp, _strnicmp),
20740 #else
20741     DLS_ENT3(strnicmp, xstrnicmp, strncasecmp),
20742 #endif
20743     DLS_ENT(table_column_metadata, dls_error),
20744     DLS_ENT(trace, dls_null),
20745     DLS_ENT(user_data, dls_null),
20746     DLS_ENT(value_blob, dls_null),
20747     DLS_ENT(value_bytes, dls_0),
20748     DLS_ENT(value_text, dls_empty),
20749     DLS_ENT(value_type, dls_snull),
20750     DLS_END
20751 };
20752 
20753 #if defined(_WIN32) || defined(_WIN64)
20754 
20755 static HMODULE sqlite3_dll = 0;
20756 
20757 static void
dls_init(void)20758 dls_init(void)
20759 {
20760     int i;
20761     static const char *dll_names[] = {
20762 	"System.Data.SQLite.dll",
20763 	"sqlite3.dll",
20764 	NULL,
20765     };
20766 
20767     i = 0;
20768     while (dll_names[i]) {
20769 	sqlite3_dll = LoadLibrary(dll_names[i]);
20770 	if (sqlite3_dll) {
20771 	    break;
20772 	}
20773 	++i;
20774     }
20775     i = 0;
20776     while (dls_nametab[i].name) {
20777 	void *func = 0, **loc;
20778 
20779 	if (sqlite3_dll) {
20780 	    func = (void *) GetProcAddress(sqlite3_dll, dls_nametab[i].name);
20781 	}
20782 	if (!func) {
20783 	    func = dls_nametab[i].func;
20784 	}
20785 	loc = (void **) ((char *) &dls_funcs + dls_nametab[i].offset);
20786 	*loc = func;
20787 	++i;
20788     }
20789     if (!sqlite3_dll) {
20790 	char buf[MAXPATHLEN], msg[MAXPATHLEN];
20791 
20792 	LoadString(hModule, IDS_DRVTITLE, buf, sizeof (buf));
20793 	LoadString(hModule, IDS_DLLERR, msg, sizeof (msg));
20794 	MessageBox(NULL, msg, buf,
20795 		   MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
20796 		   MB_SETFOREGROUND);
20797     }
20798 }
20799 
20800 static void
dls_fini(void)20801 dls_fini(void)
20802 {
20803     if (sqlite3_dll) {
20804 	FreeLibrary(sqlite3_dll);
20805 	sqlite3_dll = 0;
20806     }
20807 }
20808 
20809 #else
20810 
20811 #include <dlfcn.h>
20812 
20813 static void *libsqlite3_so = 0;
20814 
20815 void
dls_init(void)20816 dls_init(void)
20817 {
20818     int i;
20819 
20820     libsqlite3_so = dlopen("libsqlite3.so.0", RTLD_NOW | RTLD_GLOBAL);
20821     i = 0;
20822     while (dls_nametab[i].name) {
20823 	void *func = 0, **loc;
20824 
20825 	if (libsqlite3_so) {
20826 	    func = dlsym(libsqlite3_so, dls_nametab[i].name);
20827 	}
20828 	if (!func) {
20829 	    func = dls_nametab[i].func;
20830 	}
20831 	loc = (void **) ((char *) &dls_funcs + dls_nametab[i].offset);
20832 	*loc = func;
20833 	++i;
20834     }
20835     if (!libsqlite3_so) {
20836 	const char errmsg[] = "SQLite3 shared library not found.\n";
20837 
20838 	write(2, errmsg, sizeof (errmsg) - 1);
20839     }
20840 }
20841 
20842 void
dls_fini(void)20843 dls_fini(void)
20844 {
20845     if (libsqlite3_so) {
20846 	dlclose(libsqlite3_so);
20847 	libsqlite3_so = 0;
20848     }
20849 }
20850 
20851 #endif
20852 
20853 #endif
20854 
20855 /*
20856  * Local Variables:
20857  * mode: c
20858  * c-basic-offset: 4
20859  * fill-column: 78
20860  * tab-width: 8
20861  * End:
20862  */
20863