1 /**
2  * @file sqlite3odbc.c
3  * SQLite3 ODBC Driver main module.
4  *
5  * $Id: sqlite3odbc.c,v 1.136 2011/11/12 04:35:40 chw Exp chw $
6  *
7  * Copyright (c) 2004-2011 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 #endif
23 
24 #include "sqlite3odbc.h"
25 
26 #ifdef SQLITE_DYNLOAD
27 
28 #undef MEMORY_DEBUG
29 
30 #if defined(_WIN32) || defined(_WIN64)
31 static void dls_init(void);
32 static void dls_fini(void);
33 #else
34 void dls_init(void);
35 void dls_fini(void);
36 #endif
37 
38 static struct dl_sqlite3_funcs {
39     void (*activate_see)(const char *p0);
40     int (*bind_blob)(sqlite3_stmt *p0, int p1, const void *p2, int p3,
41 		     void (*p4)(void *));
42     int (*bind_double)(sqlite3_stmt *p0, int p1, double p2);
43     int (*bind_int)(sqlite3_stmt *p0, int p1, int p2);
44     int (*bind_int64)(sqlite3_stmt *p0, int p1, sqlite3_int64 p2);
45     int (*bind_null)(sqlite3_stmt *p0, int p1);
46     int (*bind_parameter_count)(sqlite3_stmt *p0);
47     int (*bind_text)(sqlite3_stmt *p0, int p1, const char *p2, int p3,
48 		     void (*p4)(void *));
49     int (*busy_handler)(sqlite3 *p0, int (*p2)(void *, int), void *p3);
50     int (*changes)(sqlite3 *p0);
51     int (*close)(sqlite3 *p0);
52     const void * (*column_blob)(sqlite3_stmt *p0, int p1);
53     int (*column_bytes)(sqlite3_stmt *p0, int p1);
54     int (*column_count)(sqlite3_stmt *p0);
55     const char * (*column_database_name)(sqlite3_stmt *p0, int p1);
56     const char * (*column_decltype)(sqlite3_stmt *p0, int p1);
57     const char * (*column_name)(sqlite3_stmt *p0, int p1);
58     const char * (*column_origin_name)(sqlite3_stmt *p0, int p1);
59     const char * (*column_table_name)(sqlite3_stmt *p0, int p1);
60     const unsigned char * (*column_text)(sqlite3_stmt *p0, int p1);
61     int (*column_type)(sqlite3_stmt *p0, int p1);
62     int (*create_function)(sqlite3 *p0, const char *p1, int p2, int p3,
63 			   void *p4,
64 			   void (*p5)(sqlite3_context *, int, sqlite3_value **),
65 			   void (*p6)(sqlite3_context *, int, sqlite3_value **),
66 			   void (*p7)(sqlite3_context *));
67     int (*enable_load_extension)(sqlite3 *p0, int p1);
68     int (*errcode)(sqlite3 *p0);
69     const char * (*errmsg)(sqlite3 *p0);
70     int (*exec)(sqlite3 *p0, const char *p1,
71 		int (*p2)(void *, int, char **, char **),
72 		void *p3, char **p4);
73     int (*finalize)(sqlite3_stmt *p0);
74     void (*free)(void *p0);
75     void (*free_table)(char **p0);
76     int (*get_table)(sqlite3 *p0, const char *p1, char ***p2,
77 		     int *p3, int *p4, char **p5);
78     void (*interrupt)(sqlite3 *p0);
79     int (*key)(sqlite3 *p0, const void *p1, int p2);
80     const char * (*libversion)(void);
81     int (*load_extension)(sqlite3 *p0, const char *p1, const char *p2,
82 			  char **p3);
83     void * (*malloc)(int p0);
84     char * (*mprintf)(const char *p0, ...);
85     int (*open)(const char *p0, sqlite3 **p1);
86     int (*open16)(const void *p0, sqlite3 **p1);
87     int (*open_v2)(const char *p0, sqlite3 **p1, int p2, const char *p3);
88     int (*prepare)(sqlite3 *p0, const char *p1, int p2, sqlite3_stmt **p3,
89 		   const char **p4);
90     int (*prepare_v2)(sqlite3 *p0, const char *p1, int p2, sqlite3_stmt **p3,
91 		      const char **p4);
92     void * (*profile)(sqlite3 *p0,
93 		      void (*p1)(void *, const char *, sqlite3_uint64),
94 		      void *p2);
95     void * (*realloc)(void *p0, int p1);
96     int (*rekey)(sqlite3 *p0, const void *p1, int p2);
97     int (*reset)(sqlite3_stmt *p0);
98     void (*result_blob)(sqlite3_context *p0, const void *p1,
99 			int p2, void (*p3)(void *));
100     void (*result_error)(sqlite3_context *p0, const char *p1, int p2);
101     void (*result_int)(sqlite3_context *p0, int p1);
102     void (*result_null)(sqlite3_context *p0);
103     int (*step)(sqlite3_stmt *p0);
104     int (*xstrnicmp)(const char *p0, const char *p1, int p2);
105     int (*table_column_metadata)(sqlite3 *p0, const char *p1,
106 				 const char *p2, const char *p3,
107 				 char const **p4, char const **p5,
108 				 int *p6, int *p7, int *p8);
109     void * (*trace)(sqlite3 *p0, void (*p1)(void *, const char *), void *p2);
110     void * (*user_data)(sqlite3_context *p0);
111     const void * (*value_blob)(sqlite3_value *p0);
112     int (*value_bytes)(sqlite3_value *p0);
113     const unsigned char * (*value_text)(sqlite3_value *p0);
114     int (*value_type)(sqlite3_value *p0);
115 } dls_funcs;
116 
117 #define sqlite3_activate_see          dls_funcs.activate_see
118 #define sqlite3_bind_blob             dls_funcs.bind_blob
119 #define sqlite3_bind_double           dls_funcs.bind_double
120 #define sqlite3_bind_int              dls_funcs.bind_int
121 #define sqlite3_bind_int64            dls_funcs.bind_int64
122 #define sqlite3_bind_null             dls_funcs.bind_null
123 #define sqlite3_bind_parameter_count  dls_funcs.bind_parameter_count
124 #define sqlite3_bind_text             dls_funcs.bind_text
125 #define sqlite3_busy_handler          dls_funcs.busy_handler
126 #define sqlite3_changes               dls_funcs.changes
127 #define sqlite3_close                 dls_funcs.close
128 #define sqlite3_column_blob           dls_funcs.column_blob
129 #define sqlite3_column_bytes          dls_funcs.column_bytes
130 #define sqlite3_column_count          dls_funcs.column_count
131 #define sqlite3_column_database_name  dls_funcs.column_database_name
132 #define sqlite3_column_decltype       dls_funcs.column_decltype
133 #define sqlite3_column_name           dls_funcs.column_name
134 #define sqlite3_column_origin_name    dls_funcs.column_origin_name
135 #define sqlite3_column_table_name     dls_funcs.column_table_name
136 #define sqlite3_column_text           dls_funcs.column_text
137 #define sqlite3_column_type           dls_funcs.column_type
138 #define sqlite3_create_function       dls_funcs.create_function
139 #define sqlite3_enable_load_extension dls_funcs.enable_load_extension
140 #define sqlite3_errcode               dls_funcs.errcode
141 #define sqlite3_errmsg                dls_funcs.errmsg
142 #define sqlite3_exec                  dls_funcs.exec
143 #define sqlite3_finalize              dls_funcs.finalize
144 #define sqlite3_free                  dls_funcs.free
145 #define sqlite3_free_table            dls_funcs.free_table
146 #define sqlite3_get_table             dls_funcs.get_table
147 #define sqlite3_interrupt             dls_funcs.interrupt
148 #define sqlite3_key                   dls_funcs.key
149 #define sqlite3_libversion            dls_funcs.libversion
150 #define sqlite3_load_extension        dls_funcs.load_extension
151 #define sqlite3_malloc                dls_funcs.malloc
152 #define sqlite3_mprintf               dls_funcs.mprintf
153 #define sqlite3_open                  dls_funcs.open
154 #define sqlite3_open16                dls_funcs.open16
155 #define sqlite3_open_v2               dls_funcs.open_v2
156 #define sqlite3_prepare               dls_funcs.prepare
157 #define sqlite3_prepare_v2            dls_funcs.prepare_v2
158 #define sqlite3_profile               dls_funcs.profile
159 #define sqlite3_realloc               dls_funcs.realloc
160 #define sqlite3_rekey                 dls_funcs.rekey
161 #define sqlite3_reset                 dls_funcs.reset
162 #define sqlite3_result_blob           dls_funcs.result_blob
163 #define sqlite3_result_error          dls_funcs.result_error
164 #define sqlite3_result_int            dls_funcs.result_int
165 #define sqlite3_result_null           dls_funcs.result_null
166 #define sqlite3_step                  dls_funcs.step
167 #define sqlite3_strnicmp              dls_funcs.xstrnicmp
168 #define sqlite3_table_column_metadata dls_funcs.table_column_metadata
169 #define sqlite3_trace                 dls_funcs.trace
170 #define sqlite3_user_data             dls_funcs.user_data
171 #define sqlite3_value_blob            dls_funcs.value_blob
172 #define sqlite3_value_bytes           dls_funcs.value_bytes
173 #define sqlite3_value_text            dls_funcs.value_text
174 #define sqlite3_value_type            dls_funcs.value_type
175 
176 #endif
177 
178 #ifndef WITHOUT_WINTERFACE
179 #define WINTERFACE
180 #define WCHARSUPPORT
181 #endif
182 
183 #if !defined(_WIN32) && !defined(_WIN64)
184 #if !defined(WCHARSUPPORT) && defined(HAVE_SQLWCHAR) && (HAVE_SQLWCHAR)
185 #define WCHARSUPPORT
186 #endif
187 #endif
188 
189 #if defined(WINTERFACE)
190 #include <sqlucode.h>
191 #endif
192 
193 #if defined(_WIN32) || defined(_WIN64)
194 #include "resource3.h"
195 #define ODBC_INI "ODBC.INI"
196 #ifndef DRIVER_VER_INFO
197 #define DRIVER_VER_INFO VERSION
198 #endif
199 #else
200 #define ODBC_INI ".odbc.ini"
201 #endif
202 
203 #ifndef DRIVER_VER_INFO
204 #define DRIVER_VER_INFO "0.0"
205 #endif
206 
207 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
208 #ifdef _WIN64
209 #define COLATTRIBUTE_LAST_ARG_TYPE SQLLEN *
210 #else
211 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
212 #endif
213 #endif
214 
215 #ifndef SETSTMTOPTION_LAST_ARG_TYPE
216 #define SETSTMTOPTION_LAST_ARG_TYPE SQLROWCOUNT
217 #endif
218 
219 #undef min
220 #define min(a, b) ((a) < (b) ? (a) : (b))
221 #undef max
222 #define max(a, b) ((a) < (b) ? (b) : (a))
223 
224 #ifndef PTRDIFF_T
225 #define PTRDIFF_T int
226 #endif
227 
228 #define array_size(x) (sizeof (x) / sizeof (x[0]))
229 
230 #define stringify1(s) #s
231 #define stringify(s) stringify1(s)
232 
233 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
234 
235 /* Column types for static string column descriptions (SQLTables etc.) */
236 
237 #if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
238 #define SCOL_VARCHAR SQL_WVARCHAR
239 #define SCOL_CHAR SQL_WCHAR
240 #else
241 #define SCOL_VARCHAR SQL_VARCHAR
242 #define SCOL_CHAR SQL_CHAR
243 #endif
244 
245 #define ENV_MAGIC  0x53544145
246 #define DBC_MAGIC  0x53544144
247 #define DEAD_MAGIC 0xdeadbeef
248 
249 static const char *xdigits = "0123456789ABCDEFabcdef";
250 
251 #ifdef MEMORY_DEBUG
252 
253 static void *
xmalloc_(int n,char * file,int line)254 xmalloc_(int n, char *file, int line)
255 {
256     int nn = n + 4 * sizeof (long);
257     long *p;
258 
259     p = malloc(nn);
260     if (!p) {
261 #if (MEMORY_DEBUG > 1)
262 	fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
263 #endif
264 	return NULL;
265     }
266     p[0] = 0xdead1234;
267     nn = nn / sizeof (long) - 1;
268     p[1] = n;
269     p[nn] = 0xdead5678;
270 #if (MEMORY_DEBUG > 1)
271     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
272 #endif
273     return (void *) &p[2];
274 }
275 
276 static void *
xrealloc_(void * old,int n,char * file,int line)277 xrealloc_(void *old, int n, char *file, int line)
278 {
279     int nn = n + 4 * sizeof (long), nnn;
280     long *p, *pp;
281 
282     if (n == 0 || !old) {
283 	return xmalloc_(n, file, line);
284     }
285     p = &((long *) old)[-2];
286     if (p[0] != 0xdead1234) {
287 	fprintf(stderr, "*** low end corruption @ %p\n", old);
288 	abort();
289     }
290     nnn = p[1] + 4 * sizeof (long);
291     nnn = nnn / sizeof (long) - 1;
292     if (p[nnn] != 0xdead5678) {
293 	fprintf(stderr, "*** high end corruption @ %p\n", old);
294 	abort();
295     }
296     pp = realloc(p, nn);
297     if (!pp) {
298 #if (MEMORY_DEBUG > 1)
299 	fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
300 #endif
301 	return NULL;
302     }
303 #if (MEMORY_DEBUG > 1)
304     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
305 #endif
306     p = pp;
307     p[1] = n;
308     nn = nn / sizeof (long) - 1;
309     p[nn] = 0xdead5678;
310     return (void *) &p[2];
311 }
312 
313 static void
xfree_(void * x,char * file,int line)314 xfree_(void *x, char *file, int line)
315 {
316     long *p;
317     int n;
318 
319     if (!x) {
320 	return;
321     }
322     p = &((long *) x)[-2];
323     if (p[0] != 0xdead1234) {
324 	fprintf(stderr, "*** low end corruption @ %p\n", x);
325 	abort();
326     }
327     n = p[1] + 4 * sizeof (long);
328     n = n / sizeof (long) - 1;
329     if (p[n] != 0xdead5678) {
330 	fprintf(stderr, "*** high end corruption @ %p\n", x);
331 	abort();
332     }
333 #if (MEMORY_DEBUG > 1)
334     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
335 #endif
336     free(p);
337 }
338 
339 static void
xfree__(void * x)340 xfree__(void *x)
341 {
342     xfree_(x, "unknown location", 0);
343 }
344 
345 static char *
xstrdup_(const char * str,char * file,int line)346 xstrdup_(const char *str, char *file, int line)
347 {
348     char *p;
349 
350     if (!str) {
351 #if (MEMORY_DEBUG > 1)
352 	fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
353 #endif
354 	return NULL;
355     }
356     p = xmalloc_(strlen(str) + 1, file, line);
357     if (p) {
358 	strcpy(p, str);
359     }
360 #if (MEMORY_DEBUG > 1)
361     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
362 #endif
363     return p;
364 }
365 
366 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
367 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
368 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
369 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
370 
371 #else
372 
373 #define xmalloc(x)    sqlite3_malloc(x)
374 #define xrealloc(x,y) sqlite3_realloc(x, y)
375 #define xfree(x)      sqlite3_free(x)
376 #define xstrdup(x)    strdup_(x)
377 
378 #endif
379 
380 #if defined(_WIN32) || defined(_WIN64)
381 
382 #define vsnprintf   _vsnprintf
383 #define snprintf    _snprintf
384 #define strcasecmp  _stricmp
385 #define strncasecmp _strnicmp
386 
387 static HINSTANCE NEAR hModule;	/* Saved module handle for resources */
388 
389 #endif
390 
391 #ifdef HAVE_SQLITE3STRNICMP
392 #undef  strncasecmp
393 #define strncasecmp(A,B,C) sqlite3_strnicmp(A,B,C)
394 #undef  strcasecmp
395 #define strcasecmp(A,B) strcasecmp_(A,B)
396 
397 #if defined(__GNUC__) && (__GNUC__ >= 2)
398 static int strcasecmp_(const char *a, const char *b)
399     __attribute__((__unused__));
400 #endif
401 
strcasecmp_(const char * a,const char * b)402 static int strcasecmp_(const char *a, const char *b)
403 {
404     int c = strlen(a), d = strlen(b);
405 
406     if (c > d) {
407 	return strncasecmp(a, b, c);
408     }
409     return strncasecmp(a, b, d);
410 }
411 #endif
412 
413 #if defined(_WIN32) || defined(_WIN64)
414 
415 /*
416  * SQLHENV, SQLHDBC, and SQLHSTMT synchronization
417  * is done using a critical section in ENV structure.
418  */
419 
420 #define HDBC_LOCK(hdbc)				\
421 {						\
422     DBC *d;					\
423 						\
424     if ((hdbc) == SQL_NULL_HDBC) {		\
425 	return SQL_INVALID_HANDLE;		\
426     }						\
427     d = (DBC *) (hdbc);				\
428     if (d->magic != DBC_MAGIC || !d->env) {	\
429 	return SQL_INVALID_HANDLE;		\
430     }						\
431     if (d->env->magic != ENV_MAGIC) {		\
432 	return SQL_INVALID_HANDLE;		\
433     }						\
434     EnterCriticalSection(&d->env->cs);		\
435     d->env->owner = GetCurrentThreadId();	\
436 }
437 
438 #define HDBC_UNLOCK(hdbc)			\
439     if ((hdbc) != SQL_NULL_HDBC) {		\
440 	DBC *d;					\
441 						\
442 	d = (DBC *) (hdbc);			\
443 	if (d->magic == DBC_MAGIC && d->env &&	\
444 	    d->env->magic == ENV_MAGIC) {	\
445 	    d->env->owner = 0;			\
446 	    LeaveCriticalSection(&d->env->cs);	\
447 	}					\
448     }
449 
450 #define HSTMT_LOCK(hstmt)			\
451 {						\
452     DBC *d;					\
453 						\
454     if ((hstmt) == SQL_NULL_HSTMT) {		\
455 	return SQL_INVALID_HANDLE;		\
456     }						\
457     d = (DBC *) ((STMT *) (hstmt))->dbc;	\
458     if (d->magic != DBC_MAGIC || !d->env) {	\
459 	return SQL_INVALID_HANDLE;		\
460     }						\
461     if (d->env->magic != ENV_MAGIC) {		\
462 	return SQL_INVALID_HANDLE;		\
463     }						\
464     EnterCriticalSection(&d->env->cs);		\
465     d->env->owner = GetCurrentThreadId();	\
466 }
467 
468 #define HSTMT_UNLOCK(hstmt)			\
469     if ((hstmt) != SQL_NULL_HSTMT) {		\
470 	DBC *d;					\
471 						\
472 	d = (DBC *) ((STMT *) (hstmt))->dbc;	\
473 	if (d->magic == DBC_MAGIC && d->env &&	\
474 	    d->env->magic == ENV_MAGIC) {	\
475 	    d->env->owner = 0;			\
476 	    LeaveCriticalSection(&d->env->cs);	\
477 	}					\
478     }
479 
480 #else
481 
482 /*
483  * On UN*X assume that we are single-threaded or
484  * the driver manager provides serialization for us.
485  *
486  * In iODBC (3.52.x) serialization can be turned
487  * on using the DSN property "ThreadManager=yes".
488  *
489  * In unixODBC that property is named
490  * "Threading=0-3" and takes one of these values:
491  *
492  *   0 - no protection
493  *   1 - statement level protection
494  *   2 - connection level protection
495  *   3 - environment level protection
496  *
497  * unixODBC 2.2.11 uses environment level protection
498  * by default when it has been built with pthread
499  * support.
500  */
501 
502 #define HDBC_LOCK(hdbc)
503 #define HDBC_UNLOCK(hdbc)
504 #define HSTMT_LOCK(hdbc)
505 #define HSTMT_UNLOCK(hdbc)
506 
507 #endif
508 
509 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
510 extern void nvfs_init(void);
511 extern const char *nvfs_makevfs(const char *);
512 #endif
513 
514 /*
515  * tolower() replacement w/o locale
516  */
517 
518 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
519 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
520 
521 static int
TOLOWER(int c)522 TOLOWER(int c)
523 {
524     if (c) {
525 	char *p = strchr(upper_chars, c);
526 
527 	if (p) {
528 	    c = lower_chars[p - upper_chars];
529 	}
530     }
531     return c;
532 }
533 
534 /*
535  * isdigit() replacement w/o ctype.h
536  */
537 
538 static const char digit_chars[] = "0123456789";
539 
540 #define ISDIGIT(c) \
541     ((c) && strchr(digit_chars, (c)) != NULL)
542 
543 /*
544  * isspace() replacement w/o ctype.h
545  */
546 
547 static const char space_chars[] = " \f\n\r\t\v";
548 
549 #define ISSPACE(c) \
550     ((c) && strchr(space_chars, (c)) != NULL)
551 
552 
553 /*
554  * Forward declarations of static functions.
555  */
556 
557 static void dbtraceapi(DBC *d, char *fn, const char *sql);
558 static void freedyncols(STMT *s);
559 static void freeresult(STMT *s, int clrcols);
560 static void freerows(char **rowp);
561 static void unbindcols(STMT *s);
562 static void s3stmt_drop(STMT *s);
563 
564 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
565 static SQLRETURN freestmt(HSTMT stmt);
566 static SQLRETURN mkbindcols(STMT *s, int ncols);
567 static SQLRETURN setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp);
568 static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
569 static SQLRETURN starttran(STMT *s);
570 static SQLRETURN setupparam(STMT *s, char *sql, int pnum);
571 
572 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
573 /* MS Access hack part 1 (reserved error -7748) */
574 static COL *statSpec2P, *statSpec3P;
575 #endif
576 
577 #if (MEMORY_DEBUG < 1)
578 /**
579  * Duplicate string using xmalloc().
580  * @param str string to be duplicated
581  * @result pointer to new string or NULL
582  */
583 
584 static char *
strdup_(const char * str)585 strdup_(const char *str)
586 {
587     char *p = NULL;
588 
589     if (str) {
590 	p = xmalloc(strlen(str) + 1);
591 	if (p) {
592 	    strcpy(p, str);
593 	}
594     }
595     return p;
596 }
597 #endif
598 
599 #ifdef WCHARSUPPORT
600 
601 /**
602  * Return length of UNICODE string.
603  * @param str UNICODE string
604  * @result length of string
605  */
606 
607 static int
uc_strlen(SQLWCHAR * str)608 uc_strlen(SQLWCHAR *str)
609 {
610     int len = 0;
611 
612     if (str) {
613 	while (*str) {
614 	    ++len;
615 	    ++str;
616 	}
617     }
618     return len;
619 }
620 
621 /**
622  * Copy UNICODE string like strncpy().
623  * @param dest destination area
624  * @param src source area
625  * @param len length of source area
626  * @return pointer to destination area
627  */
628 
629 static SQLWCHAR *
uc_strncpy(SQLWCHAR * dest,SQLWCHAR * src,int len)630 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
631 {
632     int i = 0;
633 
634     while (i < len) {
635 	if (!src[i]) {
636 	    break;
637 	}
638 	dest[i] = src[i];
639 	++i;
640     }
641     if (i < len) {
642 	dest[i] = 0;
643     }
644     return dest;
645 }
646 
647 /**
648  * Make UNICODE string from UTF8 string into buffer.
649  * @param str UTF8 string to be converted
650  * @param len length of str or -1
651  * @param uc destination area to receive UNICODE string
652  * @param ucLen byte length of destination area
653  */
654 
655 static void
uc_from_utf_buf(unsigned char * str,int len,SQLWCHAR * uc,int ucLen)656 uc_from_utf_buf(unsigned char *str, int len, SQLWCHAR *uc, int ucLen)
657 {
658     ucLen = ucLen / sizeof (SQLWCHAR);
659     if (!uc || ucLen < 0) {
660 	return;
661     }
662     if (len < 0) {
663 	len = ucLen * 5;
664     }
665     uc[0] = 0;
666     if (str) {
667 	int i = 0;
668 
669 	while (i < len && *str && i < ucLen) {
670 	    unsigned char c = str[0];
671 
672 	    if (c < 0x80) {
673 		uc[i++] = c;
674 		++str;
675 	    } else if (c <= 0xc1 || c >= 0xf5) {
676 		/* illegal, ignored */
677 		++str;
678 	    } else if (c < 0xe0) {
679 		if ((str[1] & 0xc0) == 0x80) {
680 		    unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
681 
682 		    uc[i++] = t;
683 		    str += 2;
684 		} else {
685 		    uc[i++] = c;
686 		    ++str;
687 		}
688 	    } else if (c < 0xf0) {
689 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
690 		    unsigned long t = ((c & 0x0f) << 12) |
691 			((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
692 
693 		    uc[i++] = t;
694 		    str += 3;
695 		} else {
696 		    uc[i++] = c;
697 		    ++str;
698 		}
699 	    } else if (c < 0xf8) {
700 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
701 		    (str[3] & 0xc0) == 0x80) {
702 		    unsigned long t = ((c & 0x03) << 18) |
703 			((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
704 			(str[4] & 0x3f);
705 
706 		    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
707 			t >= 0x10000) {
708 			t -= 0x10000;
709 			uc[i++] = 0xd800 | (t & 0x3ff);
710 			if (i >= ucLen) {
711 			    break;
712 			}
713 			t = 0xdc00 | ((t >> 10) & 0x3ff);
714 		    }
715 		    uc[i++] = t;
716 		    str += 4;
717 		} else {
718 		    uc[i++] = c;
719 		    ++str;
720 		}
721 	    } else if (c < 0xfc) {
722 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
723 		    (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80) {
724 		    unsigned long t = ((c & 0x01) << 24) |
725 			((str[1] & 0x3f) << 18) | ((str[2] & 0x3f) << 12) |
726 			((str[4] & 0x3f) << 6) | (str[5] & 0x3f);
727 
728 		    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
729 			t >= 0x10000) {
730 			t -= 0x10000;
731 			uc[i++] = 0xd800 | (t & 0x3ff);
732 			if (i >= ucLen) {
733 			    break;
734 			}
735 			t = 0xdc00 | ((t >> 10) & 0x3ff);
736 		    }
737 		    uc[i++] = t;
738 		    str += 5;
739 		} else {
740 		    uc[i++] = c;
741 		    ++str;
742 		}
743 	    } else {
744 		/* ignore */
745 		++str;
746 	    }
747 	}
748 	if (i < ucLen) {
749 	    uc[i] = 0;
750 	}
751     }
752 }
753 
754 /**
755  * Make UNICODE string from UTF8 string.
756  * @param str UTF8 string to be converted
757  * @param len length of UTF8 string
758  * @return alloc'ed UNICODE string to be free'd by uc_free()
759  */
760 
761 static SQLWCHAR *
uc_from_utf(unsigned char * str,int len)762 uc_from_utf(unsigned char *str, int len)
763 {
764     SQLWCHAR *uc = NULL;
765     int ucLen;
766 
767     if (str) {
768 	if (len == SQL_NTS) {
769 	    len = strlen((char *) str);
770 	}
771 	ucLen = sizeof (SQLWCHAR) * (len + 1);
772 	uc = xmalloc(ucLen);
773 	if (uc) {
774 	    uc_from_utf_buf(str, len, uc, ucLen);
775 	}
776     }
777     return uc;
778 }
779 
780 /**
781  * Make UTF8 string from UNICODE string.
782  * @param str UNICODE string to be converted
783  * @param len length of UNICODE string in bytes
784  * @return alloc'ed UTF8 string to be free'd by uc_free()
785  */
786 
787 static char *
uc_to_utf(SQLWCHAR * str,int len)788 uc_to_utf(SQLWCHAR *str, int len)
789 {
790     int i;
791     char *cp, *ret = NULL;
792 
793     if (!str) {
794 	return ret;
795     }
796     if (len == SQL_NTS) {
797 	len = uc_strlen(str);
798     } else {
799 	len = len / sizeof (SQLWCHAR);
800     }
801     cp = xmalloc(len * 6 + 1);
802     if (!cp) {
803 	return ret;
804     }
805     ret = cp;
806     for (i = 0; i < len; i++) {
807 	unsigned long c = str[i];
808 
809 	if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
810 	    c &= 0xffff;
811 	}
812 	if (c < 0x80) {
813 	    *cp++ = c;
814 	} else if (c < 0x800) {
815 	    *cp++ = 0xc0 | ((c >> 6) & 0x1f);
816 	    *cp++ = 0x80 | (c & 0x3f);
817 	} else if (c < 0x10000) {
818 	    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
819 		c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
820 		unsigned long c2 = str[i + 1] & 0xffff;
821 
822 		if (c2 >= 0xdc00 && c <= 0xdfff) {
823 		    c = ((c & 0x3ff) | ((c2 & 0x3ff) << 10)) + 0x10000;
824 		    *cp++ = 0xf0 | ((c >> 18) & 0x07);
825 		    *cp++ = 0x80 | ((c >> 12) & 0x3f);
826 		    *cp++ = 0x80 | ((c >> 6) & 0x3f);
827 		    *cp++ = 0x80 | (c & 0x3f);
828 		    ++i;
829 		    continue;
830 		}
831 	    }
832 	    *cp++ = 0xe0 | ((c >> 12) & 0x0f);
833 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
834 	    *cp++ = 0x80 | (c & 0x3f);
835 	} else if (c < 0x200000) {
836 	    *cp++ = 0xf0 | ((c >> 18) & 0x07);
837 	    *cp++ = 0x80 | ((c >> 12) & 0x3f);
838 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
839 	    *cp++ = 0x80 | (c & 0x3f);
840 	} else if (c < 0x4000000) {
841 	    *cp++ = 0xf8 | ((c >> 24) & 0x03);
842 	    *cp++ = 0x80 | ((c >> 18) & 0x3f);
843 	    *cp++ = 0x80 | ((c >> 12) & 0x3f);
844 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
845 	    *cp++ = 0x80 | (c & 0x3f);
846 	} else if (c < 0x80000000) {
847 	    *cp++ = 0xfc | ((c >> 31) & 0x01);
848 	    *cp++ = 0x80 | ((c >> 24) & 0x3f);
849 	    *cp++ = 0x80 | ((c >> 18) & 0x3f);
850 	    *cp++ = 0x80 | ((c >> 12) & 0x3f);
851 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
852 	    *cp++ = 0x80 | (c & 0x3f);
853 	}
854     }
855     *cp = '\0';
856     return ret;
857 }
858 
859 #endif
860 
861 #ifdef WINTERFACE
862 
863 /**
864  * Make UTF8 string from UNICODE string.
865  * @param str UNICODE string to be converted
866  * @param len length of UNICODE string in characters
867  * @return alloc'ed UTF8 string to be free'd by uc_free()
868  */
869 
870 static char *
uc_to_utf_c(SQLWCHAR * str,int len)871 uc_to_utf_c(SQLWCHAR *str, int len)
872 {
873     if (len != SQL_NTS) {
874 	len = len * sizeof (SQLWCHAR);
875     }
876     return uc_to_utf(str, len);
877 }
878 
879 #endif
880 
881 #if defined(WCHARSUPPORT) || defined(_WIN32) || defined(_WIN64)
882 
883 /**
884  * Free converted UTF8 or UNICODE string.
885  * @param str string to be free'd
886  */
887 
888 static void
uc_free(void * str)889 uc_free(void *str)
890 {
891     if (str) {
892 	xfree(str);
893     }
894 }
895 
896 #endif
897 
898 #if defined(_WIN32) || defined(_WIN64)
899 
900 /**
901  * Convert multibyte, current code page string to UTF8 string,
902  * @param str multibyte string to be converted
903  * @param len length of multibyte string
904  * @return alloc'ed UTF8 string to be free'd by uc_free()
905  */
906 
907 static char *
wmb_to_utf(char * str,int len)908 wmb_to_utf(char *str, int len)
909 {
910     WCHAR *wstr;
911     OSVERSIONINFO ovi;
912     int nchar, is2k, cp = CP_OEMCP;
913 
914     ovi.dwOSVersionInfoSize = sizeof (ovi);
915     GetVersionEx(&ovi);
916     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
917     if (AreFileApisANSI()) {
918 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
919     }
920     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
921     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
922     if (!wstr) {
923 	return NULL;
924     }
925     wstr[0] = 0;
926     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
927     wstr[nchar] = 0;
928     str = xmalloc((nchar + 1) * 7);
929     if (!str) {
930 	xfree(wstr);
931 	return NULL;
932     }
933     str[0] = '\0';
934     nchar = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, nchar * 7, 0, 0);
935     str[nchar] = '\0';
936     xfree(wstr);
937     return str;
938 }
939 
940 #ifndef WINTERFACE
941 
942 /**
943  * Convert multibyte, current code page string to UTF8 string,
944  * @param str multibyte string to be converted
945  * @param len length of multibyte string
946  * @return alloc'ed UTF8 string to be free'd by uc_free()
947  */
948 
949 static char *
wmb_to_utf_c(char * str,int len)950 wmb_to_utf_c(char *str, int len)
951 {
952     if (len == SQL_NTS) {
953 	len = strlen(str);
954     }
955     return wmb_to_utf(str, len);
956 }
957 
958 #endif
959 
960 /**
961  * Convert UTF8 string to multibyte, current code page string,
962  * @param str UTF8 string to be converted
963  * @param len length of UTF8 string
964  * @return alloc'ed multibyte string to be free'd by uc_free()
965  */
966 
967 static char *
utf_to_wmb(char * str,int len)968 utf_to_wmb(char *str, int len)
969 {
970     WCHAR *wstr;
971     OSVERSIONINFO ovi;
972     int nchar, is2k, cp = CP_OEMCP;
973 
974     ovi.dwOSVersionInfoSize = sizeof (ovi);
975     GetVersionEx(&ovi);
976     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
977     if (AreFileApisANSI()) {
978 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
979     }
980     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
981     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
982     if (!wstr) {
983 	return NULL;
984     }
985     wstr[0] = 0;
986     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, nchar);
987     wstr[nchar] = 0;
988     str = xmalloc((nchar + 1) * 7);
989     if (!str) {
990 	xfree(wstr);
991 	return NULL;
992     }
993     str[0] = '\0';
994     nchar = WideCharToMultiByte(cp, 0, wstr, -1, str, nchar * 7, 0, 0);
995     str[nchar] = '\0';
996     xfree(wstr);
997     return str;
998 }
999 
1000 #ifdef WINTERFACE
1001 
1002 /**
1003  * Convert multibyte, current code page string to UNICODE string,
1004  * @param str multibyte string to be converted
1005  * @param len length of multibyte string
1006  * @return alloc'ed UNICODE string to be free'd by uc_free()
1007  */
1008 
1009 static WCHAR *
wmb_to_uc(char * str,int len)1010 wmb_to_uc(char *str, int len)
1011 {
1012     WCHAR *wstr;
1013     OSVERSIONINFO ovi;
1014     int nchar, is2k, cp = CP_OEMCP;
1015 
1016     ovi.dwOSVersionInfoSize = sizeof (ovi);
1017     GetVersionEx(&ovi);
1018     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1019     if (AreFileApisANSI()) {
1020 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1021     }
1022     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
1023     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1024     if (!wstr) {
1025 	return NULL;
1026     }
1027     wstr[0] = 0;
1028     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
1029     wstr[nchar] = 0;
1030     return wstr;
1031 }
1032 
1033 /**
1034  * Convert UNICODE string to multibyte, current code page string,
1035  * @param str UNICODE string to be converted
1036  * @param len length of UNICODE string
1037  * @return alloc'ed multibyte string to be free'd by uc_free()
1038  */
1039 
1040 static char *
uc_to_wmb(WCHAR * wstr,int len)1041 uc_to_wmb(WCHAR *wstr, int len)
1042 {
1043     char *str;
1044     OSVERSIONINFO ovi;
1045     int nchar, is2k, cp = CP_OEMCP;
1046 
1047     ovi.dwOSVersionInfoSize = sizeof (ovi);
1048     GetVersionEx(&ovi);
1049     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1050     if (AreFileApisANSI()) {
1051 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1052     }
1053     nchar = WideCharToMultiByte(cp, 0, wstr, len, NULL, 0, 0, 0);
1054     str = xmalloc((nchar + 1) * 2);
1055     if (!str) {
1056 	return NULL;
1057     }
1058     str[0] = '\0';
1059     nchar = WideCharToMultiByte(cp, 0, wstr, len, str, nchar * 2, 0, 0);
1060     str[nchar] = '\0';
1061     return str;
1062 }
1063 
1064 #endif /* WINTERFACE */
1065 
1066 #endif /* _WIN32 || _WIN64 */
1067 
1068 
1069 #ifdef USE_DLOPEN_FOR_GPPS
1070 
1071 #include <dlfcn.h>
1072 
1073 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
1074 
1075 /*
1076  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
1077  * dlopen(), in theory this makes the driver independent from the
1078  * driver manager, i.e. the same driver binary can run with iODBC
1079  * and unixODBC.
1080  */
1081 
1082 static void
drvgetgpps(DBC * d)1083 drvgetgpps(DBC *d)
1084 {
1085     void *lib;
1086     int (*gpps)();
1087 
1088     lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
1089     if (!lib) {
1090 	lib = dlopen("libodbcinst.so", RTLD_LAZY);
1091     }
1092     if (!lib) {
1093 	lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
1094     }
1095     if (!lib) {
1096 	lib = dlopen("libiodbcinst.so", RTLD_LAZY);
1097     }
1098     if (lib) {
1099 	gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
1100 	if (!gpps) {
1101 	    dlclose(lib);
1102 	    return;
1103 	}
1104 	d->instlib = lib;
1105 	d->gpps = gpps;
1106     }
1107 }
1108 
1109 static void
drvrelgpps(DBC * d)1110 drvrelgpps(DBC *d)
1111 {
1112     if (d->instlib) {
1113 	dlclose(d->instlib);
1114 	d->instlib = 0;
1115     }
1116 }
1117 
1118 static int
drvgpps(DBC * d,char * sect,char * ent,char * def,char * buf,int bufsiz,char * fname)1119 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
1120 	int bufsiz, char *fname)
1121 {
1122     if (d->gpps) {
1123 	return d->gpps(sect, ent, def, buf, bufsiz, fname);
1124     }
1125     strncpy(buf, def, bufsiz);
1126     buf[bufsiz - 1] = '\0';
1127     return 1;
1128 }
1129 #else
1130 #include <odbcinst.h>
1131 #define drvgetgpps(d)
1132 #define drvrelgpps(d)
1133 #endif
1134 
1135 /*
1136  * Internal function to bind SQLite3 parameters.
1137  */
1138 
1139 static void
s3bind(DBC * d,sqlite3_stmt * stmt,int nparams,BINDPARM * p)1140 s3bind(DBC *d, sqlite3_stmt *stmt, int nparams, BINDPARM *p)
1141 {
1142     int i;
1143 
1144     if (stmt && p && nparams > 0) {
1145 	for (i = 0; i < nparams; i++, p++) {
1146 	    switch (p->s3type) {
1147 	    default:
1148 	    case SQLITE_NULL:
1149 		sqlite3_bind_null(stmt, i + 1);
1150 		if (d->trace) {
1151 		    fprintf(d->trace, "-- parameter %d: NULL\n", i + 1);
1152 		    fflush(d->trace);
1153 		}
1154 		break;
1155 	    case SQLITE_TEXT:
1156 		sqlite3_bind_text(stmt, i + 1, p->s3val, p->s3size,
1157 				  SQLITE_STATIC);
1158 		if (d->trace) {
1159 		    fprintf(d->trace, "-- parameter %d: '%*s'\n", i + 1,
1160 			    p->s3size, (char *) p->s3val);
1161 		    fflush(d->trace);
1162 		}
1163 		break;
1164 	    case SQLITE_BLOB:
1165 		sqlite3_bind_blob(stmt, i + 1, p->s3val, p->s3size,
1166 				  SQLITE_STATIC);
1167 		if (d->trace) {
1168 		    fprintf(d->trace, "-- parameter %d: [BLOB]'\n", i + 1);
1169 		    fflush(d->trace);
1170 		}
1171 		break;
1172 	    case SQLITE_FLOAT:
1173 		sqlite3_bind_double(stmt, i + 1, p->s3dval);
1174 		if (d->trace) {
1175 		    fprintf(d->trace, "-- parameter %d: %g\n",
1176 			    i + 1, p->s3dval);
1177 		    fflush(d->trace);
1178 		}
1179 		break;
1180 	    case SQLITE_INTEGER:
1181 		if (p->s3size > sizeof (int)) {
1182 		    sqlite3_bind_int64(stmt, i + 1, p->s3lival);
1183 		    if (d->trace) {
1184 			fprintf(d->trace,
1185 #ifdef _WIN32
1186 				"-- parameter %d: %I64d\n",
1187 #else
1188 				"-- parameter %d: %lld\n",
1189 #endif
1190 				i + 1, p->s3lival);
1191 			fflush(d->trace);
1192 		    }
1193 		} else {
1194 		    sqlite3_bind_int(stmt, i + 1, p->s3ival);
1195 		    if (d->trace) {
1196 			fprintf(d->trace, "-- parameter %d: %d\n",
1197 				i + 1, p->s3ival);
1198 			fflush(d->trace);
1199 		    }
1200 		}
1201 		break;
1202 	    }
1203 	}
1204     }
1205 }
1206 
1207 /*
1208  * Internal structure for managing driver's
1209  * sqlite3_get_table() implementation.
1210  */
1211 
1212 typedef struct tblres {
1213     char **resarr;
1214     char *errmsg;
1215     sqlite3_stmt *stmt;
1216     STMT *s;
1217     int nres;
1218     int nalloc;
1219     int nrow;
1220     int ncol;
1221     PTRDIFF_T ndata;
1222     int rc;
1223 } TBLRES;
1224 
1225 /*
1226  * Driver's version of sqlite3_get_table() and friends which are
1227  * capable of dealing with blobs.
1228  */
1229 
1230 static int
drvgettable_row(TBLRES * t,int ncol,int rc)1231 drvgettable_row(TBLRES *t, int ncol, int rc)
1232 {
1233     int need;
1234     int i;
1235     char *p;
1236 
1237     if (t->nrow == 0 && rc == SQLITE_ROW) {
1238 	need = ncol * 2;
1239     } else {
1240 	need = ncol;
1241     }
1242     if (t->ndata + need >= t->nalloc) {
1243 	char **resnew;
1244 	int nalloc = t->nalloc * 2 + need + 1;
1245 
1246 	resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
1247 	if (!resnew) {
1248 nomem:
1249 	    t->rc = SQLITE_NOMEM;
1250 	    return 1;
1251 	}
1252 	t->nalloc = nalloc;
1253 	t->resarr = resnew;
1254     }
1255     /* column names when first row */
1256     if (t->nrow == 0) {
1257 	t->ncol = ncol;
1258 	for (i = 0; i < ncol; i++) {
1259 	    p = (char *) sqlite3_column_name(t->stmt, i);
1260 	    if (p) {
1261 		char *q = xmalloc(strlen(p) + 1);
1262 
1263 		if (!q) {
1264 		    goto nomem;
1265 		}
1266 		strcpy(q, p);
1267 		p = q;
1268 	    }
1269 	    t->resarr[t->ndata++] = p;
1270 	}
1271 	if (t->s && t->s->guessed_types) {
1272 	    int ncol2 = ncol;
1273 
1274 	    setupdyncols(t->s, t->stmt, &ncol2);
1275 	    t->s->guessed_types = 0;
1276 	    t->s->ncols = ncol;
1277 	}
1278     } else if (t->ncol != ncol) {
1279 	t->errmsg = sqlite3_mprintf("drvgettable() called with two or"
1280 				    " more incompatible queries");
1281 	t->rc = SQLITE_ERROR;
1282 	return 1;
1283     }
1284     /* copy row data */
1285     if (rc == SQLITE_ROW) {
1286 	for (i = 0; i < ncol; i++) {
1287 	    int coltype = sqlite3_column_type(t->stmt, i);
1288 
1289 	    p = NULL;
1290 	    if (coltype == SQLITE_BLOB) {
1291 		int k, nbytes = sqlite3_column_bytes(t->stmt, i);
1292 		char *qp;
1293 		unsigned const char *bp;
1294 
1295 		bp = sqlite3_column_blob(t->stmt, i);
1296 		qp = xmalloc(nbytes * 2 + 4);
1297 		if (!qp) {
1298 		    goto nomem;
1299 		}
1300 		p = qp;
1301 		*qp++ = 'X';
1302 		*qp++ = '\'';
1303 		for (k = 0; k < nbytes; k++) {
1304 		    *qp++ = xdigits[(bp[k] >> 4)];
1305 		    *qp++ = xdigits[(bp[k] & 0xF)];
1306 		}
1307 		*qp++ = '\'';
1308 		*qp = '\0';
1309 	    } else if (coltype != SQLITE_NULL) {
1310 		p = xstrdup((char *) sqlite3_column_text(t->stmt, i));
1311 		if (!p) {
1312 		    goto nomem;
1313 		}
1314 	    }
1315 	    t->resarr[t->ndata++] = p;
1316 	}
1317 	t->nrow++;
1318     }
1319     return 0;
1320 }
1321 
1322 static int
drvgettable(STMT * s,const char * sql,char *** resp,int * nrowp,int * ncolp,char ** errp,int nparam,BINDPARM * p)1323 drvgettable(STMT *s, const char *sql, char ***resp, int *nrowp,
1324 	    int *ncolp, char **errp, int nparam, BINDPARM *p)
1325 {
1326     DBC *d = (DBC *) s->dbc;
1327     int rc = SQLITE_OK, keep = sql == NULL;
1328     TBLRES tres;
1329     const char *sqlleft = 0;
1330     int nretry = 0, haveerr = 0;
1331 
1332     if (!resp) {
1333 	return SQLITE_ERROR;
1334     }
1335     *resp = NULL;
1336     if (nrowp) {
1337 	*nrowp = 0;
1338     }
1339     if (ncolp) {
1340 	*ncolp = 0;
1341     }
1342     tres.errmsg = NULL;
1343     tres.nres = 0;
1344     tres.nrow = 0;
1345     tres.ncol = 0;
1346     tres.ndata = 1;
1347     tres.nalloc = 20;
1348     tres.rc = SQLITE_OK;
1349     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
1350     tres.stmt = NULL;
1351     tres.s = s;
1352     if (!tres.resarr) {
1353 	return SQLITE_NOMEM;
1354     }
1355     tres.resarr[0] = 0;
1356     if (sql == NULL) {
1357 	tres.stmt = s->s3stmt;
1358 	if (tres.stmt == NULL) {
1359 	    return SQLITE_NOMEM;
1360 	}
1361 	goto retrieve;
1362     }
1363     while (sql && *sql && (rc == SQLITE_OK ||
1364 			   (rc == SQLITE_SCHEMA && (++nretry) < 2))) {
1365 	int ncol;
1366 
1367 	tres.stmt = NULL;
1368 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
1369 	dbtraceapi(d, "sqlite3_prepare_v2", sql);
1370 	rc = sqlite3_prepare_v2(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
1371 #else
1372 	dbtraceapi(d, "sqlite3_prepare", sql);
1373 	rc = sqlite3_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
1374 #endif
1375 	if (rc != SQLITE_OK) {
1376 	    if (tres.stmt) {
1377 		dbtraceapi(d, "sqlite3_finalize", 0);
1378 		sqlite3_finalize(tres.stmt);
1379 		tres.stmt = NULL;
1380 	    }
1381 	    continue;
1382 	}
1383 	if (!tres.stmt) {
1384 	    /* this happens for a comment or white-space */
1385 	    sql = sqlleft;
1386 	    continue;
1387 	}
1388 retrieve:
1389 	if (sqlite3_bind_parameter_count(tres.stmt) != nparam) {
1390 	    if (errp) {
1391 		*errp =
1392 		    sqlite3_mprintf("%s", "parameter marker count incorrect");
1393 	    }
1394 	    haveerr = 1;
1395 	    rc = SQLITE_ERROR;
1396 	    goto tbldone;
1397 	}
1398 	s3bind(d, tres.stmt, nparam, p);
1399 	ncol = sqlite3_column_count(tres.stmt);
1400 	while (1) {
1401 	    if (s->max_rows && tres.nrow >= s->max_rows) {
1402 		rc = SQLITE_OK;
1403 		break;
1404 	    }
1405 	    rc = sqlite3_step(tres.stmt);
1406 	    if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
1407 		if (drvgettable_row(&tres, ncol, rc)) {
1408 		    rc = SQLITE_ABORT;
1409 		    goto tbldone;
1410 		}
1411 	    }
1412 	    if (rc != SQLITE_ROW) {
1413 		if (keep) {
1414 		    dbtraceapi(d, "sqlite3_reset", 0);
1415 		    rc = sqlite3_reset(tres.stmt);
1416 		    s->s3stmt_noreset = 1;
1417 		} else {
1418 		    dbtraceapi(d, "sqlite3_finalize", 0);
1419 		    rc = sqlite3_finalize(tres.stmt);
1420 		}
1421 		tres.stmt = 0;
1422 		if (rc != SQLITE_SCHEMA) {
1423 		    nretry = 0;
1424 		    sql = sqlleft;
1425 		    while (sql && ISSPACE(*sql)) {
1426 			sql++;
1427 		    }
1428 		}
1429 		if (rc == SQLITE_DONE) {
1430 		    rc = SQLITE_OK;
1431 		}
1432 		break;
1433 	    }
1434 	}
1435     }
1436 tbldone:
1437     if (tres.stmt) {
1438 	if (keep) {
1439 	    if (!s->s3stmt_noreset) {
1440 		dbtraceapi(d, "sqlite3_reset", 0);
1441 		sqlite3_reset(tres.stmt);
1442 		s->s3stmt_noreset = 1;
1443 	    }
1444 	} else {
1445 	    dbtraceapi(d, "sqlite3_finalize", 0);
1446 	    sqlite3_finalize(tres.stmt);
1447 	}
1448     }
1449     if (haveerr) {
1450 	/* message already in *errp if any */
1451     } else if (rc != SQLITE_OK && rc == sqlite3_errcode(d->sqlite) && errp) {
1452 	*errp = sqlite3_mprintf("%s", sqlite3_errmsg(d->sqlite));
1453     } else if (errp) {
1454 	*errp = NULL;
1455     }
1456     if (tres.resarr) {
1457 	tres.resarr[0] = (char *) (tres.ndata - 1);
1458     }
1459     if (rc == SQLITE_ABORT) {
1460 	freerows(&tres.resarr[1]);
1461 	if (tres.errmsg) {
1462 	    if (errp) {
1463 		if (*errp) {
1464 		    sqlite3_free(*errp);
1465 		}
1466 		*errp = tres.errmsg;
1467 	    } else {
1468 		sqlite3_free(tres.errmsg);
1469 	    }
1470 	}
1471 	return tres.rc;
1472     }
1473     sqlite3_free(tres.errmsg);
1474     if (rc != SQLITE_OK) {
1475 	freerows(&tres.resarr[1]);
1476 	return rc;
1477     }
1478     *resp = &tres.resarr[1];
1479     if (ncolp) {
1480 	*ncolp = tres.ncol;
1481     }
1482     if (nrowp) {
1483 	*nrowp = tres.nrow;
1484     }
1485     return rc;
1486 }
1487 
1488 /**
1489  * Set error message and SQL state on DBC
1490  * @param d database connection pointer
1491  * @param naterr native error code
1492  * @param msg error message
1493  * @param st SQL state
1494  */
1495 
1496 #if defined(__GNUC__) && (__GNUC__ >= 2)
1497 static void setstatd(DBC *, int, char *, char *, ...)
1498     __attribute__((format (printf, 3, 5)));
1499 #endif
1500 
1501 static void
setstatd(DBC * d,int naterr,char * msg,char * st,...)1502 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
1503 {
1504     va_list ap;
1505 
1506     if (!d) {
1507 	return;
1508     }
1509     d->naterr = naterr;
1510     d->logmsg[0] = '\0';
1511     if (msg) {
1512 	int count;
1513 
1514 	va_start(ap, st);
1515 	count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
1516 	va_end(ap);
1517 	if (count < 0) {
1518 	    d->logmsg[sizeof (d->logmsg) - 1] = '\0';
1519 	}
1520     }
1521     if (!st) {
1522 	st = "?????";
1523     }
1524     strncpy(d->sqlstate, st, 5);
1525     d->sqlstate[5] = '\0';
1526 }
1527 
1528 /**
1529  * Set error message and SQL state on statement
1530  * @param s statement pointer
1531  * @param naterr native error code
1532  * @param msg error message
1533  * @param st SQL state
1534  */
1535 
1536 #if defined(__GNUC__) && (__GNUC__ >= 2)
1537 static void setstat(STMT *, int, char *, char *, ...)
1538     __attribute__((format (printf, 3, 5)));
1539 #endif
1540 
1541 static void
setstat(STMT * s,int naterr,char * msg,char * st,...)1542 setstat(STMT *s, int naterr, char *msg, char *st, ...)
1543 {
1544     va_list ap;
1545 
1546     if (!s) {
1547 	return;
1548     }
1549     s->naterr = naterr;
1550     s->logmsg[0] = '\0';
1551     if (msg) {
1552 	int count;
1553 
1554 	va_start(ap, st);
1555 	count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
1556 	va_end(ap);
1557 	if (count < 0) {
1558 	    s->logmsg[sizeof (s->logmsg) - 1] = '\0';
1559 	}
1560     }
1561     if (!st) {
1562 	st = "?????";
1563     }
1564     strncpy(s->sqlstate, st, 5);
1565     s->sqlstate[5] = '\0';
1566 }
1567 
1568 /**
1569  * Report IM001 (not implemented) SQL error code for HDBC.
1570  * @param dbc database connection handle
1571  * @result ODBC error code
1572  */
1573 
1574 static SQLRETURN
drvunimpldbc(HDBC dbc)1575 drvunimpldbc(HDBC dbc)
1576 {
1577     DBC *d;
1578 
1579     if (dbc == SQL_NULL_HDBC) {
1580 	return SQL_INVALID_HANDLE;
1581     }
1582     d = (DBC *) dbc;
1583     setstatd(d, -1, "not supported", "IM001");
1584     return SQL_ERROR;
1585 }
1586 
1587 /**
1588  * Report IM001 (not implemented) SQL error code for HSTMT.
1589  * @param stmt statement handle
1590  * @result ODBC error code
1591  */
1592 
1593 static SQLRETURN
drvunimplstmt(HSTMT stmt)1594 drvunimplstmt(HSTMT stmt)
1595 {
1596     STMT *s;
1597 
1598     if (stmt == SQL_NULL_HSTMT) {
1599 	return SQL_INVALID_HANDLE;
1600     }
1601     s = (STMT *) stmt;
1602     setstat(s, -1, "not supported", "IM001");
1603     return SQL_ERROR;
1604 }
1605 
1606 /**
1607  * Free memory given pointer to memory pointer.
1608  * @param x pointer to pointer to memory to be free'd
1609  */
1610 
1611 static void
freep(void * x)1612 freep(void *x)
1613 {
1614     if (x && ((char **) x)[0]) {
1615 	xfree(((char **) x)[0]);
1616 	((char **) x)[0] = NULL;
1617     }
1618 }
1619 
1620 /**
1621  * Report S1000 (out of memory) SQL error given STMT.
1622  * @param s statement pointer
1623  * @result ODBC error code
1624  */
1625 
1626 static SQLRETURN
nomem(STMT * s)1627 nomem(STMT *s)
1628 {
1629     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
1630     return SQL_ERROR;
1631 }
1632 
1633 /**
1634  * Report S1000 (not connected) SQL error given STMT.
1635  * @param s statement pointer
1636  * @result ODBC error code
1637  */
1638 
1639 static SQLRETURN
noconn(STMT * s)1640 noconn(STMT *s)
1641 {
1642     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
1643     return SQL_ERROR;
1644 }
1645 
1646 /**
1647  * Internal locale neutral strtod function.
1648  * @param data pointer to string
1649  * @param endp pointer for ending character
1650  * @result double value
1651  */
1652 
1653 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
1654 
1655 static double
ln_strtod(const char * data,char ** endp)1656 ln_strtod(const char *data, char **endp)
1657 {
1658     struct lconv *lc;
1659     char buf[128], *p, *end;
1660     double value;
1661 
1662     lc = localeconv();
1663     if (lc && lc->decimal_point && lc->decimal_point[0] &&
1664 	lc->decimal_point[0] != '.') {
1665 	strncpy(buf, data, sizeof (buf) - 1);
1666 	buf[sizeof (buf) - 1] = '\0';
1667 	p = strchr(buf, '.');
1668 	if (p) {
1669 	    *p = lc->decimal_point[0];
1670 	}
1671 	p = buf;
1672     } else {
1673 	p = (char *) data;
1674     }
1675     value = strtod(p, &end);
1676     end = (char *) data + (end - p);
1677     if (endp) {
1678 	*endp = end;
1679     }
1680     return value;
1681 }
1682 
1683 #else
1684 
1685 #define ln_strtod(A,B) strtod(A,B)
1686 
1687 #endif
1688 
1689 /**
1690  * Strip quotes from quoted string in-place.
1691  * @param str string
1692  */
1693 
1694 static char *
unquote(char * str)1695 unquote(char *str)
1696 {
1697     if (str) {
1698 	int len = strlen(str);
1699 
1700 	if (len > 1) {
1701 	    if ((str[0] == '\'' && str[len - 1] == '\'') ||
1702 		(str[0] == '"' && str[len - 1] == '"') ||
1703 		(str[0] == '[' && str[len - 1] == ']')) {
1704 		str[len - 1] = '\0';
1705 		strcpy(str, str + 1);
1706 	    }
1707 	}
1708     }
1709     return str;
1710 }
1711 
1712 /**
1713  * Unescape search pattern for e.g. table name in
1714  * catalog functions. Replacements in string are done in-place.
1715  * @param str string
1716  * @result number of pattern characters in string or 0
1717  */
1718 
1719 static int
unescpat(char * str)1720 unescpat(char *str)
1721 {
1722     char *p, *q;
1723     int count = 0;
1724 
1725     p = str;
1726     while ((q = strchr(p, '_')) != NULL) {
1727 	if (q == str || q[-1] != '\\') {
1728 	    count++;
1729 	}
1730 	p = q + 1;
1731     }
1732     p = str;
1733     while ((q = strchr(p, '%')) != NULL) {
1734 	if (q == str || q[-1] != '\\') {
1735 	    count++;
1736 	}
1737 	p = q + 1;
1738     }
1739     p = str;
1740     while ((q = strchr(p, '\\')) != NULL) {
1741 	if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
1742 	    strcpy(q, q + 1);
1743 	}
1744 	p = q + 1;
1745     }
1746     return count;
1747 }
1748 
1749 /**
1750  * SQL LIKE string match with optional backslash escape handling.
1751  * @param str string
1752  * @param pat pattern
1753  * @param esc when true, treat literally "\\" as "\", "\?" as "?", "\_" as "_"
1754  * @result true when pattern matched
1755  */
1756 
1757 static int
namematch(char * str,char * pat,int esc)1758 namematch(char *str, char *pat, int esc)
1759 {
1760     int cp, ch;
1761 
1762     while (1) {
1763 	cp = TOLOWER(*pat);
1764 	if (cp == '\0') {
1765 	    if (*str != '\0') {
1766 		goto nomatch;
1767 	    }
1768 	    break;
1769 	}
1770 	if (*str == '\0' && cp != '%') {
1771 	    goto nomatch;
1772 	}
1773 	if (cp == '%') {
1774 	    while (*pat == '%') {
1775 		++pat;
1776 	    }
1777 	    cp = TOLOWER(*pat);
1778 	    if (cp == '\0') {
1779 		break;
1780 	    }
1781 	    while (1) {
1782 		if (cp != '_' && cp != '\\') {
1783 		    while (*str) {
1784 			ch = TOLOWER(*str);
1785 			if (ch == cp) {
1786 			    break;
1787 			}
1788 			++str;
1789 		    }
1790 		}
1791 		if (namematch(str, pat, esc)) {
1792 		    goto match;
1793 		}
1794 		if (*str == '\0') {
1795 		    goto nomatch;
1796 		}
1797 		ch = TOLOWER(*str);
1798 		++str;
1799 	    }
1800 	}
1801 	if (cp == '_') {
1802 	    pat++;
1803 	    str++;
1804 	    continue;
1805 	}
1806 	if (esc && cp == '\\' &&
1807 	    (pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
1808 	    ++pat;
1809 	    cp = TOLOWER(*pat);
1810 	}
1811 	ch = TOLOWER(*str++);
1812 	++pat;
1813 	if (ch != cp) {
1814 	    goto nomatch;
1815 	}
1816     }
1817 match:
1818     return 1;
1819 nomatch:
1820     return 0;
1821 }
1822 
1823 /**
1824  * Busy callback for SQLite.
1825  * @param udata user data, pointer to DBC
1826  * @param count count of subsequenct calls
1827  * @result true or false
1828  */
1829 
1830 static int
busy_handler(void * udata,int count)1831 busy_handler(void *udata, int count)
1832 {
1833     DBC *d = (DBC *) udata;
1834     long t1;
1835     int ret = 0;
1836 #if !defined(_WIN32) && !defined(_WIN64)
1837     struct timeval tv;
1838 #ifdef HAVE_NANOSLEEP
1839     struct timespec ts;
1840 #endif
1841 #endif
1842 
1843     if (d->busyint) {
1844 	d->busyint = 0;
1845 	return ret;
1846     }
1847     if (d->timeout <= 0) {
1848 	return ret;
1849     }
1850     if (count <= 1) {
1851 #if defined(_WIN32) || defined(_WIN64)
1852 	d->t0 = GetTickCount();
1853 #else
1854 	gettimeofday(&tv, NULL);
1855 	d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1856 #endif
1857     }
1858 #if defined(_WIN32) || defined(_WIN64)
1859     t1 = GetTickCount();
1860 #else
1861     gettimeofday(&tv, NULL);
1862     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1863 #endif
1864     if (t1 - d->t0 > d->timeout) {
1865 	goto done;
1866     }
1867 #if defined(_WIN32) || defined(_WIN64)
1868     Sleep(10);
1869 #else
1870 #ifdef HAVE_NANOSLEEP
1871     ts.tv_sec = 0;
1872     ts.tv_nsec = 10000000;
1873     do {
1874 	ret = nanosleep(&ts, &ts);
1875 	if (ret < 0 && errno != EINTR) {
1876 	    ret = 0;
1877 	}
1878     } while (ret);
1879 #else
1880 #ifdef HAVE_USLEEP
1881     usleep(10000);
1882 #else
1883     tv.tv_sec = 0;
1884     tv.tv_usec = 10000;
1885     select(0, NULL, NULL, NULL, &tv);
1886 #endif
1887 #endif
1888 #endif
1889     ret = 1;
1890 done:
1891     return ret;
1892 }
1893 
1894 /**
1895  * Set SQLite options (PRAGMAs) given SQLite handle.
1896  * @param x SQLite database handle
1897  * @param d DBC pointer
1898  * @result SQLite error code
1899  *
1900  * SQLite < 3.3.x and not shortnames DSN option:
1901  * "full_column_names" is always turned on and "short_column_names"
1902  * is always turned off, to get the table names in column labels.
1903  */
1904 
1905 static int
setsqliteopts(sqlite3 * x,DBC * d)1906 setsqliteopts(sqlite3 *x, DBC *d)
1907 {
1908     int count = 0, step = 0, max, rc = SQLITE_ERROR;
1909 
1910 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
1911     max = d->longnames ? 3 : 1;
1912 #else
1913     max = 3;
1914 #endif
1915     if (d->shortnames) {
1916 	max = 3;
1917     }
1918     while (step < max) {
1919 	if (step < 1) {
1920 	    rc = sqlite3_exec(x, "PRAGMA empty_result_callbacks = on;",
1921 			      NULL, NULL, NULL);
1922 	    if (rc == SQLITE_OK) {
1923 		rc = sqlite3_exec(x, d->fksupport ?
1924 				  "PRAGMA foreign_keys = on;" :
1925 				  "PRAGMA foreign_keys = off;",
1926 				  NULL, NULL, NULL);
1927 	    }
1928 	} else if (step < 2) {
1929 	    rc = sqlite3_exec(x, d->shortnames ?
1930 			      "PRAGMA full_column_names = off;" :
1931 			      "PRAGMA full_column_names = on;",
1932 			      NULL, NULL, NULL);
1933 	} else if (step < 3) {
1934 	    rc = sqlite3_exec(x, d->shortnames ?
1935 			      "PRAGMA short_column_names = on;" :
1936 			      "PRAGMA short_column_names = off;",
1937 			      NULL, NULL, NULL);
1938 	}
1939 	if (rc != SQLITE_OK) {
1940 	    if (rc != SQLITE_BUSY ||
1941 		!busy_handler((void *) d, ++count)) {
1942 		return rc;
1943 	    }
1944 	    continue;
1945 	}
1946 	count = 0;
1947 	++step;
1948     }
1949     sqlite3_busy_handler(x, busy_handler, (void *) d);
1950     return SQLITE_OK;
1951 }
1952 
1953 /**
1954  * Free counted array of char pointers.
1955  * @param rowp pointer to char pointer array
1956  *
1957  * The -1-th element of the array holds the array size.
1958  * All non-NULL pointers of the array and then the array
1959  * itself are free'd.
1960  */
1961 
1962 static void
freerows(char ** rowp)1963 freerows(char **rowp)
1964 {
1965     PTRDIFF_T size, i;
1966 
1967     if (!rowp) {
1968 	return;
1969     }
1970     --rowp;
1971     size = (PTRDIFF_T) rowp[0];
1972     for (i = 1; i <= size; i++) {
1973 	freep(&rowp[i]);
1974     }
1975     freep(&rowp);
1976 }
1977 
1978 /**
1979  * Map SQL field type from string to ODBC integer type code.
1980  * @param typename field type string
1981  * @param nosign pointer to indicator for unsigned field or NULL
1982  * @param ov3 boolean, true for SQL_OV_ODBC3
1983  * @param nowchar boolean, for WINTERFACE don't use WCHAR
1984  * @param dobigint boolean, force SQL_BIGINT on INTEGER columns
1985  * @result SQL data type
1986  */
1987 
1988 static int
mapsqltype(const char * typename,int * nosign,int ov3,int nowchar,int dobigint)1989 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar,
1990 	   int dobigint)
1991 {
1992     char *p, *q;
1993     int testsign = 0, result;
1994 
1995 #ifdef WINTERFACE
1996     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
1997 #else
1998     result = SQL_VARCHAR;
1999 #endif
2000     if (!typename) {
2001 	return result;
2002     }
2003     q = p = xmalloc(strlen(typename) + 1);
2004     if (!p) {
2005 	return result;
2006     }
2007     strcpy(p, typename);
2008     while (*q) {
2009 	*q = TOLOWER(*q);
2010 	++q;
2011     }
2012     if (strncmp(p, "inter", 5) == 0) {
2013     } else if (strncmp(p, "int", 3) == 0 ||
2014 	strncmp(p, "mediumint", 9) == 0) {
2015 	testsign = 1;
2016 	result = SQL_INTEGER;
2017     } else if (strncmp(p, "numeric", 7) == 0) {
2018 	result = SQL_DOUBLE;
2019     } else if (strncmp(p, "tinyint", 7) == 0) {
2020 	testsign = 1;
2021 	result = SQL_TINYINT;
2022     } else if (strncmp(p, "smallint", 8) == 0) {
2023 	testsign = 1;
2024 	result = SQL_SMALLINT;
2025     } else if (strncmp(p, "float", 5) == 0) {
2026 	result = SQL_DOUBLE;
2027     } else if (strncmp(p, "double", 6) == 0 ||
2028 	strncmp(p, "real", 4) == 0) {
2029 	result = SQL_DOUBLE;
2030     } else if (strncmp(p, "timestamp", 9) == 0) {
2031 #ifdef SQL_TYPE_TIMESTAMP
2032 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
2033 #else
2034 	result = SQL_TIMESTAMP;
2035 #endif
2036     } else if (strncmp(p, "datetime", 8) == 0) {
2037 #ifdef SQL_TYPE_TIMESTAMP
2038 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
2039 #else
2040 	result = SQL_TIMESTAMP;
2041 #endif
2042     } else if (strncmp(p, "time", 4) == 0) {
2043 #ifdef SQL_TYPE_TIME
2044 	result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
2045 #else
2046 	result = SQL_TIME;
2047 #endif
2048     } else if (strncmp(p, "date", 4) == 0) {
2049 #ifdef SQL_TYPE_DATE
2050 	result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
2051 #else
2052 	result = SQL_DATE;
2053 #endif
2054 #ifdef SQL_LONGVARCHAR
2055     } else if (strncmp(p, "text", 4) == 0 ||
2056 	       strncmp(p, "memo", 4) == 0 ||
2057 	       strncmp(p, "longvarchar", 11) == 0) {
2058 #ifdef WINTERFACE
2059 	result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
2060 #else
2061 	result = SQL_LONGVARCHAR;
2062 #endif
2063 #ifdef WINTERFACE
2064     } else if (strncmp(p, "wtext", 5) == 0 ||
2065 	       strncmp(p, "wvarchar", 8) == 0 ||
2066 	       strncmp(p, "longwvarchar", 12) == 0) {
2067 	result = SQL_WLONGVARCHAR;
2068 #endif
2069 #endif
2070 #ifdef SQL_BIT
2071     } else if (strncmp(p, "bool", 4) == 0 ||
2072 	       strncmp(p, "bit", 3) == 0) {
2073 	result = SQL_BIT;
2074 #endif
2075 #ifdef SQL_BIGINT
2076     } else if (strncmp(p, "bigint", 6) == 0) {
2077 	testsign = 1;
2078 	result = SQL_BIGINT;
2079 #endif
2080     } else if (strncmp(p, "blob", 4) == 0) {
2081 	result = SQL_BINARY;
2082     } else if (strncmp(p, "varbinary", 9) == 0) {
2083 	result = SQL_VARBINARY;
2084     } else if (strncmp(p, "longvarbinary", 13) == 0) {
2085 	result = SQL_LONGVARBINARY;
2086     }
2087     if (nosign) {
2088 	if (testsign) {
2089 	    *nosign = strstr(p, "unsigned") != NULL;
2090 	} else {
2091 	    *nosign = 1;
2092 	}
2093     }
2094 #ifdef SQL_BIGINT
2095     if (dobigint && result == SQL_INTEGER) {
2096 	result = SQL_BIGINT;
2097     }
2098 #endif
2099     xfree(p);
2100     return result;
2101 }
2102 
2103 /**
2104  * Get maximum display size and number of digits after decimal point
2105  * from field type specification.
2106  * @param typename field type specification
2107  * @param sqltype target SQL data type
2108  * @param mp pointer to maximum display size or NULL
2109  * @param dp pointer to number of digits after decimal point or NULL
2110  */
2111 
2112 static void
getmd(const char * typename,int sqltype,int * mp,int * dp)2113 getmd(const char *typename, int sqltype, int *mp, int *dp)
2114 {
2115     int m = 0, d = 0;
2116 
2117     switch (sqltype) {
2118     case SQL_INTEGER:       m = 10; d = 9; break;
2119     case SQL_TINYINT:       m = 4; d = 3; break;
2120     case SQL_SMALLINT:      m = 6; d = 5; break;
2121     case SQL_FLOAT:         m = 25; d = 24; break;
2122     case SQL_DOUBLE:        m = 54; d = 53; break;
2123     case SQL_VARCHAR:       m = 255; d = 0; break;
2124 #ifdef WINTERFACE
2125 #ifdef SQL_WVARCHAR
2126     case SQL_WVARCHAR:      m = 255; d = 0; break;
2127 #endif
2128 #endif
2129 #ifdef SQL_TYPE_DATE
2130     case SQL_TYPE_DATE:
2131 #endif
2132     case SQL_DATE:          m = 10; d = 0; break;
2133 #ifdef SQL_TYPE_TIME
2134     case SQL_TYPE_TIME:
2135 #endif
2136     case SQL_TIME:          m = 8; d = 0; break;
2137 #ifdef SQL_TYPE_TIMESTAMP
2138     case SQL_TYPE_TIMESTAMP:
2139 #endif
2140     case SQL_TIMESTAMP:     m = 32; d = 3; break;
2141 #ifdef SQL_LONGVARCHAR
2142     case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
2143 #endif
2144 #ifdef WINTERFACE
2145 #ifdef SQL_WLONGVARCHAR
2146     case SQL_WLONGVARCHAR:  m = 65536; d = 0; break;
2147 #endif
2148 #endif
2149     case SQL_VARBINARY:     m = 255; d = 0; break;
2150     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
2151 #ifdef SQL_BIGINT
2152     case SQL_BIGINT:        m = 20; d = 19; break;
2153 #endif
2154 #ifdef SQL_BIT
2155     case SQL_BIT:	    m = 1; d = 1; break;
2156 #endif
2157     }
2158     if (m && typename) {
2159 	int mm, dd;
2160 
2161 	if (sscanf(typename, "%*[^(](%d)", &mm) == 1) {
2162 	    if (sqltype == SQL_TIMESTAMP) {
2163 		d = mm;
2164 	    }
2165 #ifdef SQL_TYPE_TIMESTAMP
2166 	    else if (sqltype == SQL_TYPE_TIMESTAMP) {
2167 		d = mm;
2168 	    }
2169 #endif
2170 	    else {
2171 		m = d = mm;
2172 	    }
2173 	} else if (sscanf(typename, "%*[^(](%d,%d)", &mm, &dd) == 2) {
2174 	    m = mm;
2175 	    d = dd;
2176 	}
2177     }
2178     if (mp) {
2179 	*mp = m;
2180     }
2181     if (dp) {
2182 	*dp = d;
2183     }
2184 }
2185 
2186 /**
2187  * Map SQL_C_DEFAULT to proper C type.
2188  * @param type input C type
2189  * @param stype input SQL type
2190  * @param nosign 0=signed, 0>unsigned, 0<undefined
2191  * @param nowchar when compiled with WINTERFACE don't use WCHAR
2192  * @result C type
2193  */
2194 
2195 static int
mapdeftype(int type,int stype,int nosign,int nowchar)2196 mapdeftype(int type, int stype, int nosign, int nowchar)
2197 {
2198     if (type == SQL_C_DEFAULT) {
2199 	switch (stype) {
2200 	case SQL_INTEGER:
2201 	    type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
2202 	    break;
2203 	case SQL_TINYINT:
2204 	    type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
2205 	    break;
2206 	case SQL_SMALLINT:
2207 	    type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
2208 	    break;
2209 	case SQL_FLOAT:
2210 	    type = SQL_C_FLOAT;
2211 	    break;
2212 	case SQL_DOUBLE:
2213 	    type = SQL_C_DOUBLE;
2214 	    break;
2215 	case SQL_TIMESTAMP:
2216 	    type = SQL_C_TIMESTAMP;
2217 	    break;
2218 	case SQL_TIME:
2219 	    type = SQL_C_TIME;
2220 	    break;
2221 	case SQL_DATE:
2222 	    type = SQL_C_DATE;
2223 	    break;
2224 #ifdef SQL_C_TYPE_TIMESTAMP
2225 	case SQL_TYPE_TIMESTAMP:
2226 	    type = SQL_C_TYPE_TIMESTAMP;
2227 	    break;
2228 #endif
2229 #ifdef SQL_C_TYPE_TIME
2230 	case SQL_TYPE_TIME:
2231 	    type = SQL_C_TYPE_TIME;
2232 	    break;
2233 #endif
2234 #ifdef SQL_C_TYPE_DATE
2235 	case SQL_TYPE_DATE:
2236 	    type = SQL_C_TYPE_DATE;
2237 	    break;
2238 #endif
2239 #ifdef WINTERFACE
2240 	case SQL_WVARCHAR:
2241 	case SQL_WCHAR:
2242 #ifdef SQL_WLONGVARCHAR
2243 	case SQL_WLONGVARCHAR:
2244 #endif
2245 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
2246 	    break;
2247 #endif
2248 	case SQL_BINARY:
2249 	case SQL_VARBINARY:
2250 	case SQL_LONGVARBINARY:
2251 	    type = SQL_C_BINARY;
2252 	    break;
2253 #ifdef SQL_BIT
2254 	case SQL_BIT:
2255 	    type = SQL_C_BIT;
2256 	    break;
2257 #endif
2258 #ifdef SQL_BIGINT
2259 	case SQL_BIGINT:
2260 	    type = SQL_C_CHAR;
2261 	    break;
2262 #endif
2263 	default:
2264 #ifdef WINTERFACE
2265 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
2266 #else
2267 	    type = SQL_C_CHAR;
2268 #endif
2269 	    break;
2270 	}
2271     }
2272     return type;
2273 }
2274 
2275 /**
2276  * Fixup query string with optional parameter markers.
2277  * @param sql original query string
2278  * @param sqlLen length of query string or SQL_NTS
2279  * @param nparam output number of parameters
2280  * @param isselect output indicator for SELECT statement
2281  * @param errmsg output error message
2282  * @result newly allocated string containing query string for SQLite or NULL
2283  */
2284 
2285 static char *
fixupsql(char * sql,int sqlLen,int * nparam,int * isselect,char ** errmsg)2286 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg)
2287 {
2288     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
2289     int np = 0, isddl = -1, size;
2290 
2291     *errmsg = NULL;
2292     if (sqlLen != SQL_NTS) {
2293 	qz = q = xmalloc(sqlLen + 1);
2294 	if (!qz) {
2295 	    return NULL;
2296 	}
2297 	memcpy(q, sql, sqlLen);
2298 	q[sqlLen] = '\0';
2299 	size = sqlLen * 4;
2300     } else {
2301 	size = strlen(sql) * 4;
2302     }
2303     size += sizeof (char *) - 1;
2304     size &= ~(sizeof (char *) - 1);
2305     p = xmalloc(size);
2306     if (!p) {
2307 errout:
2308 	freep(&qz);
2309 	return NULL;
2310     }
2311     memset(p, 0, size);
2312     out = p;
2313     while (*q) {
2314 	switch (*q) {
2315 	case '\'':
2316 	case '\"':
2317 	    if (q == inq) {
2318 		inq = NULL;
2319 	    } else if (!inq) {
2320 		inq = q + 1;
2321 
2322 		while (*inq) {
2323 		    if (*inq == *q) {
2324 			if (inq[1] == *q) {
2325 			    inq++;
2326 			} else {
2327 			    break;
2328 			}
2329 		    }
2330 		    inq++;
2331 		}
2332 	    }
2333 	    *p++ = *q;
2334 	    break;
2335 	case '?':
2336 	    *p++ = *q;
2337 	    if (!inq) {
2338 		np++;
2339 	    }
2340 	    break;
2341 	case ';':
2342 	    if (!inq) {
2343 		if (isddl < 0) {
2344 		    char *qq = out;
2345 
2346 		    while (*qq && ISSPACE(*qq)) {
2347 			++qq;
2348 		    }
2349 		    if (*qq && *qq != ';') {
2350 			size = strlen(qq);
2351 			if ((size >= 5) &&
2352 			    (strncasecmp(qq, "create", 5) == 0)) {
2353 			    isddl = 1;
2354 			} else if ((size >= 4) &&
2355 				   (strncasecmp(qq, "drop", 4) == 0)) {
2356 			    isddl = 1;
2357 			} else {
2358 			    isddl = 0;
2359 			}
2360 		    }
2361 		}
2362 		if (isddl == 0) {
2363 		    char *qq = q;
2364 
2365 		    do {
2366 			++qq;
2367 		    } while (*qq && ISSPACE(*qq));
2368 		    if (*qq && *qq != ';') {
2369 			freep(&out);
2370 			*errmsg = "only one SQL statement allowed";
2371 			goto errout;
2372 		    }
2373 		}
2374 	    }
2375 	    *p++ = *q;
2376 	    break;
2377 	case '{':
2378 	    /* deal with {d 'YYYY-MM-DD'}, {t ...}, and {ts ...} */
2379 	    if (!inq) {
2380 		char *end = q + 1;
2381 
2382 		while (*end && *end != '}') {
2383 		    ++end;
2384 		}
2385 		if (*end == '}') {
2386 		    char *start = q + 1;
2387 		    char *end2 = end - 1;
2388 
2389 		    while (start < end2 && *start != '\'') {
2390 			++start;
2391 		    }
2392 		    while (end2 > start && *end2 != '\'') {
2393 			--end2;
2394 		    }
2395 		    if (*start == '\'' && *end2 == '\'') {
2396 			while (start <= end2) {
2397 			    *p++ = *start;
2398 			    ++start;
2399 			}
2400 			q = end;
2401 			break;
2402 		    }
2403 		}
2404 	    }
2405 	    /* FALL THROUGH */
2406 	default:
2407 	    *p++ = *q;
2408 	}
2409 	++q;
2410     }
2411     freep(&qz);
2412     *p = '\0';
2413     if (nparam) {
2414 	*nparam = np;
2415     }
2416     if (isselect) {
2417 	if (isddl > 0) {
2418 	    *isselect = 0;
2419 	} else {
2420 	    int incom = 0;
2421 
2422 	    p = out;
2423 	    while (*p) {
2424 		switch (*p) {
2425 		case '-':
2426 		    if (!incom && p[1] == '-') {
2427 			incom = -1;
2428 		    }
2429 		    break;
2430 		case '\n':
2431 		    if (incom < 0) {
2432 			incom = 0;
2433 		    }
2434 		    break;
2435 		case '/':
2436 		    if (incom > 0 && p[-1] == '*') {
2437 			incom = 0;
2438 			p++;
2439 			continue;
2440 		    } else if (!incom && p[1] == '*') {
2441 			incom = 1;
2442 		    }
2443 		    break;
2444 		}
2445 		if (!incom && !ISSPACE(*p)) {
2446 		    break;
2447 		}
2448 		p++;
2449 	    }
2450 	    size = strlen(p);
2451 	    *isselect = (size >= 6) && (strncasecmp(p, "select", 6) == 0);
2452 	}
2453     }
2454     return out;
2455 }
2456 
2457 /**
2458  * Find column given name in string array.
2459  * @param cols string array
2460  * @param ncols number of strings
2461  * @param name column name
2462  * @result >= 0 on success, -1 on error
2463  */
2464 
2465 static int
findcol(char ** cols,int ncols,char * name)2466 findcol(char **cols, int ncols, char *name)
2467 {
2468     int i;
2469 
2470     if (cols) {
2471 	for (i = 0; i < ncols; i++) {
2472 	    if (strcmp(cols[i], name) == 0) {
2473 		return i;
2474 	    }
2475 	}
2476     }
2477     return -1;
2478 }
2479 
2480 /**
2481  * Fixup column information for a running statement.
2482  * @param s statement to get fresh column information
2483  * @param d DBC pointer
2484  *
2485  * The column labels get the table names stripped
2486  * when there's more than one column and all table
2487  * names are identical.
2488  *
2489  * The "dyncols" field of STMT is filled with column
2490  * information obtained by SQLite "PRAGMA table_info"
2491  * for each column whose table name is known. If the
2492  * types are already present as with SQLite 2.5.7
2493  * this information is used instead.
2494  */
2495 
2496 static void
fixupdyncols(STMT * s,DBC * d)2497 fixupdyncols(STMT *s, DBC *d)
2498 {
2499     int i;
2500 #if !defined(HAVE_SQLITE3TABLECOLUMNMETADATA) || !(HAVE_SQLITE3TABLECOLUMNMETADATA)
2501     int k, pk, nn, t, r, nrows, ncols;
2502     char **rowp, *flagp, flags[128];
2503 #endif
2504 
2505     if (!s->dyncols) {
2506 	return;
2507     }
2508     /* fixup labels */
2509     if (!s->longnames) {
2510 	if (s->dcols > 1) {
2511 	    char *table = s->dyncols[0].table;
2512 
2513 	    for (i = 1; table[0] && i < s->dcols; i++) {
2514 		if (strcmp(s->dyncols[i].table, table)) {
2515 		    break;
2516 		}
2517 	    }
2518 	    if (i >= s->dcols) {
2519 		for (i = 0; i < s->dcols; i++) {
2520 		    s->dyncols[i].label = s->dyncols[i].column;
2521 		}
2522 	    }
2523 	} else if (s->dcols == 1) {
2524 	    s->dyncols[0].label = s->dyncols[0].column;
2525 	}
2526     }
2527     for (i = 0; i < s->dcols; i++) {
2528 	s->dyncols[i].type =
2529 	    mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3,
2530 		       s->nowchar[0] || s->nowchar[1], s->dobigint);
2531 	getmd(s->dyncols[i].typename, s->dyncols[i].type,
2532 	      &s->dyncols[i].size, &s->dyncols[i].prec);
2533 #ifdef SQL_LONGVARCHAR
2534 	if (s->dyncols[i].type == SQL_VARCHAR &&
2535 	    s->dyncols[i].size > 255) {
2536 	    s->dyncols[i].type = SQL_LONGVARCHAR;
2537 	}
2538 #endif
2539 #ifdef WINTERFACE
2540 #ifdef SQL_WLONGVARCHAR
2541 	if (s->dyncols[i].type == SQL_WVARCHAR &&
2542 	    s->dyncols[i].size > 255) {
2543 	    s->dyncols[i].type = SQL_WLONGVARCHAR;
2544 	}
2545 #endif
2546 #endif
2547 	if (s->dyncols[i].type == SQL_VARBINARY &&
2548 	    s->dyncols[i].size > 255) {
2549 	    s->dyncols[i].type = SQL_LONGVARBINARY;
2550 	}
2551     }
2552 #if !defined(HAVE_SQLITE3TABLECOLUMNMETADATA) || !(HAVE_SQLITE3TABLECOLUMNMETADATA)
2553     if (s->dcols > array_size(flags)) {
2554 	flagp = xmalloc(sizeof (flags[0]) * s->dcols);
2555 	if (flagp == NULL) {
2556 	    return;
2557 	}
2558     } else {
2559 	flagp = flags;
2560     }
2561     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
2562     for (i = 0; i < s->dcols; i++) {
2563 	s->dyncols[i].autoinc = SQL_FALSE;
2564 	s->dyncols[i].notnull = SQL_NULLABLE;
2565     }
2566     for (i = 0; i < s->dcols; i++) {
2567 	int ret, lastpk = -1, autoinccount = 0;
2568 	char *sql;
2569 
2570 	if (!s->dyncols[i].table[0]) {
2571 	    continue;
2572 	}
2573 	if (flagp[i]) {
2574 	    continue;
2575 	}
2576 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", s->dyncols[i].table);
2577 	if (!sql) {
2578 	    continue;
2579 	}
2580 	dbtraceapi(d, "sqlite3_get_table", sql);
2581 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, NULL);
2582 	sqlite3_free(sql);
2583 	if (ret != SQLITE_OK) {
2584 	    continue;
2585 	}
2586 	k = findcol(rowp, ncols, "name");
2587 	t = findcol(rowp, ncols, "type");
2588 	pk = findcol(rowp, ncols, "pk");
2589 	nn = findcol(rowp, ncols, "notnull");
2590 	if (k < 0 || t < 0) {
2591 	    goto freet;
2592 	}
2593 	for (r = 1; r <= nrows; r++) {
2594 	    int m;
2595 
2596 	    for (m = i; m < s->dcols; m++) {
2597 		char *colname = s->dyncols[m].column;
2598 
2599 		if (s->longnames) {
2600 		    char *dotp = strchr(colname, '.');
2601 
2602 		    if (dotp) {
2603 			colname = dotp + 1;
2604 		    }
2605 		}
2606 		if (!flagp[m] &&
2607 		    strcmp(colname, rowp[r * ncols + k]) == 0 &&
2608 		    strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
2609 		    char *typename = rowp[r * ncols + t];
2610 
2611 		    flagp[m] = 1;
2612 		    freep(&s->dyncols[m].typename);
2613 		    s->dyncols[m].typename = xstrdup(typename);
2614 		    s->dyncols[m].type =
2615 			mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
2616 				   s->nowchar[0] || s->nowchar[1],
2617 				   s->dobigint);
2618 		    getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
2619 			  &s->dyncols[m].prec);
2620 #ifdef SQL_LONGVARCHAR
2621 		    if (s->dyncols[m].type == SQL_VARCHAR &&
2622 			s->dyncols[m].size > 255) {
2623 			s->dyncols[m].type = SQL_LONGVARCHAR;
2624 		    }
2625 #endif
2626 #ifdef WINTERFACE
2627 #ifdef SQL_WLONGVARCHAR
2628 		    if (s->dyncols[i].type == SQL_WVARCHAR &&
2629 			s->dyncols[i].size > 255) {
2630 			s->dyncols[i].type = SQL_WLONGVARCHAR;
2631 		    }
2632 #endif
2633 #endif
2634 		    if (s->dyncols[i].type == SQL_VARBINARY &&
2635 			s->dyncols[i].size > 255) {
2636 			s->dyncols[i].type = SQL_LONGVARBINARY;
2637 		    }
2638 		    if (pk >= 0	&& strcmp(rowp[r * ncols + pk], "1") == 0) {
2639 			if (++autoinccount > 1) {
2640 			    if (lastpk >= 0) {
2641 				s->dyncols[lastpk].autoinc = SQL_FALSE;
2642 				lastpk = -1;
2643 			    }
2644 			} else {
2645 			    lastpk = m;
2646 			    if (strlen(typename) == 7 &&
2647 				strncasecmp(typename, "integer", 7) == 0) {
2648 				s->dyncols[m].autoinc = SQL_TRUE;
2649 			    }
2650 			}
2651 		    }
2652 		    if (nn >= 0 && rowp[r * ncols + nn][0] != '0') {
2653 			s->dyncols[m].notnull = SQL_NO_NULLS;
2654 		    }
2655 		}
2656 	    }
2657 	}
2658 freet:
2659 	sqlite3_free_table(rowp);
2660     }
2661     if (flagp != flags) {
2662 	freep(&flagp);
2663     }
2664 #endif
2665 }
2666 
2667 /**
2668  * Return number of month days.
2669  * @param year
2670  * @param month 1..12
2671  * @result number of month days or 0
2672  */
2673 
2674 static int
getmdays(int year,int month)2675 getmdays(int year, int month)
2676 {
2677     static const int mdays[] = {
2678 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2679     };
2680     int mday;
2681 
2682     if (month < 1) {
2683 	return 0;
2684     }
2685     mday = mdays[(month - 1) % 12];
2686     if (mday == 28 && year % 4 == 0 &&
2687 	(!(year % 100 == 0) || year % 400 == 0)) {
2688 	mday++;
2689     }
2690     return mday;
2691 }
2692 
2693 /**
2694  * Convert string to ODBC DATE_STRUCT.
2695  * @param str string to be converted
2696  * @param ds output DATE_STRUCT
2697  * @result 0 on success, -1 on error
2698  *
2699  * Strings of the format 'YYYYMMDD' or 'YYYY-MM-DD' or
2700  * 'YYYY/MM/DD' or 'MM/DD/YYYY' are converted to a
2701  * DATE_STRUCT.
2702  */
2703 
2704 static int
str2date(char * str,DATE_STRUCT * ds)2705 str2date(char *str, DATE_STRUCT *ds)
2706 {
2707     int i, err = 0;
2708     char *p, *q, sepc = '\0';
2709 
2710     ds->year = ds->month = ds->day = 0;
2711     p = str;
2712     while (*p && !ISDIGIT(*p)) {
2713 	++p;
2714     }
2715     q = p;
2716     i = 0;
2717     while (*q && !ISDIGIT(*q)) {
2718 	++i;
2719 	++q;
2720     }
2721     if (i >= 8) {
2722 	char buf[8];
2723 
2724 	strncpy(buf, p + 0, 4); buf[4] = '\0';
2725 	ds->year = strtol(buf, NULL, 10);
2726 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2727 	ds->month = strtol(buf, NULL, 10);
2728 	strncpy(buf, p + 6, 2); buf[2] = '\0';
2729 	ds->day = strtol(buf, NULL, 10);
2730 	goto done;
2731     }
2732     i = 0;
2733     while (i < 3) {
2734 	int n;
2735 
2736 	q = NULL;
2737 	n = strtol(p, &q, 10);
2738 	if (!q || q == p) {
2739 	    if (*q == '\0') {
2740 		if (i == 0) {
2741 		    err = 1;
2742 		}
2743 		goto done;
2744 	    }
2745 	}
2746 	if (!sepc) {
2747 	    sepc = *q;
2748 	}
2749 	if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
2750 	    switch (i) {
2751 	    case 0: ds->year = n; break;
2752 	    case 1: ds->month = n; break;
2753 	    case 2: ds->day = n; break;
2754 	    }
2755 	    ++i;
2756 	    if (*q) {
2757 		++q;
2758 	    }
2759 	} else {
2760 	    i = 0;
2761 	    while (*q && !ISDIGIT(*q)) {
2762 		++q;
2763 	    }
2764 	}
2765 	p = q;
2766     }
2767 done:
2768     /* final check for overflow */
2769     if (err ||
2770 	ds->month < 1 || ds->month > 12 ||
2771 	ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
2772 	if (sepc == '/') {
2773 	    /* Try MM/DD/YYYY format */
2774 	    int t[3];
2775 
2776 	    t[0] = ds->year;
2777 	    t[1] = ds->month;
2778 	    t[2] = ds->day;
2779 	    ds->year = t[2];
2780 	    ds->day = t[1];
2781 	    ds->month = t[0];
2782 	    if (ds->month >= 1 && ds->month <= 12 &&
2783 		(ds->day >= 1 || ds->day <= getmdays(ds->year, ds->month))) {
2784 		return 0;
2785 	    }
2786 	}
2787 	return -1;
2788     }
2789     return 0;
2790 }
2791 
2792 /**
2793  * Convert string to ODBC TIME_STRUCT.
2794  * @param str string to be converted
2795  * @param ts output TIME_STRUCT
2796  * @result 0 on success, -1 on error
2797  *
2798  * Strings of the format 'HHMMSS' or 'HH:MM:SS'
2799  * are converted to a TIME_STRUCT.
2800  */
2801 
2802 static int
str2time(char * str,TIME_STRUCT * ts)2803 str2time(char *str, TIME_STRUCT *ts)
2804 {
2805     int i, err = 0, ampm = -1;
2806     char *p, *q;
2807 
2808     ts->hour = ts->minute = ts->second = 0;
2809     p = str;
2810     while (*p && !ISDIGIT(*p)) {
2811 	++p;
2812     }
2813     q = p;
2814     i = 0;
2815     while (*q && ISDIGIT(*q)) {
2816 	++i;
2817 	++q;
2818     }
2819     if (i >= 6) {
2820 	char buf[4];
2821 
2822 	strncpy(buf, p + 0, 2); buf[2] = '\0';
2823 	ts->hour = strtol(buf, NULL, 10);
2824 	strncpy(buf, p + 2, 2); buf[2] = '\0';
2825 	ts->minute = strtol(buf, NULL, 10);
2826 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2827 	ts->second = strtol(buf, NULL, 10);
2828 	goto done;
2829     }
2830     i = 0;
2831     while (i < 3) {
2832 	int n;
2833 
2834 	q = NULL;
2835 	n = strtol(p, &q, 10);
2836 	if (!q || q == p) {
2837 	    if (*q == '\0') {
2838 		if (i == 0) {
2839 		    err = 1;
2840 		}
2841 		goto done;
2842 	    }
2843 	}
2844 	if (*q == ':' || *q == '\0' || i == 2) {
2845 	    switch (i) {
2846 	    case 0: ts->hour = n; break;
2847 	    case 1: ts->minute = n; break;
2848 	    case 2: ts->second = n; break;
2849 	    }
2850 	    ++i;
2851 	    if (*q) {
2852 		++q;
2853 	    }
2854 	} else {
2855 	    i = 0;
2856 	    while (*q && !ISDIGIT(*q)) {
2857 		++q;
2858 	    }
2859 	}
2860 	p = q;
2861     }
2862     if (!err) {
2863 	while (*p) {
2864 	    if ((p[0] == 'p' || p[0] == 'P') &&
2865 		(p[1] == 'm' || p[1] == 'M')) {
2866 		ampm = 1;
2867 	    } else if ((p[0] == 'a' || p[0] == 'A') &&
2868 		(p[1] == 'm' || p[1] == 'M')) {
2869 		ampm = 0;
2870 	    }
2871 	    ++p;
2872 	}
2873 	if (ampm > 0) {
2874 	    if (ts->hour < 12) {
2875 		ts->hour += 12;
2876 	    }
2877 	} else if (ampm == 0) {
2878 	    if (ts->hour == 12) {
2879 		ts->hour = 0;
2880 	    }
2881 	}
2882     }
2883 done:
2884     /* final check for overflow */
2885     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
2886 	return -1;
2887     }
2888     return 0;
2889 }
2890 
2891 /**
2892  * Convert string to ODBC TIMESTAMP_STRUCT.
2893  * @param str string to be converted
2894  * @param tss output TIMESTAMP_STRUCT
2895  * @result 0 on success, -1 on error
2896  *
2897  * Strings of the format 'YYYYMMDDhhmmssff' or 'YYYY-MM-DD hh:mm:ss ff'
2898  * or 'YYYY/MM/DD hh:mm:ss ff' or 'hh:mm:ss ff YYYY-MM-DD' are
2899  * converted to a TIMESTAMP_STRUCT. The ISO8601 formats
2900  *    YYYY-MM-DDThh:mm:ss[.f]Z
2901  *    YYYY-MM-DDThh:mm:ss[.f]shh:mm
2902  * are also supported. In case a time zone field is present,
2903  * the resulting TIMESTAMP_STRUCT is expressed in UTC.
2904  */
2905 
2906 static int
str2timestamp(char * str,TIMESTAMP_STRUCT * tss)2907 str2timestamp(char *str, TIMESTAMP_STRUCT *tss)
2908 {
2909     int i, m, n, err = 0, ampm = -1;
2910     char *p, *q, in = '\0', sepc = '\0';
2911 
2912     tss->year = tss->month = tss->day = 0;
2913     tss->hour = tss->minute = tss->second = 0;
2914     tss->fraction = 0;
2915     p = str;
2916     while (*p && !ISDIGIT(*p)) {
2917 	++p;
2918     }
2919     q = p;
2920     i = 0;
2921     while (*q && ISDIGIT(*q)) {
2922 	++i;
2923 	++q;
2924     }
2925     if (i >= 14) {
2926 	char buf[16];
2927 
2928 	strncpy(buf, p + 0, 4); buf[4] = '\0';
2929 	tss->year = strtol(buf, NULL, 10);
2930 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2931 	tss->month = strtol(buf, NULL, 10);
2932 	strncpy(buf, p + 6, 2); buf[2] = '\0';
2933 	tss->day = strtol(buf, NULL, 10);
2934 	strncpy(buf, p + 8, 2); buf[2] = '\0';
2935 	tss->hour = strtol(buf, NULL, 10);
2936 	strncpy(buf, p + 10, 2); buf[2] = '\0';
2937 	tss->minute = strtol(buf, NULL, 10);
2938 	strncpy(buf, p + 12, 2); buf[2] = '\0';
2939 	tss->second = strtol(buf, NULL, 10);
2940 	if (i > 14) {
2941 	    m = i - 14;
2942 	    strncpy(buf, p + 14, m);
2943 	    while (m < 9) {
2944 		buf[m] = '0';
2945 		++m;
2946 	    }
2947 	    buf[m] = '\0';
2948 	    tss->fraction = strtol(buf, NULL, 0);
2949 	}
2950 	m = 7;
2951 	goto done;
2952     }
2953     m = i = 0;
2954     while ((m & 7) != 7) {
2955 	q = NULL;
2956 	n = strtol(p, &q, 10);
2957 	if (!q || q == p) {
2958 	    if (*q == '\0') {
2959 		if (m < 1) {
2960 		    err = 1;
2961 		}
2962 		goto done;
2963 	    }
2964 	}
2965 	if (in == '\0') {
2966 	    switch (*q) {
2967 	    case '-':
2968 	    case '/':
2969 		if ((m & 1) == 0) {
2970 		    in = *q;
2971 		    i = 0;
2972 		}
2973 		break;
2974 	    case ':':
2975 		if ((m & 2) == 0) {
2976 		    in = *q;
2977 		    i = 0;
2978 		}
2979 		break;
2980 	    case ' ':
2981 	    case '.':
2982 		break;
2983 	    default:
2984 		in = '\0';
2985 		i = 0;
2986 		break;
2987 	    }
2988 	}
2989 	switch (in) {
2990 	case '-':
2991 	case '/':
2992 	    if (!sepc) {
2993 		sepc = in;
2994 	    }
2995 	    switch (i) {
2996 	    case 0: tss->year = n; break;
2997 	    case 1: tss->month = n; break;
2998 	    case 2: tss->day = n; break;
2999 	    }
3000 	    if (++i >= 3) {
3001 		i = 0;
3002 		m |= 1;
3003 		if (!(m & 2)) {
3004 		    m |= 8;
3005 		}
3006 		goto skip;
3007 	    } else {
3008 		++q;
3009 	    }
3010 	    break;
3011 	case ':':
3012 	    switch (i) {
3013 	    case 0: tss->hour = n; break;
3014 	    case 1: tss->minute = n; break;
3015 	    case 2: tss->second = n; break;
3016 	    }
3017 	    if (++i >= 3) {
3018 		i = 0;
3019 		m |= 2;
3020 		if (*q == '.') {
3021 		    in = '.';
3022 		    goto skip2;
3023 		}
3024 		if (*q == ' ') {
3025 		    if ((m & 1) == 0) {
3026 			char *e = NULL;
3027 			int dummy;
3028 
3029 			dummy = strtol(q + 1, &e, 10);
3030 			if (e && *e == '-') {
3031 			    goto skip;
3032 			}
3033 		    }
3034 		    in = '.';
3035 		    goto skip2;
3036 		}
3037 		goto skip;
3038 	    } else {
3039 		++q;
3040 	    }
3041 	    break;
3042 	case '.':
3043 	    if (++i >= 1) {
3044 		int ndig = q - p;
3045 
3046 		if (p[0] == '+' || p[0] == '-') {
3047 		    ndig--;
3048 		}
3049 		while (ndig < 9) {
3050 		    n = n * 10;
3051 		    ++ndig;
3052 		}
3053 		tss->fraction = n;
3054 		m |= 4;
3055 		i = 0;
3056 	    }
3057 	default:
3058 	skip:
3059 	    in = '\0';
3060 	skip2:
3061 	    while (*q && !ISDIGIT(*q)) {
3062 		if ((q[0] == 'a' || q[0] == 'A') &&
3063 		    (q[1] == 'm' || q[1] == 'M')) {
3064 		    ampm = 0;
3065 		    ++q;
3066 		} else if ((q[0] == 'p' || q[0] == 'P') &&
3067 			   (q[1] == 'm' || q[1] == 'M')) {
3068 		    ampm = 1;
3069 		    ++q;
3070 		}
3071 		++q;
3072 	    }
3073 	}
3074 	p = q;
3075     }
3076     if ((m & 7) > 1 && (m & 8)) {
3077 	/* ISO8601 timezone */
3078 	if (p > str && ISDIGIT(*p)) {
3079 	    int nn, sign;
3080 
3081 	    q = p - 1;
3082 	    if (*q != '+' && *q != '-') {
3083 		goto done;
3084 	    }
3085 	    sign = (*q == '+') ? -1 : 1;
3086 	    q = NULL;
3087 	    n = strtol(p, &q, 10);
3088 	    if (!q || *q++ != ':' || !ISDIGIT(*q)) {
3089 		goto done;
3090 	    }
3091 	    p = q;
3092 	    q = NULL;
3093 	    nn = strtol(p, &q, 0);
3094 	    tss->minute += nn * sign;
3095 	    if ((SQLSMALLINT) tss->minute < 0) {
3096 		tss->hour -= 1;
3097 		tss->minute += 60;
3098 	    } else if (tss->minute >= 60) {
3099 		tss->hour += 1;
3100 		tss->minute -= 60;
3101 	    }
3102 	    tss->hour += n * sign;
3103 	    if ((SQLSMALLINT) tss->hour < 0) {
3104 		tss->day -= 1;
3105 		tss->hour += 24;
3106 	    } else if (tss->hour >= 24) {
3107 		tss->day += 1;
3108 		tss->hour -= 24;
3109 	    }
3110 	    if ((short) tss->day < 1 || tss->day >= 28) {
3111 		int mday, pday, pmon;
3112 
3113 		mday = getmdays(tss->year, tss->month);
3114 		pmon = tss->month - 1;
3115 		if (pmon < 1) {
3116 		    pmon = 12;
3117 		}
3118 		pday = getmdays(tss->year, pmon);
3119 		if ((SQLSMALLINT) tss->day < 1) {
3120 		    tss->month -= 1;
3121 		    tss->day = pday;
3122 		} else if (tss->day > mday) {
3123 		    tss->month += 1;
3124 		    tss->day = 1;
3125 		}
3126 		if ((SQLSMALLINT) tss->month < 1) {
3127 		    tss->year -= 1;
3128 		    tss->month = 12;
3129 		} else if (tss->month > 12) {
3130 		    tss->year += 1;
3131 		    tss->month = 1;
3132 		}
3133 	    }
3134 	}
3135     }
3136 done:
3137     if ((m & 1) &&
3138 	(tss->month < 1 || tss->month > 12 ||
3139 	 tss->day < 1 || tss->day > getmdays(tss->year, tss->month))) {
3140 	if (sepc == '/') {
3141 	    /* Try MM/DD/YYYY format */
3142 	    int t[3];
3143 
3144 	    t[0] = tss->year;
3145 	    t[1] = tss->month;
3146 	    t[2] = tss->day;
3147 	    tss->year = t[2];
3148 	    tss->day = t[1];
3149 	    tss->month = t[0];
3150 	}
3151     }
3152     /* Replace missing year/month/day with current date */
3153     if (!err && (m & 1) == 0) {
3154 #ifdef _WIN32
3155 	SYSTEMTIME t;
3156 
3157 	GetLocalTime(&t);
3158 	tss->year = t.wYear;
3159 	tss->month = t.wMonth;
3160 	tss->day = t.wDay;
3161 #else
3162 	struct timeval tv;
3163 	struct tm tm;
3164 
3165 	gettimeofday(&tv, NULL);
3166 	tm = *localtime(&tv.tv_sec);
3167 	tss->year = tm.tm_year + 1900;
3168 	tss->month = tm.tm_mon + 1;
3169 	tss->day = tm.tm_mday;
3170 #endif
3171     }
3172     /* Normalize fraction */
3173     if (tss->fraction < 0) {
3174 	tss->fraction = 0;
3175     }
3176     /* Final check for overflow */
3177     if (err ||
3178 	tss->month < 1 || tss->month > 12 ||
3179 	tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
3180 	tss->hour > 23 || tss->minute > 59 || tss->second > 59) {
3181 	return -1;
3182     }
3183     if ((m & 7) > 1) {
3184 	if (ampm > 0) {
3185 	    if (tss->hour < 12) {
3186 		tss->hour += 12;
3187 	    }
3188 	} else if (ampm == 0) {
3189 	    if (tss->hour == 12) {
3190 		tss->hour = 0;
3191 	    }
3192 	}
3193     }
3194     return ((m & 7) < 1) ? -1 : 0;
3195 }
3196 
3197 /**
3198  * Get boolean flag from string.
3199  * @param string string to be inspected
3200  * @result true or false
3201  */
3202 
3203 static int
getbool(char * string)3204 getbool(char *string)
3205 {
3206     if (string) {
3207 	return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
3208     }
3209     return 0;
3210 }
3211 
3212 /**
3213  * SQLite function to import a BLOB from a file
3214  * @param ctx function context
3215  * @param nargs number arguments
3216  * @param args arguments
3217  */
3218 
3219 static void
blob_import(sqlite3_context * ctx,int nargs,sqlite3_value ** args)3220 blob_import(sqlite3_context *ctx, int nargs, sqlite3_value **args)
3221 {
3222 #if 0
3223     DBC *d = (DBC *) sqlite3_user_data(ctx);
3224 #endif
3225     char *filename = 0;
3226 
3227     if (nargs > 0) {
3228 	if (sqlite3_value_type(args[0]) != SQLITE_NULL) {
3229 	    filename = (char *) sqlite3_value_text(args[0]);
3230 	}
3231     }
3232     if (filename) {
3233 #ifdef _WIN32
3234 	char *wname = utf_to_wmb(filename, -1);
3235 	FILE *f;
3236 #else
3237 	FILE *f = fopen(filename, "r");
3238 #endif
3239 	char *p;
3240 	long n, nn;
3241 
3242 #ifdef _WIN32
3243 	if (wname) {
3244 	    f = fopen(wname, "rb");
3245 	} else {
3246 	    sqlite3_result_error(ctx, "out of memory", -1);
3247 	    return;
3248 	}
3249 	uc_free(wname);
3250 #endif
3251 	if (f) {
3252 	    if (fseek(f, 0, SEEK_END) == 0) {
3253 		n = ftell(f);
3254 		if (fseek(f, 0, SEEK_SET) == 0) {
3255 		    p = sqlite3_malloc(n);
3256 		    if (p) {
3257 			nn = fread(p, 1, n, f);
3258 			if (nn != n) {
3259 			    sqlite3_result_error(ctx, "read error", -1);
3260 			    sqlite3_free(p);
3261 			} else {
3262 			    sqlite3_result_blob(ctx, p, n, sqlite3_free);
3263 			}
3264 		    } else {
3265 			sqlite3_result_error(ctx, "out of memory", -1);
3266 		    }
3267 		} else {
3268 		    sqlite3_result_error(ctx, "seek error", -1);
3269 		}
3270 	    } else {
3271 		sqlite3_result_error(ctx, "seek error", -1);
3272 	    }
3273 	    fclose(f);
3274 	} else {
3275 	    sqlite3_result_error(ctx, "cannot open file", -1);
3276 	}
3277     } else {
3278 	sqlite3_result_error(ctx, "no filename given", -1);
3279     }
3280 }
3281 
3282 /**
3283  * SQLite function to export a BLOB to a file
3284  * @param ctx function context
3285  * @param nargs number arguments
3286  * @param args arguments
3287  */
3288 
3289 static void
blob_export(sqlite3_context * ctx,int nargs,sqlite3_value ** args)3290 blob_export(sqlite3_context *ctx, int nargs, sqlite3_value **args)
3291 {
3292 #if 0
3293     DBC *d = (DBC *) sqlite3_user_data(ctx);
3294 #endif
3295     char *filename = 0;
3296     char *p = 0;
3297     int n = 0;
3298 
3299     if (nargs > 0) {
3300 	p = (char *) sqlite3_value_blob(args[0]);
3301 	n = sqlite3_value_bytes(args[0]);
3302     }
3303     if (nargs > 1) {
3304 	if (sqlite3_value_type(args[1]) != SQLITE_NULL) {
3305 	    filename = (char *) sqlite3_value_text(args[1]);
3306 	}
3307     }
3308     if (p) {
3309 	if (filename) {
3310 #ifdef _WIN32
3311 	    char *wname = utf_to_wmb(filename, -1);
3312 	    FILE *f;
3313 #else
3314 	    FILE *f = fopen(filename, "w");
3315 #endif
3316 	    int nn;
3317 
3318 #ifdef _WIN32
3319 	    if (wname) {
3320 		f = fopen(wname, "wb");
3321 	    } else {
3322 		sqlite3_result_error(ctx, "out of memory", -1);
3323 		return;
3324 	    }
3325 	    uc_free(wname);
3326 #endif
3327 	    if (f) {
3328 		nn = fwrite(p, 1, n, f);
3329 		if (nn != n) {
3330 		    sqlite3_result_error(ctx, "write error", -1);
3331 		} else {
3332 		    sqlite3_result_int(ctx, nn);
3333 		}
3334 	    } else {
3335 		sqlite3_result_error(ctx, "cannot open file", -1);
3336 	    }
3337 	} else {
3338 	    sqlite3_result_error(ctx, "no filename given", -1);
3339 	}
3340     } else {
3341 	sqlite3_result_null(ctx);
3342     }
3343 }
3344 
3345 /**
3346  * SQLite trace or profile callback
3347  * @param arg DBC pointer
3348  * @param msg log message, SQL text
3349  * @param et  elapsed time
3350  */
3351 
3352 static void
3353 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
dbtrace(void * arg,const char * msg,sqlite_uint64 et)3354 dbtrace(void *arg, const char *msg, sqlite_uint64 et)
3355 #else
3356 dbtrace(void *arg, const char *msg)
3357 #endif
3358 {
3359     DBC *d = (DBC *) arg;
3360 
3361     if (msg && d->trace) {
3362 	int len = strlen(msg);
3363 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
3364 	unsigned long s, f;
3365 #endif
3366 
3367 	if (len > 0) {
3368 	    char *end = "\n";
3369 
3370 	    if (msg[len - 1] != ';') {
3371 		end = ";\n";
3372 	    }
3373 	    fprintf(d->trace, "%s%s", msg, end);
3374 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
3375 	    s = et / 1000000000LL;
3376 	    f = et % 1000000000LL;
3377 	    fprintf(d->trace, "-- took %lu.%09lu seconds\n", s, f);
3378 #endif
3379 	    fflush(d->trace);
3380 	}
3381     }
3382 }
3383 
3384 /**
3385  * Trace function for SQLite API calls
3386  * @param d pointer to database connection handle
3387  * @param fn SQLite function name
3388  * @param sql SQL string
3389  */
3390 
3391 static void
dbtraceapi(DBC * d,char * fn,const char * sql)3392 dbtraceapi(DBC *d, char *fn, const char *sql)
3393 {
3394     if (fn && d->trace) {
3395 	if (sql) {
3396 	    fprintf(d->trace, "-- %s: %s\n", fn, sql);
3397 	} else {
3398 	    fprintf(d->trace, "-- %s\n", fn);
3399 	}
3400 	fflush(d->trace);
3401     }
3402 }
3403 
3404 /**
3405  * Trace function for SQLite return codes
3406  * @param d pointer to database connection handle
3407  * @param rc SQLite return code
3408  * @param err error string or NULL
3409  */
3410 
3411 static void
dbtracerc(DBC * d,int rc,char * err)3412 dbtracerc(DBC *d, int rc, char *err)
3413 {
3414     if (rc != SQLITE_OK && d->trace) {
3415 	fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
3416 	fprintf(d->trace, err ? ": %s\n" : "\n", err);
3417 	fflush(d->trace);
3418     }
3419 }
3420 
3421 /**
3422  * Open SQLite database file given file name and flags.
3423  * @param d DBC pointer
3424  * @param name file name
3425  * @param isu true/false: file name is UTF8 encoded
3426  * @param dsn data source name
3427  * @param sflag STEPAPI flag
3428  * @param spflag SyncPragma string
3429  * @param ntflag NoTransaction string
3430  * @param jmode JournalMode string
3431  * @param busy busy/lock timeout
3432  * @result ODBC error code
3433  */
3434 
3435 static SQLRETURN
dbopen(DBC * d,char * name,int isu,char * dsn,char * sflag,char * spflag,char * ntflag,char * jmode,char * busy)3436 dbopen(DBC *d, char *name, int isu, char *dsn, char *sflag,
3437        char *spflag, char *ntflag, char *jmode, char *busy)
3438 {
3439     char *endp = NULL;
3440     int rc, tmp, busyto = 100000;
3441 #if defined(HAVE_SQLITE3VFS) && (HAVE_SQLITE3VFS)
3442     int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
3443     char *uname = name;
3444     const char *vfs_name = NULL;
3445 #endif
3446 
3447     if (d->sqlite) {
3448 	if (d->trace) {
3449 	    fprintf(d->trace, "-- sqlite3_close (deferred): '%s'\n",
3450 		    d->dbname);
3451 	    fflush(d->trace);
3452 	}
3453 	sqlite3_close(d->sqlite);
3454 	d->sqlite = NULL;
3455     }
3456 #if defined(HAVE_SQLITE3VFS) && (HAVE_SQLITE3VFS)
3457     if (d->nocreat) {
3458 	flags &= ~ SQLITE_OPEN_CREATE;
3459     }
3460 #if defined(_WIN32) || defined(_WIN64)
3461     if (!isu) {
3462 	uname = wmb_to_utf(name, -1);
3463 	if (!uname) {
3464 	    rc = SQLITE_NOMEM;
3465 	    setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
3466 	    return SQL_ERROR;
3467 	}
3468     }
3469 #endif
3470 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
3471     vfs_name = nvfs_makevfs(uname);
3472 #endif
3473 #ifdef SQLITE_OPEN_URI
3474     flags |= SQLITE_OPEN_URI;
3475 #endif
3476     rc = sqlite3_open_v2(uname, &d->sqlite, flags, vfs_name);
3477 #if defined(WINTERFACE) || defined(_WIN32) || defined(_WIN64)
3478     if (uname != name) {
3479 	uc_free(uname);
3480     }
3481 #endif
3482 #else
3483 #if defined(_WIN32) || defined(_WIN64)
3484     if (d->nocreat) {
3485 	char *cname = NULL;
3486 
3487 	if (isu) {
3488 	    cname = utf_to_wmb(name, -1);
3489 	}
3490 	if (GetFileAttributesA(cname ? cname : name) ==
3491 	    INVALID_FILE_ATTRIBUTES) {
3492 	    uc_free(cname);
3493 	    rc = SQLITE_CANTOPEN;
3494 	    setstatd(d, rc, "cannot open database",
3495 		     (*d->ov3) ? "HY000" : "S1000");
3496 	    return SQL_ERROR;
3497 	}
3498 	uc_free(cname);
3499     }
3500 #else
3501     if (d->nocreat && access(name, 004) < 0) {
3502 	rc = SQLITE_CANTOPEN;
3503 	setstatd(d, rc, "cannot open database", (*d->ov3) ? "HY000" : "S1000");
3504 	return SQL_ERROR;
3505     }
3506 #endif
3507 #if defined(_WIN32) || defined(_WIN64)
3508     if (!isu) {
3509 	WCHAR *wname = wmb_to_uc(name, -1);
3510 
3511 	if (!wname) {
3512 	    rc = SQLITE_NOMEM;
3513 	    setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
3514 	    return SQL_ERROR;
3515 	}
3516 	rc = sqlite3_open16(wname, &d->sqlite);
3517 	uc_free(wname);
3518     } else
3519 #endif
3520     rc = sqlite3_open(name, &d->sqlite);
3521 #endif /* !HAVE_SQLITE3VFS */
3522     if (rc != SQLITE_OK) {
3523 connfail:
3524 	setstatd(d, rc, "connect failed", (*d->ov3) ? "HY000" : "S1000");
3525 	if (d->sqlite) {
3526 	    sqlite3_close(d->sqlite);
3527 	    d->sqlite = NULL;
3528 	}
3529 	return SQL_ERROR;
3530     }
3531 #if defined(SQLITE_DYNLOAD) || defined(SQLITE_HAS_CODEC)
3532     if (d->pwd) {
3533 	sqlite3_key(d->sqlite, d->pwd, d->pwdLen);
3534     }
3535 #endif
3536     d->pwd = NULL;
3537     d->pwdLen = 0;
3538     if (d->trace) {
3539 #if defined(HAVE_SQLITE3PROFILE) && (HAVE_SQLITE3PROFILE)
3540 	sqlite3_profile(d->sqlite, dbtrace, d);
3541 #else
3542 	sqlite3_trace(d->sqlite, dbtrace, d);
3543 #endif
3544     }
3545     d->step_enable = getbool(sflag);
3546     d->trans_disable = getbool(ntflag);
3547     d->curtype = d->step_enable ?
3548 	SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
3549     tmp = strtol(busy, &endp, 0);
3550     if (endp && *endp == '\0' && endp != busy) {
3551 	busyto = tmp;
3552     }
3553     if (busyto < 1 || busyto > 1000000) {
3554 	busyto = 1000000;
3555     }
3556     d->timeout = busyto;
3557     if ((rc = setsqliteopts(d->sqlite, d)) != SQLITE_OK) {
3558 	if (d->trace) {
3559 	    fprintf(d->trace, "-- sqlite3_close: '%s'\n",
3560 		    d->dbname);
3561 	    fflush(d->trace);
3562 	}
3563 	sqlite3_close(d->sqlite);
3564 	d->sqlite = NULL;
3565 	goto connfail;
3566     }
3567     if (!spflag || spflag[0] == '\0') {
3568 	spflag = "NORMAL";
3569     }
3570     if (spflag[0] != '\0') {
3571 	char syncp[128];
3572 
3573 	sprintf(syncp, "PRAGMA synchronous = %8.8s;", spflag);
3574 	sqlite3_exec(d->sqlite, syncp, NULL, NULL, NULL);
3575     }
3576     if (jmode[0] != '\0') {
3577 	char jourp[128];
3578 
3579 	sprintf(jourp, "PRAGMA journal_mode = %16.16s;", jmode);
3580 	sqlite3_exec(d->sqlite, jourp, NULL, NULL, NULL);
3581     }
3582     freep(&d->dbname);
3583     d->dbname = xstrdup(name);
3584     freep(&d->dsn);
3585     d->dsn = xstrdup(dsn);
3586     if (d->trace) {
3587 	fprintf(d->trace, "-- sqlite3_open: '%s'\n", d->dbname);
3588 	fflush(d->trace);
3589     }
3590 #if defined(_WIN32) || defined(_WIN64)
3591     {
3592 	char pname[MAX_PATH];
3593 	HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
3594 			       FALSE, GetCurrentProcessId());
3595 
3596 	pname[0] = '\0';
3597 	if (h) {
3598 	    HMODULE m = NULL, l = LoadLibrary("psapi.dll");
3599 	    DWORD need;
3600 	    typedef BOOL (WINAPI *epmfunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
3601 	    typedef BOOL (WINAPI *gmbfunc)(HANDLE, HMODULE, LPSTR, DWORD);
3602 	    epmfunc epm;
3603 	    gmbfunc gmb;
3604 
3605 	    if (l) {
3606 		epm = (epmfunc) GetProcAddress(l, "EnumProcessModules");
3607 		gmb = (gmbfunc) GetProcAddress(l, "GetModuleBaseNameA");
3608 		if (epm && gmb && epm(h, &m, sizeof (m), &need)) {
3609 		    gmb(h, m, pname, sizeof (pname));
3610 		}
3611 		FreeLibrary(l);
3612 	    }
3613 	    CloseHandle(h);
3614 	}
3615 	d->xcelqrx = strncasecmp(pname, "EXCEL", 5) == 0 ||
3616 		     strncasecmp(pname, "MSQRY", 5) == 0;
3617 	if (d->trace && d->xcelqrx) {
3618 	    fprintf(d->trace, "-- enabled EXCEL quirks\n");
3619 	    fflush(d->trace);
3620 	}
3621     }
3622 #endif
3623     sqlite3_create_function(d->sqlite, "blob_import", 1, SQLITE_UTF8,
3624 			    d, blob_import, 0, 0);
3625     sqlite3_create_function(d->sqlite, "blob_export", 2, SQLITE_UTF8,
3626 			    d, blob_export, 0, 0);
3627     return SQL_SUCCESS;
3628 }
3629 
3630 /**
3631  * Load SQLite extension modules, if any
3632  * @param d DBC pointer
3633  * @param exts string, comma separated extension names
3634  */
3635 
3636 static void
dbloadext(DBC * d,char * exts)3637 dbloadext(DBC *d, char *exts)
3638 {
3639 #if defined(HAVE_SQLITE3LOADEXTENSION) && (HAVE_SQLITE3LOADEXTENSION)
3640     char *p;
3641     char path[SQL_MAX_MESSAGE_LENGTH];
3642     int plen = 0;
3643 
3644     if (!d->sqlite) {
3645 	return;
3646     }
3647     sqlite3_enable_load_extension(d->sqlite, 1);
3648 #if defined(_WIN32) || defined(_WIN64)
3649     GetModuleFileName(hModule, path, sizeof (path));
3650     p = strrchr(path, '\\');
3651     plen = p ? ((p + 1) - path) : 0;
3652 #endif
3653     do {
3654 	p = strchr(exts, ',');
3655 	if (p) {
3656 	    strncpy(path + plen, exts, p - exts);
3657 	    path[plen + (p - exts)] = '\0';
3658 	} else {
3659 	    strcpy(path + plen, exts);
3660 	}
3661 	if (exts[0]) {
3662 	    char *errmsg = NULL;
3663 	    int rc;
3664 #if defined(_WIN32) || defined(_WIN64)
3665 	    char *q;
3666 
3667 	    q = path + plen;
3668 	    if (!(q[0] &&
3669 		  ((q[1] == ':' && (q[2] == '\\' || q[2] == '/')) ||
3670 		   q[0] == '\\' || q[0] == '/' || q[0] == '.'))) {
3671 		q = path;
3672 	    }
3673 	    rc = sqlite3_load_extension(d->sqlite, q, 0, &errmsg);
3674 #else
3675 	    rc = sqlite3_load_extension(d->sqlite, path, 0, &errmsg);
3676 #endif
3677 	    if (rc != SQLITE_OK) {
3678 #if defined(_WIN32) || defined(_WIN64)
3679 		char buf[512], msg[512];
3680 
3681 		LoadString(hModule, IDS_EXTERR, buf, sizeof (buf));
3682 		wsprintf(msg, buf, q, errmsg ?
3683 			 errmsg : "no error info available");
3684 		LoadString(hModule, IDS_EXTTITLE, buf, sizeof (buf));
3685 		MessageBox(NULL, msg, buf,
3686 			   MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
3687 			   MB_SETFOREGROUND);
3688 #else
3689 		fprintf(stderr, "extension '%s' did not load%s%s\n",
3690 			path, errmsg ? ": " : "", errmsg ? errmsg : "");
3691 #endif
3692 	    }
3693 	}
3694 	if (p) {
3695 	    exts = p + 1;
3696 	}
3697     } while (p);
3698 #endif /* HAVE_SQLITE3LOADEXTENSION */
3699 }
3700 
3701 /**
3702  * Find out column type
3703  * @param s3stmt SQLite statement pointer
3704  * @param col column number
3705  * @param d DBC pointer (for tracing only)
3706  * @param guessed_types flag array
3707  * @result type name as string
3708  */
3709 
3710 static char *
s3stmt_coltype(sqlite3_stmt * s3stmt,int col,DBC * d,int * guessed_types)3711 s3stmt_coltype(sqlite3_stmt *s3stmt, int col, DBC *d, int *guessed_types)
3712 {
3713     char *typename = (char *) sqlite3_column_decltype(s3stmt, col);
3714     char guess[64];
3715 
3716     guess[0] = '\0';
3717     if (!typename) {
3718 	int coltype = sqlite3_column_type(s3stmt, col);
3719 
3720 	if (guessed_types) {
3721 	    guessed_types[0]++;
3722 	}
3723 	if (d->trace) {
3724 	    sprintf(guess, " (guessed from %d)", coltype);
3725 	}
3726 	switch (coltype) {
3727 	case SQLITE_INTEGER: typename = "integer"; break;
3728 	case SQLITE_FLOAT:   typename = "double";  break;
3729 	default:
3730 	case SQLITE_TEXT:    typename = "varchar"; break;
3731 	case SQLITE_BLOB:    typename = "blob";    break;
3732 #if 0
3733 	case SQLITE_NULL:    typename = "null";    break;
3734 #endif
3735 	}
3736     }
3737     if (d->trace) {
3738 	fprintf(d->trace, "-- column %d type%s: '%s'\n", col + 1,
3739 		guess, typename);
3740 	fflush(d->trace);
3741     }
3742     return typename;
3743 }
3744 
3745 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && (HAVE_SQLITE3TABLECOLUMNMETADATA)
3746 
3747 /**
3748  * Add meta data for column
3749  * @param s3stmt SQLite statement pointer
3750  * @param col column number
3751  * @param d DBC pointer (for tracing only)
3752  * @param ci pointer to COL
3753  */
3754 
3755 static void
s3stmt_addmeta(sqlite3_stmt * s3stmt,int col,DBC * d,COL * ci)3756 s3stmt_addmeta(sqlite3_stmt *s3stmt, int col, DBC *d, COL *ci)
3757 {
3758     int nn = 0, pk = 0, ai = 0;
3759     const char *dn, *tn, *cn, *dummy1, *dummy2;
3760 
3761     dn = sqlite3_column_database_name(s3stmt, col);
3762     tn = sqlite3_column_table_name(s3stmt, col);
3763     cn = sqlite3_column_origin_name(s3stmt, col);
3764     sqlite3_table_column_metadata(d->sqlite, dn, tn, cn,
3765 				  &dummy1, &dummy2,
3766 				  &nn, &pk, &ai);
3767     ci->autoinc = ai ? SQL_TRUE: SQL_FALSE;
3768     ci->notnull = nn ? SQL_NO_NULLS : SQL_NULLABLE;
3769     if (d->trace) {
3770 	fprintf(d->trace, "-- column %d %s\n",
3771 		col + 1, nn ? "notnull" : "nullable");
3772 	if (ai) {
3773 	    fprintf(d->trace, "-- column %d autoincrement\n", col + 1);
3774 	}
3775 	fflush(d->trace);
3776     }
3777 }
3778 
3779 #endif
3780 
3781 /**
3782  * Do one sqlite statement step gathering one result row
3783  * @param s statement pointer
3784  * @result ODBC error code
3785  */
3786 
3787 static int
s3stmt_step(STMT * s)3788 s3stmt_step(STMT *s)
3789 {
3790     DBC *d = (DBC *) s->dbc;
3791     char **rowd = NULL;
3792     const char *errp = NULL;
3793     int i, ncols, rc;
3794 
3795     if (s != d->cur_s3stmt || !s->s3stmt) {
3796 	setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
3797 	return SQL_ERROR;
3798     }
3799     rc = sqlite3_step(s->s3stmt);
3800     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
3801 	++s->s3stmt_rownum;
3802 	ncols = sqlite3_column_count(s->s3stmt);
3803 	if (d->s3stmt_needmeta && s->s3stmt_rownum == 0 && ncols > 0) {
3804 	    PTRDIFF_T size;
3805 	    char *p;
3806 	    COL *dyncols;
3807 	    const char *colname, *typename;
3808 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
3809 	    char *tblname;
3810 #endif
3811 
3812 	    for (i = size = 0; i < ncols; i++) {
3813 		colname = sqlite3_column_name(s->s3stmt, i);
3814 		size += 3 + 3 * strlen(colname);
3815 	    }
3816 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
3817 	    tblname = (char *) size;
3818 	    for (i = 0; i < ncols; i++) {
3819 		p = (char *) sqlite3_column_table_name(s->s3stmt, i);
3820 		size += 2 + (p ? strlen(p) : 0);
3821 	    }
3822 #endif
3823 	    dyncols = xmalloc(ncols * sizeof (COL) + size);
3824 	    if (!dyncols) {
3825 		freedyncols(s);
3826 		s->ncols = 0;
3827 		dbtraceapi(d, "sqlite3_finalize", 0);
3828 		sqlite3_finalize(s->s3stmt);
3829 		s->s3stmt = NULL;
3830 		d->cur_s3stmt = NULL;
3831 		return nomem(s);
3832 	    }
3833 	    p = (char *) (dyncols + ncols);
3834 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
3835 	    tblname = p + (PTRDIFF_T) tblname;
3836 #endif
3837 	    for (i = 0; i < ncols; i++) {
3838 		char *q;
3839 
3840 		colname = sqlite3_column_name(s->s3stmt, i);
3841 		if (d->trace) {
3842 		    fprintf(d->trace, "-- column %d name: '%s'\n",
3843 			    i + 1, colname);
3844 		    fflush(d->trace);
3845 		}
3846 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
3847 		q = (char *) sqlite3_column_table_name(s->s3stmt, i);
3848 		strcpy(tblname, q ? q : "");
3849 		if (d->trace) {
3850 		    fprintf(d->trace, "-- table %d name: '%s'\n",
3851 			    i + 1, tblname);
3852 		    fflush(d->trace);
3853 		}
3854 		dyncols[i].table = tblname;
3855 		tblname += strlen(tblname) + 1;
3856 #endif
3857 		typename = s3stmt_coltype(s->s3stmt, i, d, 0);
3858 		dyncols[i].db = ((DBC *) (s->dbc))->dbname;
3859 		strcpy(p, colname);
3860 		dyncols[i].label = p;
3861 		p += strlen(p) + 1;
3862 		q = strchr(colname, '.');
3863 		if (q) {
3864 		    char *q2 = strchr(q + 1, '.');
3865 
3866 		    /* SQLite 3.3.4 produces view.table.column sometimes */
3867 		    if (q2) {
3868 			q = q2;
3869 		    }
3870 		}
3871 		if (q) {
3872 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
3873 		    dyncols[i].table = p;
3874 #endif
3875 		    strncpy(p, colname, q - colname);
3876 		    p[q - colname] = '\0';
3877 		    p += strlen(p) + 1;
3878 		    strcpy(p, q + 1);
3879 		    dyncols[i].column = p;
3880 		    p += strlen(p) + 1;
3881 		} else {
3882 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
3883 		    dyncols[i].table = "";
3884 #endif
3885 		    strcpy(p, colname);
3886 		    dyncols[i].column = p;
3887 		    p += strlen(p) + 1;
3888 		}
3889 		if (s->longnames) {
3890 		    dyncols[i].column = dyncols[i].label;
3891 		}
3892 #ifdef SQL_LONGVARCHAR
3893 		dyncols[i].type = SQL_LONGVARCHAR;
3894 		dyncols[i].size = 65535;
3895 #else
3896 		dyncols[i].type = SQL_VARCHAR;
3897 		dyncols[i].size = 255;
3898 #endif
3899 		dyncols[i].index = i;
3900 		dyncols[i].scale = 0;
3901 		dyncols[i].prec = 0;
3902 		dyncols[i].nosign = 1;
3903 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && (HAVE_SQLITE3TABLECOLUMNMETADATA)
3904 		s3stmt_addmeta(s->s3stmt, i, d, &dyncols[i]);
3905 #else
3906 		dyncols[i].autoinc = SQL_FALSE;
3907 		dyncols[i].notnull = SQL_NULLABLE;
3908 #endif
3909 		dyncols[i].typename = xstrdup(typename);
3910 	    }
3911 	    freedyncols(s);
3912 	    s->ncols = s->dcols = ncols;
3913 	    s->dyncols = s->cols = dyncols;
3914 	    fixupdyncols(s, d);
3915 	    mkbindcols(s, s->ncols);
3916 	    d->s3stmt_needmeta = 0;
3917 	}
3918 	if (ncols <= 0) {
3919 	    goto killstmt;
3920 	}
3921 	if (rc == SQLITE_DONE) {
3922 	    freeresult(s, 0);
3923 	    s->nrows = 0;
3924 	    dbtraceapi(d, "sqlite3_finalize", 0);
3925 	    sqlite3_finalize(s->s3stmt);
3926 	    s->s3stmt = NULL;
3927 	    d->cur_s3stmt = NULL;
3928 	    return SQL_SUCCESS;
3929 	}
3930 	rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
3931 	if (rowd) {
3932 	    const unsigned char *value;
3933 
3934 	    rowd[0] = (char *) ((PTRDIFF_T) (ncols * 2));
3935 	    ++rowd;
3936 	    for (i = 0; i < ncols; i++) {
3937 		int coltype = sqlite3_column_type(s->s3stmt, i);
3938 
3939 		rowd[i] = rowd[i + ncols] = NULL;
3940 		if (coltype == SQLITE_BLOB) {
3941 		    int k, nbytes = sqlite3_column_bytes(s->s3stmt, i);
3942 		    char *qp;
3943 		    unsigned const char *bp;
3944 
3945 		    bp = sqlite3_column_blob(s->s3stmt, i);
3946 		    qp = xmalloc(nbytes * 2 + 4);
3947 		    if (qp) {
3948 			rowd[i + ncols] = qp;
3949 			*qp++ = 'X';
3950 			*qp++ = '\'';
3951 			for (k = 0; k < nbytes; k++) {
3952 			    *qp++ = xdigits[(bp[k] >> 4)];
3953 			    *qp++ = xdigits[(bp[k] & 0xF)];
3954 			}
3955 			*qp++ = '\'';
3956 			*qp = '\0';
3957 		    }
3958 		} else if (coltype != SQLITE_NULL) {
3959 		    value = sqlite3_column_text(s->s3stmt, i);
3960 		    rowd[i + ncols] = xstrdup((char *) value);
3961 		}
3962 	    }
3963 	    for (i = 0; i < ncols; i++) {
3964 		int coltype = sqlite3_column_type(s->s3stmt, i);
3965 
3966 		value = NULL;
3967 		if (coltype == SQLITE_BLOB) {
3968 		    value = sqlite3_column_blob(s->s3stmt, i);
3969 		} else if (coltype != SQLITE_NULL) {
3970 		    value = sqlite3_column_text(s->s3stmt, i);
3971 		}
3972 		if (value && !rowd[i + ncols]) {
3973 		    freerows(rowd);
3974 		    rowd = 0;
3975 		    break;
3976 		}
3977 	    }
3978 	}
3979 	if (rowd) {
3980 	    freeresult(s, 0);
3981 	    s->nrows = 1;
3982 	    s->rows = rowd;
3983 	    s->rowfree = freerows;
3984 	    if (rc == SQLITE_DONE) {
3985 		dbtraceapi(d, "sqlite3_finalize", 0);
3986 		sqlite3_finalize(s->s3stmt);
3987 		s->s3stmt = NULL;
3988 		d->cur_s3stmt = NULL;
3989 	    }
3990 	    return SQL_SUCCESS;
3991 	}
3992     }
3993 killstmt:
3994     dbtraceapi(d, "sqlite3_reset", 0);
3995     rc = sqlite3_reset(s->s3stmt);
3996     s->s3stmt_noreset = 1;
3997     errp = sqlite3_errmsg(d->sqlite);
3998     if (d->cur_s3stmt == s) {
3999 	d->cur_s3stmt = NULL;
4000     }
4001     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
4002 	    errp ? errp : "unknown error", rc);
4003     return SQL_ERROR;
4004 }
4005 
4006 /**
4007  * Stop running sqlite statement
4008  * @param s statement pointer
4009  */
4010 
4011 static void
s3stmt_end(STMT * s)4012 s3stmt_end(STMT *s)
4013 {
4014     DBC *d;
4015 
4016     if (!s || !s->s3stmt) {
4017 	return;
4018     }
4019     d = (DBC *) s->dbc;
4020     if (d) {
4021 	d->busyint = 0;
4022     }
4023     if (!s->s3stmt_noreset) {
4024 	dbtraceapi(d, "sqlite3_reset", 0);
4025 	sqlite3_reset(s->s3stmt);
4026 	s->s3stmt_noreset = 1;
4027 	s->s3stmt_rownum = -1;
4028     }
4029     if (d->cur_s3stmt == s) {
4030 	d->cur_s3stmt = NULL;
4031     }
4032 }
4033 
4034 /**
4035  * Conditionally stop running sqlite statement
4036  * @param s statement pointer
4037  */
4038 
4039 static void
s3stmt_end_if(STMT * s)4040 s3stmt_end_if(STMT *s)
4041 {
4042     DBC *d = (DBC *) s->dbc;
4043 
4044     if (d) {
4045 	d->busyint = 0;
4046     }
4047     if (d && d->cur_s3stmt == s) {
4048 	s3stmt_end(s);
4049     }
4050 }
4051 
4052 /**
4053  * Drop running sqlite statement in STMT
4054  * @param s statement pointer
4055  */
4056 
4057 static void
s3stmt_drop(STMT * s)4058 s3stmt_drop(STMT *s)
4059 {
4060     if (s->s3stmt) {
4061 	DBC *d = (DBC *) s->dbc;
4062 
4063 	if (d) {
4064 	    dbtraceapi(d, "sqlite3_finalize", 0);
4065 	}
4066 	sqlite3_finalize(s->s3stmt);
4067 	s->s3stmt = NULL;
4068 	s->s3stmt_rownum = 0;
4069     }
4070 }
4071 
4072 /**
4073  * Start sqlite statement for execution of SELECT statement.
4074  * @param s statement pointer
4075  * @result ODBC error code
4076  */
4077 
4078 static SQLRETURN
s3stmt_start(STMT * s)4079 s3stmt_start(STMT *s)
4080 {
4081     DBC *d = (DBC *) s->dbc;
4082     const char *endp;
4083     sqlite3_stmt *s3stmt = NULL;
4084     int rc, nretry = 0;
4085 
4086     d->s3stmt_needmeta = 0;
4087     if (!s->s3stmt) {
4088 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
4089 	dbtraceapi(d, "sqlite3_prepare_v2", (char *) s->query);
4090 #else
4091 	dbtraceapi(d, "sqlite3_prepare", (char *) s->query);
4092 #endif
4093 	do {
4094 	    s3stmt = NULL;
4095 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
4096 	    rc = sqlite3_prepare_v2(d->sqlite, (char *) s->query, -1,
4097 				    &s3stmt, &endp);
4098 #else
4099 	    rc = sqlite3_prepare(d->sqlite, (char *) s->query, -1,
4100 				 &s3stmt, &endp);
4101 #endif
4102 	    if (rc != SQLITE_OK) {
4103 		if (s3stmt) {
4104 		    sqlite3_finalize(s3stmt);
4105 		    s3stmt = NULL;
4106 		}
4107 	    }
4108 	} while (rc == SQLITE_SCHEMA && (++nretry) < 2);
4109 	dbtracerc(d, rc, NULL);
4110 	if (rc != SQLITE_OK) {
4111 	    if (s3stmt) {
4112 		dbtraceapi(d, "sqlite3_finalize", NULL);
4113 		sqlite3_finalize(s3stmt);
4114 	    }
4115 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
4116 		    sqlite3_errmsg(d->sqlite), rc);
4117 	    return SQL_ERROR;
4118 	}
4119 	if (sqlite3_bind_parameter_count(s3stmt) != s->nparams) {
4120 	    dbtraceapi(d, "sqlite3_finalize", 0);
4121 	    sqlite3_finalize(s3stmt);
4122 	    setstat(s, SQLITE_ERROR, "parameter marker count incorrect",
4123 		    (*s->ov3) ? "HY000" : "S1000");
4124 	    return SQL_ERROR;
4125 	}
4126 	s->s3stmt = s3stmt;
4127 	s->s3stmt_noreset = 1;
4128 	d->s3stmt_needmeta = 1;
4129     }
4130     d->cur_s3stmt = s;
4131     s->s3stmt_rownum = -1;
4132     s3bind(d, s->s3stmt, s->nparams, s->bindparms);
4133     return SQL_SUCCESS;
4134 }
4135 
4136 /**
4137  * Function not implemented.
4138  */
4139 
4140 SQLRETURN SQL_API
SQLBulkOperations(SQLHSTMT stmt,SQLSMALLINT oper)4141 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
4142 {
4143     SQLRETURN ret;
4144 
4145     HSTMT_LOCK(stmt);
4146     ret = drvunimplstmt(stmt);
4147     HSTMT_UNLOCK(stmt);
4148     return ret;
4149 }
4150 
4151 #ifndef WINTERFACE
4152 /**
4153  * Function not implemented.
4154  */
4155 
4156 SQLRETURN SQL_API
SQLDataSources(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)4157 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
4158 	       SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
4159 	       SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
4160 {
4161     if (env == SQL_NULL_HENV) {
4162 	return SQL_INVALID_HANDLE;
4163     }
4164     return SQL_ERROR;
4165 }
4166 #endif
4167 
4168 #ifdef WINTERFACE
4169 /**
4170  * Function not implemented.
4171  */
4172 
4173 SQLRETURN SQL_API
SQLDataSourcesW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLWCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)4174 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
4175 		SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
4176 		SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
4177 {
4178     if (env == SQL_NULL_HENV) {
4179 	return SQL_INVALID_HANDLE;
4180     }
4181     return SQL_ERROR;
4182 }
4183 #endif
4184 
4185 #ifndef WINTERFACE
4186 /**
4187  * Function not implemented.
4188  */
4189 
4190 SQLRETURN SQL_API
SQLDrivers(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)4191 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
4192 	   SQLSMALLINT descmax, SQLSMALLINT *desclenp,
4193 	   SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
4194 {
4195     if (env == SQL_NULL_HENV) {
4196 	return SQL_INVALID_HANDLE;
4197     }
4198     return SQL_ERROR;
4199 }
4200 #endif
4201 
4202 #ifdef WINTERFACE
4203 /**
4204  * Function not implemented.
4205  */
4206 
4207 SQLRETURN SQL_API
SQLDriversW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLWCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)4208 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
4209 	    SQLSMALLINT descmax, SQLSMALLINT *desclenp,
4210 	    SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
4211 {
4212     if (env == SQL_NULL_HENV) {
4213 	return SQL_INVALID_HANDLE;
4214     }
4215     return SQL_ERROR;
4216 }
4217 #endif
4218 
4219 #ifndef WINTERFACE
4220 /**
4221  * Function not implemented.
4222  */
4223 
4224 SQLRETURN SQL_API
SQLBrowseConnect(SQLHDBC dbc,SQLCHAR * connin,SQLSMALLINT conninLen,SQLCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)4225 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
4226 		 SQLCHAR *connout, SQLSMALLINT connoutMax,
4227 		 SQLSMALLINT *connoutLen)
4228 {
4229     SQLRETURN ret;
4230 
4231     HDBC_LOCK(dbc);
4232     ret = drvunimpldbc(dbc);
4233     HDBC_UNLOCK(dbc);
4234     return ret;
4235 }
4236 #endif
4237 
4238 #ifdef WINTERFACE
4239 /**
4240  * Function not implemented.
4241  */
4242 
4243 SQLRETURN SQL_API
SQLBrowseConnectW(SQLHDBC dbc,SQLWCHAR * connin,SQLSMALLINT conninLen,SQLWCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)4244 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
4245 		  SQLWCHAR *connout, SQLSMALLINT connoutMax,
4246 		  SQLSMALLINT *connoutLen)
4247 {
4248     SQLRETURN ret;
4249 
4250     HDBC_LOCK(dbc);
4251     ret = drvunimpldbc(dbc);
4252     HDBC_UNLOCK(dbc);
4253     return ret;
4254 }
4255 #endif
4256 
4257 /**
4258  * Internal put (partial) parameter data into executing statement.
4259  * @param stmt statement handle
4260  * @param data pointer to data
4261  * @param len length of data
4262  * @result ODBC error code
4263  */
4264 
4265 static SQLRETURN
drvputdata(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)4266 drvputdata(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
4267 {
4268     STMT *s;
4269     int i, dlen, done = 0;
4270     BINDPARM *p;
4271 
4272     if (stmt == SQL_NULL_HSTMT) {
4273 	return SQL_INVALID_HANDLE;
4274     }
4275     s = (STMT *) stmt;
4276     if (!s->query || s->nparams <= 0) {
4277 seqerr:
4278 	setstat(s, -1, "sequence error", "HY010");
4279 	return SQL_ERROR;
4280     }
4281     for (i = 0; i < s->nparams; i++) {
4282 	p = &s->bindparms[i];
4283 	if (p->need > 0) {
4284 	    int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
4285 
4286 	    if (len == SQL_NULL_DATA) {
4287 		freep(&p->parbuf);
4288 		p->param = NULL;
4289 		p->len = SQL_NULL_DATA;
4290 		p->need = -1;
4291 	    } else if (type != SQL_C_CHAR
4292 #ifdef WCHARSUPPORT
4293 		       && type != SQL_C_WCHAR
4294 #endif
4295 		       && type != SQL_C_BINARY) {
4296 		int size = 0;
4297 
4298 		switch (type) {
4299 		case SQL_C_TINYINT:
4300 		case SQL_C_UTINYINT:
4301 		case SQL_C_STINYINT:
4302 #ifdef SQL_BIT
4303 		case SQL_C_BIT:
4304 #endif
4305 		    size = sizeof (char);
4306 		    break;
4307 		case SQL_C_SHORT:
4308 		case SQL_C_USHORT:
4309 		case SQL_C_SSHORT:
4310 		    size = sizeof (short);
4311 		    break;
4312 		case SQL_C_LONG:
4313 		case SQL_C_ULONG:
4314 		case SQL_C_SLONG:
4315 		    size = sizeof (long);
4316 		    break;
4317 #ifdef SQL_BIGINT
4318 		case SQL_C_UBIGINT:
4319 		case SQL_C_SBIGINT:
4320 		    size = sizeof (SQLBIGINT);
4321 		    break;
4322 #endif
4323 		case SQL_C_FLOAT:
4324 		    size = sizeof (float);
4325 		    break;
4326 		case SQL_C_DOUBLE:
4327 		    size = sizeof (double);
4328 		    break;
4329 #ifdef SQL_C_TYPE_DATE
4330 		case SQL_C_TYPE_DATE:
4331 #endif
4332 		case SQL_C_DATE:
4333 		    size = sizeof (DATE_STRUCT);
4334 		    break;
4335 #ifdef SQL_C_TYPE_DATE
4336 		case SQL_C_TYPE_TIME:
4337 #endif
4338 		case SQL_C_TIME:
4339 		    size = sizeof (TIME_STRUCT);
4340 		    break;
4341 #ifdef SQL_C_TYPE_DATE
4342 		case SQL_C_TYPE_TIMESTAMP:
4343 #endif
4344 		case SQL_C_TIMESTAMP:
4345 		    size = sizeof (TIMESTAMP_STRUCT);
4346 		    break;
4347 		}
4348 		freep(&p->parbuf);
4349 		p->parbuf = xmalloc(size);
4350 		if (!p->parbuf) {
4351 		    return nomem(s);
4352 		}
4353 		p->param = p->parbuf;
4354 		memcpy(p->param, data, size);
4355 		p->len = size;
4356 		p->need = -1;
4357 	    } else if (len == SQL_NTS && (
4358 		       type == SQL_C_CHAR
4359 #ifdef WCHARSUPPORT
4360 		       || type == SQL_C_WCHAR
4361 #endif
4362 		      )) {
4363 		char *dp = data;
4364 
4365 #ifdef WCHARSUPPORT
4366 		if (type == SQL_C_WCHAR) {
4367 		    dp = uc_to_utf(data, len);
4368 		    if (!dp) {
4369 			return nomem(s);
4370 		    }
4371 		}
4372 #endif
4373 #if defined(_WIN32) || defined(_WIN64)
4374 		if (*s->oemcp) {
4375 		    dp = wmb_to_utf(data, strlen (data));
4376 		    if (!dp) {
4377 			return nomem(s);
4378 		    }
4379 		}
4380 #endif
4381 		dlen = strlen(dp);
4382 		freep(&p->parbuf);
4383 		p->parbuf = xmalloc(dlen + 1);
4384 		if (!p->parbuf) {
4385 		    if (dp != data) {
4386 			uc_free(dp);
4387 		    }
4388 		    return nomem(s);
4389 		}
4390 		p->param = p->parbuf;
4391 		strcpy(p->param, dp);
4392 		if (dp != data) {
4393 		    uc_free(dp);
4394 		}
4395 		p->len = dlen;
4396 		p->need = -1;
4397 	    } else if (len < 0) {
4398 		setstat(s, -1, "invalid length", "HY090");
4399 		return SQL_ERROR;
4400 	    } else {
4401 		dlen = min(p->len - p->offs, len);
4402 		if (!p->param) {
4403 		    setstat(s, -1, "no memory for parameter", "HY013");
4404 		    return SQL_ERROR;
4405 		}
4406 		memcpy((char *) p->param + p->offs, data, dlen);
4407 		p->offs += dlen;
4408 		if (p->offs >= p->len) {
4409 #ifdef WCHARSUPPORT
4410 		    if (type == SQL_C_WCHAR) {
4411 			char *dp = uc_to_utf(p->param, p->len);
4412 			char *np;
4413 			int nlen;
4414 
4415 			if (!dp) {
4416 			    return nomem(s);
4417 			}
4418 			nlen = strlen(dp);
4419 			np = xmalloc(nlen + 1);
4420 			if (!np) {
4421 			    uc_free(dp);
4422 			    return nomem(s);
4423 			}
4424 			strcpy(np, dp);
4425 			uc_free(dp);
4426 			if (p->param == p->parbuf) {
4427 			    freep(&p->parbuf);
4428 			}
4429 			p->parbuf = p->param = np;
4430 			p->len = nlen;
4431 		    } else {
4432 			*((char *) p->param + p->len) = '\0';
4433 		    }
4434 		    p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR)
4435 			    ? -1 : 0;
4436 #else
4437 		    *((char *) p->param + p->len) = '\0';
4438 		    p->need = (type == SQL_C_CHAR) ? -1 : 0;
4439 #endif
4440 #if defined(_WIN32) || defined(_WIN64)
4441 		    if (type == SQL_C_CHAR && *s->oemcp) {
4442 			char *dp = wmb_to_utf(p->param, p->len);
4443 
4444 			if (!dp) {
4445 			    return nomem(s);
4446 			}
4447 			if (p->param == p->parbuf) {
4448 			    freep(&p->parbuf);
4449 			}
4450 			p->parbuf = p->param = dp;
4451 			p->len = strlen(dp);
4452 		    }
4453 		    if (p->type == SQL_C_WCHAR &&
4454 			(p->stype == SQL_VARCHAR ||
4455 			 p->stype == SQL_LONGVARCHAR) &&
4456 			 p->len == p->coldef * sizeof (SQLWCHAR)) {
4457 			/* fix for MS-Access */
4458 			p->len = p->coldef;
4459 		    }
4460 #endif
4461 		}
4462 	    }
4463 	    done = 1;
4464 	    break;
4465 	}
4466     }
4467     if (!done) {
4468 	goto seqerr;
4469     }
4470     return SQL_SUCCESS;
4471 }
4472 
4473 /**
4474  * Put (partial) parameter data into executing statement.
4475  * @param stmt statement handle
4476  * @param data pointer to data
4477  * @param len length of data
4478  * @result ODBC error code
4479  */
4480 
4481 SQLRETURN SQL_API
SQLPutData(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)4482 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
4483 {
4484     SQLRETURN ret;
4485 
4486     HSTMT_LOCK(stmt);
4487     ret = drvputdata(stmt, data, len);
4488     HSTMT_UNLOCK(stmt);
4489     return ret;
4490 }
4491 
4492 /**
4493  * Clear out parameter bindings, if any.
4494  * @param s statement pointer
4495  */
4496 
4497 static SQLRETURN
freeparams(STMT * s)4498 freeparams(STMT *s)
4499 {
4500     if (s->bindparms) {
4501 	int n;
4502 
4503 	for (n = 0; n < s->nbindparms; n++) {
4504 	    freep(&s->bindparms[n].parbuf);
4505 	    memset(&s->bindparms[n], 0, sizeof (BINDPARM));
4506 	}
4507     }
4508     return SQL_SUCCESS;
4509 }
4510 
4511 /**
4512  * Setup SQLite3 parameter for statement parameter.
4513  * @param s statement pointer
4514  * @param sql sql string
4515  * @param pnum parameter number
4516  * @result ODBC error code
4517  *
4518  * The parameter is converted within BINDPARM in order to
4519  * be presented to sqlite3_bind_*() functions.
4520  */
4521 
4522 static SQLRETURN
setupparam(STMT * s,char * sql,int pnum)4523 setupparam(STMT *s, char *sql, int pnum)
4524 {
4525     int type, len = 0, needalloc = 0;
4526     BINDPARM *p;
4527 
4528     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
4529 	goto error;
4530     }
4531     p = &s->bindparms[pnum];
4532     type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
4533 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
4534     /* MS Access hack part 4 (map SQL_C_DEFAULT to SQL_C_CHAR) */
4535     if (type == SQL_C_WCHAR && p->type == SQL_C_DEFAULT) {
4536 	type = SQL_C_CHAR;
4537     }
4538 #endif
4539     if (p->need > 0) {
4540 	return setupparbuf(s, p);
4541     }
4542     p->strbuf[0] = '\0';
4543     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
4544 	p->s3type = SQLITE_NULL;
4545 	p->s3size = 0;
4546 	return SQL_SUCCESS;
4547     }
4548     switch (type) {
4549     case SQL_C_BINARY:
4550 	p->s3type = SQLITE_BLOB;
4551 	p->s3size = p->len;
4552 	p->s3val = p->param;
4553 	if (p->need < 0) {
4554 	    break;
4555 	}
4556 	if (!p->lenp) {
4557 	    len = p->len;
4558 	} else {
4559 	    len = *p->lenp;
4560 	    if (len <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
4561 		len = SQL_LEN_DATA_AT_EXEC(len);
4562 	    }
4563 	}
4564 	if (len < 0) {
4565 	    setstat(s, -1, "invalid length", "HY009");
4566 	    return SQL_ERROR;
4567 	}
4568 	p->len = len;
4569 	p->max = p->len;
4570 	p->need = -1;
4571 	p->s3size = len;
4572 	break;
4573 #ifdef WCHARSUPPORT
4574     case SQL_C_WCHAR:
4575 #endif
4576     case SQL_C_CHAR:
4577 	p->s3type = SQLITE_TEXT;
4578 	p->s3size = -1;
4579 	p->s3val = p->param;
4580 	if (!p->parbuf && p->lenp) {
4581 #ifdef WCHARSUPPORT
4582 	    if (type == SQL_C_WCHAR) {
4583 		if (*p->lenp == SQL_NTS) {
4584 		    p->max = uc_strlen(p->param) * sizeof (SQLWCHAR);
4585 		} else if (*p->lenp >= 0) {
4586 		    p->max = *p->lenp;
4587 		}
4588 	    } else
4589 #endif
4590 	    if (type == SQL_C_CHAR) {
4591 		if (*p->lenp == SQL_NTS) {
4592 		    p->len = p->max = strlen(p->param);
4593 #if defined(_WIN32) || defined(_WIN64)
4594 		    needalloc = 1;
4595 #endif
4596 		} else if (*p->lenp >= 0) {
4597 		    p->len = p->max = *p->lenp;
4598 		    needalloc = 1;
4599 		}
4600 	    }
4601 	}
4602 	if (p->need < 0 && p->parbuf == p->param) {
4603 	    break;
4604 	}
4605 #ifdef WCHARSUPPORT
4606 	if (type == SQL_C_WCHAR) {
4607 	    char *dp = uc_to_utf(p->param, p->max);
4608 
4609 	    if (!dp) {
4610 		return nomem(s);
4611 	    }
4612 	    if (p->param == p->parbuf) {
4613 		freep(&p->parbuf);
4614 	    }
4615 	    p->parbuf = p->param = dp;
4616 	    p->need = -1;
4617 	    p->len = strlen(p->param);
4618 	    p->s3val = p->param;
4619 	    p->s3size = p->len;
4620 	} else
4621 #endif
4622 	if (type == SQL_C_CHAR) {
4623 	    p->s3val = p->param;
4624 	    if (needalloc) {
4625 		char *dp;
4626 
4627 #if defined(_WIN32) || defined(_WIN64)
4628 		if (*s->oemcp) {
4629 		    dp = wmb_to_utf(p->param, p->len);
4630 		} else {
4631 		    dp = xmalloc(p->len + 1);
4632 		}
4633 #else
4634 		dp = xmalloc(p->len + 1);
4635 #endif
4636 		if (!dp) {
4637 		    return nomem(s);
4638 		}
4639 #if defined(_WIN32) || defined(_WIN64)
4640 		if (*s->oemcp) {
4641 		    p->len = strlen(dp);
4642 		} else {
4643 		    memcpy(dp, p->param, p->len);
4644 		    dp[p->len] = '\0';
4645 		}
4646 #else
4647 		memcpy(dp, p->param, p->len);
4648 		dp[p->len] = '\0';
4649 #endif
4650 		if (p->param == p->parbuf) {
4651 		    freep(&p->parbuf);
4652 		}
4653 		p->parbuf = p->param = dp;
4654 		p->need = -1;
4655 		p->s3val = p->param;
4656 		p->s3size = p->len;
4657 	    }
4658 	}
4659 	break;
4660     case SQL_C_UTINYINT:
4661 	p->s3type = SQLITE_INTEGER;
4662 	p->s3size = sizeof (int);
4663 	p->s3ival = *((unsigned char *) p->param);
4664 	break;
4665     case SQL_C_TINYINT:
4666     case SQL_C_STINYINT:
4667 	p->s3type = SQLITE_INTEGER;
4668 	p->s3size = sizeof (int);
4669 	p->s3ival = *((char *) p->param);
4670 	break;
4671     case SQL_C_USHORT:
4672 	p->s3type = SQLITE_INTEGER;
4673 	p->s3size = sizeof (int);
4674 	p->s3ival = *((unsigned short *) p->param);
4675 	break;
4676     case SQL_C_SHORT:
4677     case SQL_C_SSHORT:
4678 	p->s3type = SQLITE_INTEGER;
4679 	p->s3size = sizeof (int);
4680 	p->s3ival = *((short *) p->param);
4681 	break;
4682     case SQL_C_ULONG:
4683 	p->s3type = SQLITE_INTEGER;
4684 	p->s3size = sizeof (int);
4685 	p->s3ival = *((unsigned int *) p->param);
4686 	break;
4687     case SQL_C_LONG:
4688     case SQL_C_SLONG:
4689 	p->s3type = SQLITE_INTEGER;
4690 	p->s3size = sizeof (int);
4691 	p->s3ival = *((int *) p->param);
4692 	break;
4693 #ifdef SQL_BIT
4694     case SQL_C_BIT:
4695 	p->s3type = SQLITE_INTEGER;
4696 	p->s3size = sizeof (int);
4697 	p->s3ival = (*((unsigned char *) p->param)) ? 1 : 0;
4698 	break;
4699 #endif
4700 #ifdef SQL_BIGINT
4701     case SQL_C_SBIGINT:
4702 	p->s3type = SQLITE_INTEGER;
4703 	p->s3size = sizeof (sqlite_int64);
4704 	p->s3lival = *((sqlite_int64 *) p->param);
4705 	break;
4706     case SQL_C_UBIGINT:
4707 	p->s3type = SQLITE_INTEGER;
4708 	p->s3size = sizeof (sqlite_int64);
4709 	p->s3lival = *((sqlite_uint64 *) p->param);
4710 	break;
4711 #endif
4712     case SQL_C_FLOAT:
4713 	p->s3type = SQLITE_FLOAT;
4714 	p->s3size = sizeof (double);
4715 	p->s3dval = *((float *) p->param);
4716 	break;
4717     case SQL_C_DOUBLE:
4718 	p->s3type = SQLITE_FLOAT;
4719 	p->s3size = sizeof (double);
4720 	p->s3dval = *((double *) p->param);
4721 	break;
4722 #ifdef SQL_C_TYPE_DATE
4723     case SQL_C_TYPE_DATE:
4724 #endif
4725     case SQL_C_DATE:
4726 	sprintf(p->strbuf, "%04d-%02d-%02d",
4727 		((DATE_STRUCT *) p->param)->year,
4728 		((DATE_STRUCT *) p->param)->month,
4729 		((DATE_STRUCT *) p->param)->day);
4730 	p->s3type = SQLITE_TEXT;
4731 	p->s3size = -1;
4732 	p->s3val = p->strbuf;
4733 	break;
4734 #ifdef SQL_C_TYPE_TIME
4735     case SQL_C_TYPE_TIME:
4736 #endif
4737     case SQL_C_TIME:
4738 	sprintf(p->strbuf, "%02d:%02d:%02d",
4739 		((TIME_STRUCT *) p->param)->hour,
4740 		((TIME_STRUCT *) p->param)->minute,
4741 		((TIME_STRUCT *) p->param)->second);
4742 	p->s3type = SQLITE_TEXT;
4743 	p->s3size = -1;
4744 	p->s3val = p->strbuf;
4745 	break;
4746 #ifdef SQL_C_TYPE_TIMESTAMP
4747     case SQL_C_TYPE_TIMESTAMP:
4748 #endif
4749     case SQL_C_TIMESTAMP:
4750 	len = (int) ((TIMESTAMP_STRUCT *) p->param)->fraction;
4751 	len /= 1000000;
4752 	len = len % 1000;
4753 	if (len < 0) {
4754 	    len = 0;
4755 	}
4756 	if (p->coldef && p->coldef <= 16) {
4757 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
4758 		    ((TIMESTAMP_STRUCT *) p->param)->year,
4759 		    ((TIMESTAMP_STRUCT *) p->param)->month,
4760 		    ((TIMESTAMP_STRUCT *) p->param)->day,
4761 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
4762 		    ((TIMESTAMP_STRUCT *) p->param)->minute);
4763 	} else if (p->coldef && p->coldef <= 19) {
4764 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
4765 		    ((TIMESTAMP_STRUCT *) p->param)->year,
4766 		    ((TIMESTAMP_STRUCT *) p->param)->month,
4767 		    ((TIMESTAMP_STRUCT *) p->param)->day,
4768 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
4769 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
4770 		    ((TIMESTAMP_STRUCT *) p->param)->second);
4771 	} else {
4772 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
4773 		    ((TIMESTAMP_STRUCT *) p->param)->year,
4774 		    ((TIMESTAMP_STRUCT *) p->param)->month,
4775 		    ((TIMESTAMP_STRUCT *) p->param)->day,
4776 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
4777 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
4778 		    ((TIMESTAMP_STRUCT *) p->param)->second,
4779 		    len);
4780 	}
4781 	p->s3type = SQLITE_TEXT;
4782 	p->s3size = -1;
4783 	p->s3val = p->strbuf;
4784 	break;
4785     default:
4786     error:
4787 	setstat(s, -1, "unsupported parameter type",
4788 		(*s->ov3) ? "07009" : "S1093");
4789 	return SQL_ERROR;
4790     }
4791     return SQL_SUCCESS;
4792 }
4793 
4794 /**
4795  * Internal bind parameter on HSTMT.
4796  * @param stmt statement handle
4797  * @param pnum parameter number, starting at 1
4798  * @param iotype input/output type of parameter
4799  * @param buftype type of host variable
4800  * @param ptype
4801  * @param coldef
4802  * @param scale
4803  * @param data pointer to host variable
4804  * @param buflen length of host variable
4805  * @param len output length pointer
4806  * @result ODBC error code
4807  */
4808 
4809 static SQLRETURN
drvbindparam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLUINTEGER coldef,SQLSMALLINT scale,SQLPOINTER data,SQLINTEGER buflen,SQLLEN * len)4810 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
4811 	     SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
4812 	     SQLSMALLINT scale,
4813 	     SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
4814 {
4815     STMT *s;
4816     BINDPARM *p;
4817 
4818     if (stmt == SQL_NULL_HSTMT) {
4819 	return SQL_INVALID_HANDLE;
4820     }
4821     s = (STMT *) stmt;
4822     if (pnum == 0) {
4823 	setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
4824 	return SQL_ERROR;
4825     }
4826     if (!data && !len) {
4827 	setstat(s, -1, "invalid buffer", "HY003");
4828 	return SQL_ERROR;
4829     }
4830     --pnum;
4831     if (s->bindparms) {
4832 	if (pnum >= s->nbindparms) {
4833 	    BINDPARM *newparms;
4834 
4835 	    newparms = xrealloc(s->bindparms,
4836 				(pnum + 1) * sizeof (BINDPARM));
4837 	    if (!newparms) {
4838 outofmem:
4839 		return nomem(s);
4840 	    }
4841 	    s->bindparms = newparms;
4842 	    memset(&s->bindparms[s->nbindparms], 0,
4843 		   (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
4844 	    s->nbindparms = pnum + 1;
4845 	}
4846     } else {
4847 	int npar = max(10, pnum + 1);
4848 
4849 	s->bindparms = xmalloc(npar * sizeof (BINDPARM));
4850 	if (!s->bindparms) {
4851 	    goto outofmem;
4852 	}
4853 	memset(s->bindparms, 0, npar * sizeof (BINDPARM));
4854 	s->nbindparms = npar;
4855     }
4856     switch (buftype) {
4857     case SQL_C_STINYINT:
4858     case SQL_C_UTINYINT:
4859     case SQL_C_TINYINT:
4860 #ifdef SQL_C_BIT
4861     case SQL_C_BIT:
4862 #endif
4863 	buflen = sizeof (char);
4864 	break;
4865     case SQL_C_SHORT:
4866     case SQL_C_USHORT:
4867     case SQL_C_SSHORT:
4868 	buflen = sizeof (short);
4869 	break;
4870     case SQL_C_SLONG:
4871     case SQL_C_ULONG:
4872     case SQL_C_LONG:
4873 	buflen = sizeof (long);
4874 	break;
4875     case SQL_C_FLOAT:
4876 	buflen = sizeof (float);
4877 	break;
4878     case SQL_C_DOUBLE:
4879 	buflen = sizeof (double);
4880 	break;
4881     case SQL_C_TIMESTAMP:
4882 #ifdef SQL_C_TYPE_TIMESTAMP
4883     case SQL_C_TYPE_TIMESTAMP:
4884 #endif
4885 	buflen = sizeof (TIMESTAMP_STRUCT);
4886 	break;
4887     case SQL_C_TIME:
4888 #ifdef SQL_C_TYPE_TIME
4889     case SQL_C_TYPE_TIME:
4890 #endif
4891 	buflen = sizeof (TIME_STRUCT);
4892 	break;
4893     case SQL_C_DATE:
4894 #ifdef SQL_C_TYPE_DATE
4895     case SQL_C_TYPE_DATE:
4896 #endif
4897 	buflen = sizeof (DATE_STRUCT);
4898 	break;
4899 #ifdef SQL_C_UBIGINT
4900     case SQL_C_UBIGINT:
4901 	buflen = sizeof (SQLBIGINT);
4902 	break;
4903 #endif
4904 #ifdef SQL_C_SBIGINT
4905     case SQL_C_SBIGINT:
4906 	buflen = sizeof (SQLBIGINT);
4907 	break;
4908 #endif
4909 #ifdef SQL_C_BIGINT
4910     case SQL_C_BIGINT:
4911 	buflen = sizeof (SQLBIGINT);
4912 	break;
4913 #endif
4914     }
4915     p = &s->bindparms[pnum];
4916     p->type = buftype;
4917     p->stype = ptype;
4918     p->coldef = coldef;
4919     p->scale = scale;
4920     p->max = buflen;
4921     p->inc = buflen;
4922     p->lenp = p->lenp0 = len;
4923     p->offs = 0;
4924     p->len = 0;
4925     p->param0 = data;
4926     freep(&p->parbuf);
4927     p->param = p->param0;
4928     p->bound = 1;
4929     p->need = 0;
4930     return SQL_SUCCESS;
4931 }
4932 
4933 /**
4934  * Bind parameter on HSTMT.
4935  * @param stmt statement handle
4936  * @param pnum parameter number, starting at 1
4937  * @param iotype input/output type of parameter
4938  * @param buftype type of host variable
4939  * @param ptype
4940  * @param coldef
4941  * @param scale
4942  * @param data pointer to host variable
4943  * @param buflen length of host variable
4944  * @param len output length pointer
4945  * @result ODBC error code
4946  */
4947 
4948 SQLRETURN SQL_API
SQLBindParameter(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER data,SQLLEN buflen,SQLLEN * len)4949 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
4950 		 SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
4951 		 SQLSMALLINT scale,
4952 		 SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
4953 {
4954     SQLRETURN ret;
4955 
4956     HSTMT_LOCK(stmt);
4957     ret = drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
4958 		       scale, data, buflen, len);
4959     HSTMT_UNLOCK(stmt);
4960     return ret;
4961 }
4962 
4963 #ifndef HAVE_IODBC
4964 /**
4965  * Bind parameter on HSTMT.
4966  * @param stmt statement handle
4967  * @param pnum parameter number, starting at 1
4968  * @param vtype input/output type of parameter
4969  * @param ptype
4970  * @param lenprec
4971  * @param scale
4972  * @param val pointer to host variable
4973  * @param lenp output length pointer
4974  * @result ODBC error code
4975  */
4976 
4977 SQLRETURN SQL_API
SQLBindParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT vtype,SQLSMALLINT ptype,SQLULEN lenprec,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * lenp)4978 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
4979 	     SQLSMALLINT ptype, SQLULEN lenprec,
4980 	     SQLSMALLINT scale, SQLPOINTER val,
4981 	     SQLLEN *lenp)
4982 {
4983     SQLRETURN ret;
4984 
4985     HSTMT_LOCK(stmt);
4986     ret = drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
4987 		       lenprec, scale, val, 0, lenp);
4988     HSTMT_UNLOCK(stmt);
4989     return ret;
4990 }
4991 #endif
4992 
4993 /**
4994  * Return number of parameters.
4995  * @param stmt statement handle
4996  * @param nparam output parameter count
4997  * @result ODBC error code
4998  */
4999 
5000 SQLRETURN SQL_API
SQLNumParams(SQLHSTMT stmt,SQLSMALLINT * nparam)5001 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
5002 {
5003     STMT *s;
5004     SQLSMALLINT dummy;
5005 
5006     HSTMT_LOCK(stmt);
5007     if (stmt == SQL_NULL_HSTMT) {
5008 	return SQL_INVALID_HANDLE;
5009     }
5010     s = (STMT *) stmt;
5011     if (!nparam) {
5012 	nparam = &dummy;
5013     }
5014     *nparam = s->nparams;
5015     HSTMT_UNLOCK(stmt);
5016     return SQL_SUCCESS;
5017 }
5018 
5019 /**
5020  * Setup parameter buffer for deferred parameter.
5021  * @param s pointer to STMT
5022  * @param p pointer to BINDPARM
5023  * @result ODBC error code (success indicated by SQL_NEED_DATA)
5024  */
5025 
5026 static SQLRETURN
setupparbuf(STMT * s,BINDPARM * p)5027 setupparbuf(STMT *s, BINDPARM *p)
5028 {
5029     if (!p->parbuf) {
5030 	p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
5031 	if (p->len < 0 && p->len != SQL_NTS &&
5032 	    p->len != SQL_NULL_DATA) {
5033 	    setstat(s, -1, "invalid length", "HY009");
5034 	    return SQL_ERROR;
5035 	}
5036 	if (p->len >= 0) {
5037 	    p->parbuf = xmalloc(p->len + 1);
5038 	    if (!p->parbuf) {
5039 		return nomem(s);
5040 	    }
5041 	    p->param = p->parbuf;
5042 	} else {
5043 	    p->param = NULL;
5044 	}
5045     }
5046     return SQL_NEED_DATA;
5047 }
5048 
5049 /**
5050  * Retrieve next parameter for sending data to executing query.
5051  * @param stmt statement handle
5052  * @param pind pointer to output parameter indicator
5053  * @result ODBC error code
5054  */
5055 
5056 SQLRETURN SQL_API
SQLParamData(SQLHSTMT stmt,SQLPOINTER * pind)5057 SQLParamData(SQLHSTMT stmt, SQLPOINTER *pind)
5058 {
5059     STMT *s;
5060     int i;
5061     SQLPOINTER dummy;
5062     SQLRETURN ret;
5063 
5064     HSTMT_LOCK(stmt);
5065     if (stmt == SQL_NULL_HSTMT) {
5066 	return SQL_INVALID_HANDLE;
5067     }
5068     s = (STMT *) stmt;
5069     if (!pind) {
5070 	pind = &dummy;
5071     }
5072     for (i = 0; i < s->nparams; i++) {
5073 	BINDPARM *p = &s->bindparms[i];
5074 
5075 	if (p->need > 0) {
5076 	    *pind = (SQLPOINTER) p->param0;
5077 	    ret = setupparbuf(s, p);
5078 	    goto done;
5079 	}
5080     }
5081     ret = drvexecute(stmt, 0);
5082 done:
5083     HSTMT_UNLOCK(stmt);
5084     return ret;
5085 }
5086 
5087 /**
5088  * Return information about parameter.
5089  * @param stmt statement handle
5090  * @param pnum parameter number, starting at 1
5091  * @param dtype output type indicator
5092  * @param size output size indicator
5093  * @param decdigits output number of digits
5094  * @param nullable output NULL allowed indicator
5095  * @result ODBC error code
5096  */
5097 
5098 SQLRETURN SQL_API
SQLDescribeParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT * dtype,SQLULEN * size,SQLSMALLINT * decdigits,SQLSMALLINT * nullable)5099 SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT *dtype,
5100 		 SQLULEN *size, SQLSMALLINT *decdigits, SQLSMALLINT *nullable)
5101 {
5102     STMT *s;
5103     SQLRETURN ret = SQL_ERROR;
5104 
5105     HSTMT_LOCK(stmt);
5106     if (stmt == SQL_NULL_HSTMT) {
5107 	return SQL_INVALID_HANDLE;
5108     }
5109     s = (STMT *) stmt;
5110     --pnum;
5111     if (pnum >= s->nparams) {
5112 	setstat(s, -1, "invalid parameter index",
5113 		(*s->ov3) ? "HY000" : "S1000");
5114 	goto done;
5115     }
5116     if (dtype) {
5117 #ifdef SQL_LONGVARCHAR
5118 #ifdef WINTERFACE
5119 	*dtype = s->nowchar[0] ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
5120 #else
5121 	*dtype = SQL_LONGVARCHAR;
5122 #endif
5123 #else
5124 #ifdef WINTERFACE
5125 	*dtype = s->nowchar[0] ? SQL_VARCHAR : SQL_WVARCHAR;
5126 #else
5127 	*dtype = SQL_VARCHAR;
5128 #endif
5129 #endif
5130     }
5131     if (size) {
5132 #ifdef SQL_LONGVARCHAR
5133 	*size = 65536;
5134 #else
5135 	*size = 255;
5136 #endif
5137     }
5138     if (decdigits) {
5139 	*decdigits = 0;
5140     }
5141     if (nullable) {
5142 	*nullable = SQL_NULLABLE;
5143     }
5144     ret = SQL_SUCCESS;
5145 done:
5146     HSTMT_UNLOCK(stmt);
5147     return ret;
5148 }
5149 
5150 /**
5151  * Set information on parameter.
5152  * @param stmt statement handle
5153  * @param par parameter number, starting at 1
5154  * @param type type of host variable
5155  * @param sqltype
5156  * @param coldef
5157  * @param scale
5158  * @param val pointer to host variable
5159  * @param nval output length pointer
5160  * @result ODBC error code
5161  */
5162 
5163 SQLRETURN SQL_API
SQLSetParam(SQLHSTMT stmt,SQLUSMALLINT par,SQLSMALLINT type,SQLSMALLINT sqltype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * nval)5164 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
5165 	    SQLSMALLINT sqltype, SQLULEN coldef,
5166 	    SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
5167 {
5168     SQLRETURN ret;
5169 
5170     HSTMT_LOCK(stmt);
5171     ret = drvbindparam(stmt, par, SQL_PARAM_INPUT,
5172 		       type, sqltype, coldef, scale, val,
5173 		       SQL_SETPARAM_VALUE_MAX, nval);
5174     HSTMT_UNLOCK(stmt);
5175     return ret;
5176 }
5177 
5178 /**
5179  * Function not implemented.
5180  */
5181 
5182 SQLRETURN SQL_API
SQLParamOptions(SQLHSTMT stmt,SQLULEN rows,SQLULEN * rowp)5183 SQLParamOptions(SQLHSTMT stmt, SQLULEN rows, SQLULEN *rowp)
5184 {
5185     SQLRETURN ret;
5186 
5187     HSTMT_LOCK(stmt);
5188     ret = drvunimplstmt(stmt);
5189     HSTMT_UNLOCK(stmt);
5190     return ret;
5191 }
5192 
5193 #ifndef WINTERFACE
5194 /**
5195  * Function not implemented.
5196  */
5197 
5198 SQLRETURN SQL_API
SQLGetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)5199 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
5200 		SQLSMALLINT fieldid, SQLPOINTER value,
5201 		SQLINTEGER buflen, SQLINTEGER *strlen)
5202 {
5203     return SQL_ERROR;
5204 }
5205 #endif
5206 
5207 #ifdef WINTERFACE
5208 /**
5209  * Function not implemented.
5210  */
5211 
5212 SQLRETURN SQL_API
SQLGetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)5213 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
5214 		 SQLSMALLINT fieldid, SQLPOINTER value,
5215 		 SQLINTEGER buflen, SQLINTEGER *strlen)
5216 {
5217     return SQL_ERROR;
5218 }
5219 #endif
5220 
5221 #ifndef WINTERFACE
5222 /**
5223  * Function not implemented.
5224  */
5225 
5226 SQLRETURN SQL_API
SQLSetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)5227 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
5228 		SQLSMALLINT fieldid, SQLPOINTER value,
5229 		SQLINTEGER buflen)
5230 {
5231     return SQL_ERROR;
5232 }
5233 #endif
5234 
5235 #ifdef WINTERFACE
5236 /**
5237  * Function not implemented.
5238  */
5239 
5240 SQLRETURN SQL_API
SQLSetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)5241 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
5242 		 SQLSMALLINT fieldid, SQLPOINTER value,
5243 		 SQLINTEGER buflen)
5244 {
5245     return SQL_ERROR;
5246 }
5247 #endif
5248 
5249 #ifndef WINTERFACE
5250 /**
5251  * Function not implemented.
5252  */
5253 
5254 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)5255 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
5256 	      SQLCHAR *name, SQLSMALLINT buflen,
5257 	      SQLSMALLINT *strlen, SQLSMALLINT *type,
5258 	      SQLSMALLINT *subtype, SQLLEN *len,
5259 	      SQLSMALLINT *prec, SQLSMALLINT *scale,
5260 	      SQLSMALLINT *nullable)
5261 {
5262     return SQL_ERROR;
5263 }
5264 #endif
5265 
5266 #ifdef WINTERFACE
5267 /**
5268  * Function not implemented.
5269  */
5270 
5271 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)5272 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
5273 	       SQLWCHAR *name, SQLSMALLINT buflen,
5274 	       SQLSMALLINT *strlen, SQLSMALLINT *type,
5275 	       SQLSMALLINT *subtype, SQLLEN *len,
5276 	       SQLSMALLINT *prec, SQLSMALLINT *scale,
5277 	       SQLSMALLINT *nullable)
5278 {
5279     return SQL_ERROR;
5280 }
5281 #endif
5282 
5283 /**
5284  * Function not implemented.
5285  */
5286 
5287 SQLRETURN SQL_API
SQLSetDescRec(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT type,SQLSMALLINT subtype,SQLLEN len,SQLSMALLINT prec,SQLSMALLINT scale,SQLPOINTER data,SQLLEN * strlen,SQLLEN * indicator)5288 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
5289 	      SQLSMALLINT type, SQLSMALLINT subtype,
5290 	      SQLLEN len, SQLSMALLINT prec,
5291 	      SQLSMALLINT scale, SQLPOINTER data,
5292 	      SQLLEN *strlen, SQLLEN *indicator)
5293 {
5294     return SQL_ERROR;
5295 }
5296 
5297 /**
5298  * Setup empty result set from constant column specification.
5299  * @param stmt statement handle
5300  * @param colspec column specification array (default, ODBC2)
5301  * @param ncols number of columns (default, ODBC2)
5302  * @param colspec3 column specification array (ODBC3)
5303  * @param ncols3 number of columns (ODBC3)
5304  * @param nret returns number of columns
5305  * @result ODBC error code
5306  */
5307 
5308 static SQLRETURN
mkresultset(HSTMT stmt,COL * colspec,int ncols,COL * colspec3,int ncols3,int * nret)5309 mkresultset(HSTMT stmt, COL *colspec, int ncols, COL *colspec3,
5310 	    int ncols3, int *nret)
5311 {
5312     STMT *s;
5313     DBC *d;
5314 
5315     if (stmt == SQL_NULL_HSTMT) {
5316 	return SQL_INVALID_HANDLE;
5317     }
5318     s = (STMT *) stmt;
5319     if (s->dbc == SQL_NULL_HDBC) {
5320 noconn:
5321 	return noconn(s);
5322     }
5323     d = (DBC *) s->dbc;
5324     if (!d->sqlite) {
5325 	goto noconn;
5326     }
5327     s3stmt_end_if(s);
5328     freeresult(s, 0);
5329     if (colspec3 && *s->ov3) {
5330 	s->ncols = ncols3;
5331 	s->cols = colspec3;
5332     } else {
5333 	s->ncols = ncols;
5334 	s->cols = colspec;
5335     }
5336     mkbindcols(s, s->ncols);
5337     s->nowchar[1] = 1;
5338     s->nrows = 0;
5339     s->rowp = -1;
5340     s->isselect = -1;
5341     if (nret) {
5342 	*nret = s->ncols;
5343     }
5344     return SQL_SUCCESS;
5345 }
5346 
5347 /**
5348  * Columns for result set of SQLTablePrivileges().
5349  */
5350 
5351 static COL tablePrivSpec2[] = {
5352     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5353     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
5354     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5355     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5356     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5357     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
5358     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
5359 };
5360 
5361 static COL tablePrivSpec3[] = {
5362     { "SYSTEM", "TABLEPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
5363     { "SYSTEM", "TABLEPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
5364     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5365     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5366     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5367     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
5368     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
5369 };
5370 
5371 /**
5372  * Retrieve privileges on tables and/or views.
5373  * @param stmt statement handle
5374  * @param cat catalog name/pattern or NULL
5375  * @param catLen length of catalog name/pattern or SQL_NTS
5376  * @param schema schema name/pattern or NULL
5377  * @param schemaLen length of schema name/pattern or SQL_NTS
5378  * @param table table name/pattern or NULL
5379  * @param tableLen length of table name/pattern or SQL_NTS
5380  * @result ODBC error code
5381  */
5382 
5383 static SQLRETURN
drvtableprivileges(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5384 drvtableprivileges(SQLHSTMT stmt,
5385 		   SQLCHAR *cat, SQLSMALLINT catLen,
5386 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
5387 		   SQLCHAR *table, SQLSMALLINT tableLen)
5388 {
5389     SQLRETURN ret;
5390     STMT *s;
5391     DBC *d;
5392     int ncols, rc, size, npatt;
5393     char *errp = NULL, *sql, tname[512];
5394 
5395     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
5396 		      tablePrivSpec3, array_size(tablePrivSpec3), NULL);
5397     if (ret != SQL_SUCCESS) {
5398 	return ret;
5399     }
5400     s = (STMT *) stmt;
5401     d = (DBC *) s->dbc;
5402     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
5403 	table = NULL;
5404 	goto doit;
5405     }
5406     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
5407 	schema[0] == '%') {
5408 	if ((!cat || catLen == 0 || !cat[0]) &&
5409 	    (!table || tableLen == 0 || !table[0])) {
5410 	    table = NULL;
5411 	    goto doit;
5412 	}
5413     }
5414 doit:
5415     if (!table) {
5416 	size = 1;
5417 	tname[0] = '%';
5418     } else {
5419 	if (tableLen == SQL_NTS) {
5420 	    size = sizeof (tname) - 1;
5421 	} else {
5422 	    size = min(sizeof (tname) - 1, tableLen);
5423 	}
5424 	strncpy(tname, (char *) table, size);
5425     }
5426     tname[size] = '\0';
5427     npatt = unescpat(tname);
5428 #if defined(_WIN32) || defined(_WIN64)
5429     sql = sqlite3_mprintf("select %s as 'TABLE_QUALIFIER', "
5430 			  "%s as 'TABLE_OWNER', "
5431 			  "tbl_name as 'TABLE_NAME', "
5432 			  "'' as 'GRANTOR', "
5433 			  "'' as 'GRANTEE', "
5434 			  "'SELECT' AS 'PRIVILEGE', "
5435 			  "NULL as 'IS_GRANTABLE' "
5436 			  "from sqlite_master where "
5437 			  "(type = 'table' or type = 'view') "
5438 			  "and tbl_name %s %Q "
5439 			  "UNION "
5440 			  "select %s as 'TABLE_QUALIFIER', "
5441 			  "%s as 'TABLE_OWNER', "
5442 			  "tbl_name as 'TABLE_NAME', "
5443 			  "'' as 'GRANTOR', "
5444 			  "'' as 'GRANTEE', "
5445 			  "'UPDATE' AS 'PRIVILEGE', "
5446 			  "NULL as 'IS_GRANTABLE' "
5447 			  "from sqlite_master where "
5448 			  "(type = 'table' or type = 'view') "
5449 			  "and tbl_name %s %Q "
5450 			  "UNION "
5451 			  "select %s as 'TABLE_QUALIFIER', "
5452 			  "%s as 'TABLE_OWNER', "
5453 			  "tbl_name as 'TABLE_NAME', "
5454 			  "'' as 'GRANTOR', "
5455 			  "'' as 'GRANTEE', "
5456 			  "'DELETE' AS 'PRIVILEGE', "
5457 			  "NULL as 'IS_GRANTABLE' "
5458 			  "from sqlite_master where "
5459 			  "(type = 'table' or type = 'view') "
5460 			  "and tbl_name %s %Q "
5461 			  "UNION "
5462 			  "select %s as 'TABLE_QUALIFIER', "
5463 			  "%s as 'TABLE_OWNER', "
5464 			  "tbl_name as 'TABLE_NAME', "
5465 			  "'' as 'GRANTOR', "
5466 			  "'' as 'GRANTEE', "
5467 			  "'INSERT' AS 'PRIVILEGE', "
5468 			  "NULL as 'IS_GRANTABLE' "
5469 			  "from sqlite_master where "
5470 			  "(type = 'table' or type = 'view') "
5471 			  "and tbl_name %s %Q "
5472 			  "UNION "
5473 			  "select %s as 'TABLE_QUALIFIER', "
5474 			  "%s as 'TABLE_OWNER', "
5475 			  "tbl_name as 'TABLE_NAME', "
5476 			  "'' as 'GRANTOR', "
5477 			  "'' as 'GRANTEE', "
5478 			  "'REFERENCES' AS 'PRIVILEGE', "
5479 			  "NULL as 'IS_GRANTABLE' "
5480 			  "from sqlite_master where "
5481 			  "(type = 'table' or type = 'view') "
5482 			  "and tbl_name %s %Q",
5483 			  d->xcelqrx ? "''" : "NULL",
5484 			  d->xcelqrx ? "'main'" : "NULL",
5485 			  npatt ? "like" : "=", tname,
5486 			  d->xcelqrx ? "''" : "NULL",
5487 			  d->xcelqrx ? "'main'" : "NULL",
5488 			  npatt ? "like" : "=", tname,
5489 			  d->xcelqrx ? "''" : "NULL",
5490 			  d->xcelqrx ? "'main'" : "NULL",
5491 			  npatt ? "like" : "=", tname,
5492 			  d->xcelqrx ? "''" : "NULL",
5493 			  d->xcelqrx ? "'main'" : "NULL",
5494 			  npatt ? "like" : "=", tname,
5495 			  d->xcelqrx ? "''" : "NULL",
5496 			  d->xcelqrx ? "'main'" : "NULL",
5497 			  npatt ? "like" : "=", tname);
5498 #else
5499     sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
5500 			  "NULL as 'TABLE_OWNER', "
5501 			  "tbl_name as 'TABLE_NAME', "
5502 			  "'' as 'GRANTOR', "
5503 			  "'' as 'GRANTEE', "
5504 			  "'SELECT' AS 'PRIVILEGE', "
5505 			  "NULL as 'IS_GRANTABLE' "
5506 			  "from sqlite_master where "
5507 			  "(type = 'table' or type = 'view') "
5508 			  "and tbl_name %s %Q "
5509 			  "UNION "
5510 			  "select NULL as 'TABLE_QUALIFIER', "
5511 			  "NULL as 'TABLE_OWNER', "
5512 			  "tbl_name as 'TABLE_NAME', "
5513 			  "'' as 'GRANTOR', "
5514 			  "'' as 'GRANTEE', "
5515 			  "'UPDATE' AS 'PRIVILEGE', "
5516 			  "NULL as 'IS_GRANTABLE' "
5517 			  "from sqlite_master where "
5518 			  "(type = 'table' or type = 'view') "
5519 			  "and tbl_name %s %Q "
5520 			  "UNION "
5521 			  "select NULL as 'TABLE_QUALIFIER', "
5522 			  "NULL as 'TABLE_OWNER', "
5523 			  "tbl_name as 'TABLE_NAME', "
5524 			  "'' as 'GRANTOR', "
5525 			  "'' as 'GRANTEE', "
5526 			  "'DELETE' AS 'PRIVILEGE', "
5527 			  "NULL as 'IS_GRANTABLE' "
5528 			  "from sqlite_master where "
5529 			  "(type = 'table' or type = 'view') "
5530 			  "and tbl_name %s %Q "
5531 			  "UNION "
5532 			  "select NULL as 'TABLE_QUALIFIER', "
5533 			  "NULL as 'TABLE_OWNER', "
5534 			  "tbl_name as 'TABLE_NAME', "
5535 			  "'' as 'GRANTOR', "
5536 			  "'' as 'GRANTEE', "
5537 			  "'INSERT' AS 'PRIVILEGE', "
5538 			  "NULL as 'IS_GRANTABLE' "
5539 			  "from sqlite_master where "
5540 			  "(type = 'table' or type = 'view') "
5541 			  "and tbl_name %s %Q "
5542 			  "UNION "
5543 			  "select NULL as 'TABLE_QUALIFIER', "
5544 			  "NULL as 'TABLE_OWNER', "
5545 			  "tbl_name as 'TABLE_NAME', "
5546 			  "'' as 'GRANTOR', "
5547 			  "'' as 'GRANTEE', "
5548 			  "'REFERENCES' AS 'PRIVILEGE', "
5549 			  "NULL as 'IS_GRANTABLE' "
5550 			  "from sqlite_master where "
5551 			  "(type = 'table' or type = 'view') "
5552 			  "and tbl_name %s %Q",
5553 			  npatt ? "like" : "=", tname,
5554 			  npatt ? "like" : "=", tname,
5555 			  npatt ? "like" : "=", tname,
5556 			  npatt ? "like" : "=", tname,
5557 			  npatt ? "like" : "=", tname);
5558 #endif
5559     if (!sql) {
5560 	return nomem(s);
5561     }
5562     ret = starttran(s);
5563     if (ret != SQL_SUCCESS) {
5564 	sqlite3_free(sql);
5565 	return ret;
5566     }
5567     dbtraceapi(d, "sqlite3_get_table", sql);
5568     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
5569     sqlite3_free(sql);
5570     if (rc == SQLITE_OK) {
5571 	if (ncols != s->ncols) {
5572 	    freeresult(s, 0);
5573 	    s->nrows = 0;
5574 	} else {
5575 	    s->rowfree = sqlite3_free_table;
5576 	}
5577     } else {
5578 	s->nrows = 0;
5579 	s->rows = NULL;
5580 	s->rowfree = NULL;
5581     }
5582     if (errp) {
5583 	sqlite3_free(errp);
5584 	errp = NULL;
5585     }
5586     s->rowp = -1;
5587     return SQL_SUCCESS;
5588 }
5589 
5590 
5591 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
5592 /**
5593  * Retrieve privileges on tables and/or views.
5594  * @param stmt statement handle
5595  * @param catalog catalog name/pattern or NULL
5596  * @param catalogLen length of catalog name/pattern or SQL_NTS
5597  * @param schema schema name/pattern or NULL
5598  * @param schemaLen length of schema name/pattern or SQL_NTS
5599  * @param table table name/pattern or NULL
5600  * @param tableLen length of table name/pattern or SQL_NTS
5601  * @result ODBC error code
5602  */
5603 
5604 SQLRETURN SQL_API
SQLTablePrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5605 SQLTablePrivileges(SQLHSTMT stmt,
5606 		   SQLCHAR *catalog, SQLSMALLINT catalogLen,
5607 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
5608 		   SQLCHAR *table, SQLSMALLINT tableLen)
5609 {
5610 #if defined(_WIN32) || defined(_WIN64)
5611     char *c = NULL, *s = NULL, *t = NULL;
5612 #endif
5613     SQLRETURN ret;
5614 
5615     HSTMT_LOCK(stmt);
5616 #if defined(_WIN32) || defined(_WIN64)
5617     if (!((STMT *) stmt)->oemcp[0]) {
5618 	ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
5619 				 table, tableLen);
5620 	goto done2;
5621     }
5622     if (catalog) {
5623 	c = wmb_to_utf_c((char *) catalog, catalogLen);
5624 	if (!c) {
5625 	    ret = nomem((STMT *) stmt);
5626 	    goto done;
5627 	}
5628     }
5629     if (schema) {
5630 	s = wmb_to_utf_c((char *) schema, schemaLen);
5631 	if (!s) {
5632 	    ret = nomem((STMT *) stmt);
5633 	    goto done;
5634 	}
5635     }
5636     if (table) {
5637 	t = wmb_to_utf_c((char *) table, tableLen);
5638 	if (!t) {
5639 	    ret = nomem((STMT *) stmt);
5640 	    goto done;
5641 	}
5642     }
5643     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
5644 			     (SQLCHAR *) s, SQL_NTS,
5645 			     (SQLCHAR *) t, SQL_NTS);
5646 #else
5647     ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
5648 			     table, tableLen);
5649 #endif
5650 #if defined(_WIN32) || defined(_WIN64)
5651 done:
5652     uc_free(t);
5653     uc_free(s);
5654     uc_free(c);
5655 done2:
5656     ;
5657 #endif
5658     HSTMT_UNLOCK(stmt);
5659     return ret;
5660 }
5661 #endif
5662 
5663 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
5664 #ifdef WINTERFACE
5665 /**
5666  * Retrieve privileges on tables and/or views (UNICODE version).
5667  * @param stmt statement handle
5668  * @param catalog catalog name/pattern or NULL
5669  * @param catalogLen length of catalog name/pattern or SQL_NTS
5670  * @param schema schema name/pattern or NULL
5671  * @param schemaLen length of schema name/pattern or SQL_NTS
5672  * @param table table name/pattern or NULL
5673  * @param tableLen length of table name/pattern or SQL_NTS
5674  * @result ODBC error code
5675  */
5676 
5677 SQLRETURN SQL_API
SQLTablePrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)5678 SQLTablePrivilegesW(SQLHSTMT stmt,
5679 		    SQLWCHAR *catalog, SQLSMALLINT catalogLen,
5680 		    SQLWCHAR *schema, SQLSMALLINT schemaLen,
5681 		    SQLWCHAR *table, SQLSMALLINT tableLen)
5682 {
5683     char *c = NULL, *s = NULL, *t = NULL;
5684     SQLRETURN ret;
5685 
5686     HSTMT_LOCK(stmt);
5687     if (catalog) {
5688 	c = uc_to_utf_c(catalog, catalogLen);
5689 	if (!c) {
5690 	    ret = nomem((STMT *) stmt);
5691 	    goto done;
5692 	}
5693     }
5694     if (schema) {
5695 	s = uc_to_utf_c(schema, schemaLen);
5696 	if (!s) {
5697 	    ret = nomem((STMT *) stmt);
5698 	    goto done;
5699 	}
5700     }
5701     if (table) {
5702 	t = uc_to_utf_c(table, tableLen);
5703 	if (!t) {
5704 	    ret = nomem((STMT *) stmt);
5705 	    goto done;
5706 	}
5707     }
5708     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
5709 			     (SQLCHAR *) s, SQL_NTS,
5710 			     (SQLCHAR *) t, SQL_NTS);
5711 done:
5712     uc_free(t);
5713     uc_free(s);
5714     uc_free(c);
5715     HSTMT_UNLOCK(stmt);
5716     return ret;
5717 }
5718 #endif
5719 #endif
5720 
5721 /**
5722  * Columns for result set of SQLColumnPrivileges().
5723  */
5724 
5725 static COL colPrivSpec2[] = {
5726     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5727     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
5728     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5729     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5730     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5731     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5732     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
5733 };
5734 
5735 static COL colPrivSpec3[] = {
5736     { "SYSTEM", "COLPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
5737     { "SYSTEM", "COLPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
5738     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5739     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5740     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5741     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5742     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
5743 };
5744 
5745 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
5746 /**
5747  * Retrieve privileges on columns.
5748  * @param stmt statement handle
5749  * @param catalog catalog name/pattern or NULL
5750  * @param catalogLen length of catalog name/pattern or SQL_NTS
5751  * @param schema schema name/pattern or NULL
5752  * @param schemaLen length of schema name/pattern or SQL_NTS
5753  * @param table table name/pattern or NULL
5754  * @param tableLen length of table name/pattern or SQL_NTS
5755  * @param column column name or NULL
5756  * @param columnLen length of column name or SQL_NTS
5757  * @result ODBC error code
5758  */
5759 
5760 SQLRETURN SQL_API
SQLColumnPrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * column,SQLSMALLINT columnLen)5761 SQLColumnPrivileges(SQLHSTMT stmt,
5762 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
5763 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
5764 		    SQLCHAR *table, SQLSMALLINT tableLen,
5765 		    SQLCHAR *column, SQLSMALLINT columnLen)
5766 {
5767     SQLRETURN ret;
5768 
5769     HSTMT_LOCK(stmt);
5770     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
5771 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
5772     HSTMT_UNLOCK(stmt);
5773     return ret;
5774 }
5775 #endif
5776 
5777 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
5778 #ifdef WINTERFACE
5779 /**
5780  * Retrieve privileges on columns (UNICODE version).
5781  * @param stmt statement handle
5782  * @param catalog catalog name/pattern or NULL
5783  * @param catalogLen length of catalog name/pattern or SQL_NTS
5784  * @param schema schema name/pattern or NULL
5785  * @param schemaLen length of schema name/pattern or SQL_NTS
5786  * @param table table name/pattern or NULL
5787  * @param tableLen length of table name/pattern or SQL_NTS
5788  * @param column column name or NULL
5789  * @param columnLen length of column name or SQL_NTS
5790  * @result ODBC error code
5791  */
5792 
5793 SQLRETURN SQL_API
SQLColumnPrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * column,SQLSMALLINT columnLen)5794 SQLColumnPrivilegesW(SQLHSTMT stmt,
5795 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
5796 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
5797 		     SQLWCHAR *table, SQLSMALLINT tableLen,
5798 		     SQLWCHAR *column, SQLSMALLINT columnLen)
5799 {
5800     SQLRETURN ret;
5801 
5802     HSTMT_LOCK(stmt);
5803     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
5804 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
5805     HSTMT_UNLOCK(stmt);
5806     return ret;
5807 }
5808 #endif
5809 #endif
5810 
5811 /**
5812  * Columns for result set of SQLPrimaryKeys().
5813  */
5814 
5815 static COL pkeySpec2[] = {
5816     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5817     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
5818     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
5819     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5820     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
5821     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
5822 };
5823 
5824 static COL pkeySpec3[] = {
5825     { "SYSTEM", "PRIMARYKEY", "TABLE_CAT", SCOL_VARCHAR, 50 },
5826     { "SYSTEM", "PRIMARYKEY", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
5827     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
5828     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5829     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
5830     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
5831 };
5832 
5833 /**
5834  * Internal retrieve information about indexed columns.
5835  * @param stmt statement handle
5836  * @param cat catalog name/pattern or NULL
5837  * @param catLen length of catalog name/pattern or SQL_NTS
5838  * @param schema schema name/pattern or NULL
5839  * @param schemaLen length of schema name/pattern or SQL_NTS
5840  * @param table table name/pattern or NULL
5841  * @param tableLen length of table name/pattern or SQL_NTS
5842  * @result ODBC error code
5843  */
5844 
5845 static SQLRETURN
drvprimarykeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5846 drvprimarykeys(SQLHSTMT stmt,
5847 	       SQLCHAR *cat, SQLSMALLINT catLen,
5848 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
5849 	       SQLCHAR *table, SQLSMALLINT tableLen)
5850 {
5851     STMT *s;
5852     DBC *d;
5853     SQLRETURN sret;
5854     int i, asize, ret, nrows, ncols, nrows2 = 0, ncols2 = 0;
5855     int namec = -1, uniquec = -1, namec2 = -1, uniquec2 = -1, offs, seq = 1;
5856     PTRDIFF_T size;
5857     char **rowp = NULL, **rowp2 = NULL, *errp = NULL, *sql, tname[512];
5858 
5859     sret = mkresultset(stmt, pkeySpec2, array_size(pkeySpec2),
5860 		       pkeySpec3, array_size(pkeySpec3), &asize);
5861     if (sret != SQL_SUCCESS) {
5862 	return sret;
5863     }
5864     s = (STMT *) stmt;
5865     d = (DBC *) s->dbc;
5866     if (!table || table[0] == '\0' || table[0] == '%') {
5867 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
5868 	return SQL_ERROR;
5869     }
5870     if (tableLen == SQL_NTS) {
5871 	size = sizeof (tname) - 1;
5872     } else {
5873 	size = min(sizeof (tname) - 1, tableLen);
5874     }
5875     strncpy(tname, (char *) table, size);
5876     tname[size] = '\0';
5877     unescpat(tname);
5878     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
5879     if (!sql) {
5880 	return nomem(s);
5881     }
5882     sret = starttran(s);
5883     if (sret != SQL_SUCCESS) {
5884 	sqlite3_free(sql);
5885 	return sret;
5886     }
5887     dbtraceapi(d, "sqlite3_get_table", sql);
5888     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
5889     sqlite3_free(sql);
5890     if (ret != SQLITE_OK) {
5891 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5892 		errp ? errp : "unknown error", ret);
5893 	if (errp) {
5894 	    sqlite3_free(errp);
5895 	    errp = NULL;
5896 	}
5897 	return SQL_ERROR;
5898     }
5899     if (errp) {
5900 	sqlite3_free(errp);
5901 	errp = NULL;
5902     }
5903     size = 0;
5904     if (ncols * nrows > 0) {
5905 	int typec;
5906 
5907 	namec = findcol(rowp, ncols, "name");
5908 	uniquec = findcol(rowp, ncols, "pk");
5909 	typec = findcol(rowp, ncols, "type");
5910 	if (namec >= 0 && uniquec >= 0 && typec >= 0) {
5911 	    for (i = 1; i <= nrows; i++) {
5912 		if (*rowp[i * ncols + uniquec] != '0') {
5913 		    size++;
5914 		}
5915 	    }
5916 	}
5917     }
5918     if (size == 0) {
5919 	sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
5920 	if (!sql) {
5921 	    sqlite3_free_table(rowp);
5922 	    return nomem(s);
5923 	}
5924 	dbtraceapi(d, "sqlite3_get_table", sql);
5925 	ret = sqlite3_get_table(d->sqlite, sql, &rowp2, &nrows2, &ncols2,
5926 				&errp);
5927 	sqlite3_free(sql);
5928 	if (ret != SQLITE_OK) {
5929 	    sqlite3_free_table(rowp);
5930 	    sqlite3_free_table(rowp2);
5931 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5932 		    errp ? errp : "unknown error", ret);
5933 	    if (errp) {
5934 		sqlite3_free(errp);
5935 		errp = NULL;
5936 	    }
5937 	    return SQL_ERROR;
5938 	}
5939 	if (errp) {
5940 	    sqlite3_free(errp);
5941 	    errp = NULL;
5942 	}
5943     }
5944     if (ncols2 * nrows2 > 0) {
5945 	namec2 = findcol(rowp2, ncols2, "name");
5946 	uniquec2 = findcol(rowp2, ncols2, "unique");
5947 	if (namec2 >= 0 && uniquec2 >=  0) {
5948 	    for (i = 1; i <= nrows2; i++) {
5949 		int nnrows, nncols, nlen = 0;
5950 		char **rowpp;
5951 
5952 		if (rowp2[i * ncols2 + namec2]) {
5953 		    nlen = strlen(rowp2[i * ncols2 + namec2]);
5954 		}
5955 		if (nlen < 17 ||
5956 		    strncmp(rowp2[i * ncols2 + namec2],
5957 			    "sqlite_autoindex_", 17)) {
5958 		    continue;
5959 		}
5960 		if (*rowp2[i * ncols2 + uniquec2] != '0') {
5961 		    ret = SQLITE_ERROR;
5962 		    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
5963 					  rowp2[i * ncols2 + namec2]);
5964 		    if (sql) {
5965 			dbtraceapi(d, "sqlite3_get_table", sql);
5966 			ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
5967 						&nnrows, &nncols, NULL);
5968 			sqlite3_free(sql);
5969 		    }
5970 		    if (ret == SQLITE_OK) {
5971 			size += nnrows;
5972 			sqlite3_free_table(rowpp);
5973 		    }
5974 		}
5975 	    }
5976 	}
5977     }
5978     if (size == 0) {
5979 	sqlite3_free_table(rowp);
5980 	sqlite3_free_table(rowp2);
5981 	return SQL_SUCCESS;
5982     }
5983     s->nrows = size;
5984     size = (size + 1) * asize;
5985     s->rows = xmalloc((size + 1) * sizeof (char *));
5986     if (!s->rows) {
5987 	s->nrows = 0;
5988 	sqlite3_free_table(rowp);
5989 	sqlite3_free_table(rowp2);
5990 	return nomem(s);
5991     }
5992     s->rows[0] = (char *) size;
5993     s->rows += 1;
5994     memset(s->rows, 0, sizeof (char *) * size);
5995     s->rowfree = freerows;
5996     offs = s->ncols;
5997     if (rowp) {
5998 	for (i = 1; i <= nrows; i++) {
5999 	    if (*rowp[i * ncols + uniquec] != '0') {
6000 		char buf[32];
6001 
6002 		s->rows[offs + 0] = xstrdup("");
6003 #if defined(_WIN32) || defined(_WIN64)
6004 		s->rows[offs + 1] = xstrdup(d->xcelqrx ? "main" : "");
6005 #else
6006 		s->rows[offs + 1] = xstrdup("");
6007 #endif
6008 		s->rows[offs + 2] = xstrdup(tname);
6009 		s->rows[offs + 3] = xstrdup(rowp[i * ncols + namec]);
6010 		sprintf(buf, "%d", seq++);
6011 		s->rows[offs + 4] = xstrdup(buf);
6012 		offs += s->ncols;
6013 	    }
6014 	}
6015     }
6016     if (rowp2) {
6017 	for (i = 1; i <= nrows2; i++) {
6018 	    int nnrows, nncols, nlen = 0;
6019 	    char **rowpp;
6020 
6021 	    if (rowp2[i * ncols2 + namec2]) {
6022 		nlen = strlen(rowp2[i * ncols2 + namec2]);
6023 	    }
6024 	    if (nlen < 17 ||
6025 		strncmp(rowp2[i * ncols2 + namec2], "sqlite_autoindex_", 17)) {
6026 		continue;
6027 	    }
6028 	    if (*rowp2[i * ncols2 + uniquec2] != '0') {
6029 		int k;
6030 
6031 		ret = SQLITE_ERROR;
6032 		sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
6033 				      rowp2[i * ncols2 + namec2]);
6034 		if (sql) {
6035 		    dbtraceapi(d, "sqlite3_get_table", sql);
6036 		    ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6037 					    &nnrows, &nncols, NULL);
6038 		    sqlite3_free(sql);
6039 		}
6040 		if (ret != SQLITE_OK) {
6041 		    continue;
6042 		}
6043 		for (k = 0; nnrows && k < nncols; k++) {
6044 		    if (strcmp(rowpp[k], "name") == 0) {
6045 			int m;
6046 
6047 			for (m = 1; m <= nnrows; m++) {
6048 			    int roffs = offs + (m - 1) * s->ncols;
6049 
6050 			    s->rows[roffs + 0] = xstrdup("");
6051 #if defined(_WIN32) || defined(_WIN64)
6052 			    s->rows[roffs + 1] =
6053 				xstrdup(d->xcelqrx ? "main" : "");
6054 #else
6055 			    s->rows[roffs + 1] = xstrdup("");
6056 #endif
6057 			    s->rows[roffs + 2] = xstrdup(tname);
6058 			    s->rows[roffs + 3] =
6059 				xstrdup(rowpp[m * nncols + k]);
6060 			    s->rows[roffs + 5] =
6061 				xstrdup(rowp2[i * ncols2 + namec2]);
6062 			}
6063 		    } else if (strcmp(rowpp[k], "seqno") == 0) {
6064 			int m;
6065 
6066 			for (m = 1; m <= nnrows; m++) {
6067 			    int roffs = offs + (m - 1) * s->ncols;
6068 			    int pos = m - 1;
6069 			    char buf[32];
6070 
6071 			    sscanf(rowpp[m * nncols + k], "%d", &pos);
6072 			    sprintf(buf, "%d", pos + 1);
6073 			    s->rows[roffs + 4] = xstrdup(buf);
6074 			}
6075 		    }
6076 		}
6077 		offs += nnrows * s->ncols;
6078 		sqlite3_free_table(rowpp);
6079 	    }
6080 	}
6081     }
6082     sqlite3_free_table(rowp);
6083     sqlite3_free_table(rowp2);
6084     return SQL_SUCCESS;
6085 }
6086 
6087 #ifndef WINTERFACE
6088 /**
6089  * Retrieve information about indexed columns.
6090  * @param stmt statement handle
6091  * @param cat catalog name/pattern or NULL
6092  * @param catLen length of catalog name/pattern or SQL_NTS
6093  * @param schema schema name/pattern or NULL
6094  * @param schemaLen length of schema name/pattern or SQL_NTS
6095  * @param table table name/pattern or NULL
6096  * @param tableLen length of table name/pattern or SQL_NTS
6097  * @result ODBC error code
6098  */
6099 
6100 SQLRETURN SQL_API
SQLPrimaryKeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)6101 SQLPrimaryKeys(SQLHSTMT stmt,
6102 	       SQLCHAR *cat, SQLSMALLINT catLen,
6103 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
6104 	       SQLCHAR *table, SQLSMALLINT tableLen)
6105 {
6106 #if defined(_WIN32) || defined(_WIN64)
6107     char *c = NULL, *s = NULL, *t = NULL;
6108 #endif
6109     SQLRETURN ret;
6110 
6111     HSTMT_LOCK(stmt);
6112 #if defined(_WIN32) || defined(_WIN64)
6113     if (!((STMT *) stmt)->oemcp[0]) {
6114 	ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
6115 			     table, tableLen);
6116 	goto done2;
6117     }
6118     if (cat) {
6119 	c = wmb_to_utf_c((char *) cat, catLen);
6120 	if (!c) {
6121 	    ret = nomem((STMT *) stmt);
6122 	    goto done;
6123 	}
6124     }
6125     if (schema) {
6126 	s = wmb_to_utf_c((char *) schema, schemaLen);
6127 	if (!s) {
6128 	    ret = nomem((STMT *) stmt);
6129 	    goto done;
6130 	}
6131     }
6132     if (table) {
6133 	t = wmb_to_utf_c((char *) table, tableLen);
6134 	if (!t) {
6135 	    ret = nomem((STMT *) stmt);
6136 	    goto done;
6137 	}
6138     }
6139     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
6140 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
6141 #else
6142     ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
6143 			 table, tableLen);
6144 #endif
6145 #if defined(_WIN32) || defined(_WIN64)
6146 done:
6147     uc_free(t);
6148     uc_free(s);
6149     uc_free(c);
6150 done2:
6151     ;
6152 #endif
6153     HSTMT_UNLOCK(stmt);
6154     return ret;
6155 }
6156 #endif
6157 
6158 #ifdef WINTERFACE
6159 /**
6160  * Retrieve information about indexed columns (UNICODE version).
6161  * @param stmt statement handle
6162  * @param cat catalog name/pattern or NULL
6163  * @param catLen length of catalog name/pattern or SQL_NTS
6164  * @param schema schema name/pattern or NULL
6165  * @param schemaLen length of schema name/pattern or SQL_NTS
6166  * @param table table name/pattern or NULL
6167  * @param tableLen length of table name/pattern or SQL_NTS
6168  * @result ODBC error code
6169  */
6170 
6171 SQLRETURN SQL_API
SQLPrimaryKeysW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)6172 SQLPrimaryKeysW(SQLHSTMT stmt,
6173 		SQLWCHAR *cat, SQLSMALLINT catLen,
6174 		SQLWCHAR *schema, SQLSMALLINT schemaLen,
6175 		SQLWCHAR *table, SQLSMALLINT tableLen)
6176 {
6177     char *c = NULL, *s = NULL, *t = NULL;
6178     SQLRETURN ret;
6179 
6180     HSTMT_LOCK(stmt);
6181     if (cat) {
6182 	c = uc_to_utf_c(cat, catLen);
6183 	if (!c) {
6184 	    ret = nomem((STMT *) stmt);
6185 	    goto done;
6186 	}
6187     }
6188     if (schema) {
6189 	s = uc_to_utf_c(schema, schemaLen);
6190 	if (!s) {
6191 	    ret = nomem((STMT *) stmt);
6192 	    goto done;
6193 	}
6194     }
6195     if (table) {
6196 	t = uc_to_utf_c(table, tableLen);
6197 	if (!t) {
6198 	    ret = nomem((STMT *) stmt);
6199 	    goto done;
6200 	}
6201     }
6202     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
6203 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
6204 done:
6205     uc_free(t);
6206     uc_free(s);
6207     uc_free(c);
6208     HSTMT_UNLOCK(stmt);
6209     return ret;
6210 }
6211 #endif
6212 
6213 /**
6214  * Columns for result set of SQLSpecialColumns().
6215  */
6216 
6217 static COL scolSpec2[] = {
6218     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
6219     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6220     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
6221     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
6222     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
6223     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
6224     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
6225     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
6226     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
6227 };
6228 
6229 static COL scolSpec3[] = {
6230     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
6231     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6232     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
6233     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
6234     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
6235     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
6236     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
6237     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
6238     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
6239 };
6240 
6241 /**
6242  * Internal retrieve information about indexed columns.
6243  * @param stmt statement handle
6244  * @param id type of information, e.g. best row id
6245  * @param cat catalog name/pattern or NULL
6246  * @param catLen length of catalog name/pattern or SQL_NTS
6247  * @param schema schema name/pattern or NULL
6248  * @param schemaLen length of schema name/pattern or SQL_NTS
6249  * @param table table name/pattern or NULL
6250  * @param tableLen length of table name/pattern or SQL_NTS
6251  * @param scope
6252  * @param nullable
6253  * @result ODBC error code
6254  */
6255 
6256 static SQLRETURN
drvspecialcolumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6257 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
6258 		  SQLCHAR *cat, SQLSMALLINT catLen,
6259 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
6260 		  SQLCHAR *table, SQLSMALLINT tableLen,
6261 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
6262 {
6263     STMT *s;
6264     DBC *d;
6265     SQLRETURN sret;
6266     int i, asize, ret, nrows, ncols, nnnrows, nnncols, offs;
6267     PTRDIFF_T size;
6268     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
6269     int notnullcc = -1, mkrowid = 0;
6270     char *errp = NULL, *sql, tname[512];
6271     char **rowp = NULL, **rowppp = NULL;
6272 
6273     sret = mkresultset(stmt, scolSpec2, array_size(scolSpec2),
6274 		       scolSpec3, array_size(scolSpec3), &asize);
6275     if (sret != SQL_SUCCESS) {
6276 	return sret;
6277     }
6278     s = (STMT *) stmt;
6279     d = (DBC *) s->dbc;
6280     if (!table || table[0] == '\0' || table[0] == '%') {
6281 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
6282 	return SQL_ERROR;
6283     }
6284     if (tableLen == SQL_NTS) {
6285 	size = sizeof (tname) - 1;
6286     } else {
6287 	size = min(sizeof (tname) - 1, tableLen);
6288     }
6289     strncpy(tname, (char *) table, size);
6290     tname[size] = '\0';
6291     unescpat(tname);
6292     if (id != SQL_BEST_ROWID) {
6293 	return SQL_SUCCESS;
6294     }
6295     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
6296     if (!sql) {
6297 	return nomem(s);
6298     }
6299     sret = starttran(s);
6300     if (sret != SQL_SUCCESS) {
6301 	sqlite3_free(sql);
6302 	return sret;
6303     }
6304     dbtraceapi(d, "sqlite3_get_table", sql);
6305     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
6306     sqlite3_free(sql);
6307     if (ret != SQLITE_OK) {
6308 doerr:
6309 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6310 		errp ? errp : "unknown error", ret);
6311 	if (errp) {
6312 	    sqlite3_free(errp);
6313 	    errp = NULL;
6314 	}
6315 	return SQL_ERROR;
6316     }
6317     if (errp) {
6318 	sqlite3_free(errp);
6319 	errp = NULL;
6320     }
6321     size = 0; /* number result rows */
6322     if (ncols * nrows <= 0) {
6323 	goto nodata_but_rowid;
6324     }
6325     sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
6326     if (!sql) {
6327 	return nomem(s);
6328     }
6329     dbtraceapi(d, "sqlite3_get_table", sql);
6330     ret = sqlite3_get_table(d->sqlite, sql, &rowppp, &nnnrows, &nnncols,
6331 			    &errp);
6332     sqlite3_free(sql);
6333     if (ret != SQLITE_OK) {
6334 	sqlite3_free_table(rowp);
6335 	goto doerr;
6336     }
6337     if (errp) {
6338 	sqlite3_free(errp);
6339 	errp = NULL;
6340     }
6341     namec = findcol(rowp, ncols, "name");
6342     uniquec = findcol(rowp, ncols, "unique");
6343     if (namec < 0 || uniquec < 0) {
6344 	goto nodata_but_rowid;
6345     }
6346     namecc = findcol(rowppp, nnncols, "name");
6347     typecc = findcol(rowppp, nnncols, "type");
6348     notnullcc = findcol(rowppp, nnncols, "notnull");
6349     for (i = 1; i <= nrows; i++) {
6350 	int nnrows, nncols;
6351 	char **rowpp = NULL;
6352 
6353 	if (*rowp[i * ncols + uniquec] != '0') {
6354 	    ret = SQLITE_ERROR;
6355 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
6356 				  rowp[i * ncols + namec]);
6357 	    if (sql) {
6358 		dbtraceapi(d, "sqlite3_get_table", sql);
6359 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6360 					&nnrows, &nncols, NULL);
6361 		sqlite3_free(sql);
6362 	    }
6363 	    if (ret == SQLITE_OK) {
6364 		size += nnrows;
6365 		sqlite3_free_table(rowpp);
6366 	    }
6367 	}
6368     }
6369 nodata_but_rowid:
6370     if (size == 0) {
6371 	size = 1;
6372 	mkrowid = 1;
6373     }
6374     s->nrows = size;
6375     size = (size + 1) * asize;
6376     s->rows = xmalloc((size + 1) * sizeof (char *));
6377     if (!s->rows) {
6378 	s->nrows = 0;
6379 	sqlite3_free_table(rowp);
6380 	sqlite3_free_table(rowppp);
6381 	return nomem(s);
6382     }
6383     s->rows[0] = (char *) size;
6384     s->rows += 1;
6385     memset(s->rows, 0, sizeof (char *) * size);
6386     s->rowfree = freerows;
6387     if (mkrowid) {
6388 	s->nrows = 0;
6389 	goto mkrowid;
6390     }
6391     offs = 0;
6392     for (i = 1; i <= nrows; i++) {
6393 	int nnrows, nncols;
6394 	char **rowpp = NULL;
6395 
6396 	if (*rowp[i * ncols + uniquec] != '0') {
6397 	    int k;
6398 
6399 	    ret = SQLITE_ERROR;
6400 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
6401 				  rowp[i * ncols + namec]);
6402 	    if (sql) {
6403 		dbtraceapi(d, "sqlite3_get_table", sql);
6404 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6405 					&nnrows, &nncols, NULL);
6406 		sqlite3_free(sql);
6407 	    }
6408 	    if (ret != SQLITE_OK) {
6409 		continue;
6410 	    }
6411 	    for (k = 0; nnrows && k < nncols; k++) {
6412 		if (strcmp(rowpp[k], "name") == 0) {
6413 		    int m;
6414 
6415 		    for (m = 1; m <= nnrows; m++) {
6416 			int roffs = (offs + m) * s->ncols;
6417 
6418 			s->rows[roffs + 0] =
6419 			    xstrdup(stringify(SQL_SCOPE_SESSION));
6420 			s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
6421 			s->rows[roffs + 4] = xstrdup("0");
6422 			s->rows[roffs + 7] =
6423 			    xstrdup(stringify(SQL_PC_NOT_PSEUDO));
6424 			if (namecc >= 0 && typecc >= 0) {
6425 			    int ii;
6426 
6427 			    for (ii = 1; ii <= nnnrows; ii++) {
6428 				if (strcmp(rowppp[ii * nnncols + namecc],
6429 					   rowpp[m * nncols + k]) == 0) {
6430 				    char *typen = rowppp[ii * nnncols + typecc];
6431 				    int sqltype, mm, dd, isnullable = 0;
6432 				    char buf[32];
6433 
6434 				    s->rows[roffs + 3] = xstrdup(typen);
6435 				    sqltype = mapsqltype(typen, NULL, *s->ov3,
6436 							 s->nowchar[0],
6437 							 s->dobigint);
6438 				    getmd(typen, sqltype, &mm, &dd);
6439 #ifdef SQL_LONGVARCHAR
6440 				    if (sqltype == SQL_VARCHAR && mm > 255) {
6441 					sqltype = SQL_LONGVARCHAR;
6442 				    }
6443 #endif
6444 #ifdef WINTERFACE
6445 #ifdef SQL_WLONGVARCHAR
6446 				    if (sqltype == SQL_WVARCHAR && mm > 255) {
6447 					sqltype = SQL_WLONGVARCHAR;
6448 				    }
6449 #endif
6450 #endif
6451 				    if (sqltype == SQL_VARBINARY && mm > 255) {
6452 					sqltype = SQL_LONGVARBINARY;
6453 				    }
6454 				    sprintf(buf, "%d", sqltype);
6455 				    s->rows[roffs + 2] = xstrdup(buf);
6456 				    sprintf(buf, "%d", mm);
6457 				    s->rows[roffs + 5] = xstrdup(buf);
6458 				    sprintf(buf, "%d", dd);
6459 				    s->rows[roffs + 6] = xstrdup(buf);
6460 				    if (notnullcc >= 0) {
6461 					char *inp =
6462 					   rowppp[ii * nnncols + notnullcc];
6463 
6464 					isnullable = inp[0] != '0';
6465 				    }
6466 				    sprintf(buf, "%d", isnullable);
6467 				    s->rows[roffs + 8] = xstrdup(buf);
6468 				}
6469 			    }
6470 			}
6471 		    }
6472 		}
6473 	    }
6474 	    offs += nnrows;
6475 	    sqlite3_free_table(rowpp);
6476 	}
6477     }
6478     if (nullable == SQL_NO_NULLS) {
6479 	for (i = 1; i < s->nrows; i++) {
6480 	    if (s->rows[i * s->ncols + 8][0] == '0') {
6481 		int m, i1 = i + 1;
6482 
6483 		for (m = 0; m < s->ncols; m++) {
6484 		    freep(&s->rows[i * s->ncols + m]);
6485 		}
6486 		size = s->ncols * sizeof (char *) * (s->nrows - i1);
6487 		if (size > 0) {
6488 		    memmove(s->rows + i * s->ncols,
6489 			    s->rows + i1 * s->ncols,
6490 			    size);
6491 		    memset(s->rows + s->nrows * s->ncols, 0,
6492 			   s->ncols * sizeof (char *));
6493 		}
6494 		s->nrows--;
6495 		--i;
6496 	    }
6497 	}
6498     }
6499 mkrowid:
6500     sqlite3_free_table(rowp);
6501     sqlite3_free_table(rowppp);
6502     if (s->nrows == 0) {
6503 	s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
6504 	s->rows[s->ncols + 1] = xstrdup("_ROWID_");
6505 	s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
6506 	s->rows[s->ncols + 3] = xstrdup("integer");
6507 	s->rows[s->ncols + 4] = xstrdup("0");
6508 	s->rows[s->ncols + 5] = xstrdup("10");
6509 	s->rows[s->ncols + 6] = xstrdup("9");
6510 	s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
6511 	s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
6512 	s->nrows = 1;
6513     }
6514     return SQL_SUCCESS;
6515 }
6516 
6517 #ifndef WINTERFACE
6518 /**
6519  * Retrieve information about indexed columns.
6520  * @param stmt statement handle
6521  * @param id type of information, e.g. best row id
6522  * @param cat catalog name/pattern or NULL
6523  * @param catLen length of catalog name/pattern or SQL_NTS
6524  * @param schema schema name/pattern or NULL
6525  * @param schemaLen length of schema name/pattern or SQL_NTS
6526  * @param table table name/pattern or NULL
6527  * @param tableLen length of table name/pattern or SQL_NTS
6528  * @param scope
6529  * @param nullable
6530  * @result ODBC error code
6531  */
6532 
6533 SQLRETURN SQL_API
SQLSpecialColumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6534 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
6535 		  SQLCHAR *cat, SQLSMALLINT catLen,
6536 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
6537 		  SQLCHAR *table, SQLSMALLINT tableLen,
6538 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
6539 {
6540 #if defined(_WIN32) || defined(_WIN64)
6541     char *c = NULL, *s = NULL, *t = NULL;
6542 #endif
6543     SQLRETURN ret;
6544 
6545     HSTMT_LOCK(stmt);
6546 #if defined(_WIN32) || defined(_WIN64)
6547     if (!((STMT *) stmt)->oemcp[0]) {
6548 	ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
6549 				table, tableLen, scope, nullable);
6550 	goto done2;
6551     }
6552     if (cat) {
6553 	c = wmb_to_utf_c((char *) cat, catLen);
6554 	if (!c) {
6555 	    ret = nomem((STMT *) stmt);
6556 	    goto done;
6557 	}
6558     }
6559     if (schema) {
6560 	s = wmb_to_utf_c((char *) schema, schemaLen);
6561 	if (!s) {
6562 	    ret = nomem((STMT *) stmt);
6563 	    goto done;
6564 	}
6565     }
6566     if (table) {
6567 	t = wmb_to_utf_c((char *) table, tableLen);
6568 	if (!t) {
6569 	    ret = nomem((STMT *) stmt);
6570 	    goto done;
6571 	}
6572     }
6573     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
6574 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
6575 			    scope, nullable);
6576 #else
6577     ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
6578 			    table, tableLen, scope, nullable);
6579 #endif
6580 #if defined(_WIN32) || defined(_WIN64)
6581 done:
6582     uc_free(t);
6583     uc_free(s);
6584     uc_free(c);
6585 done2:
6586     ;
6587 #endif
6588     HSTMT_UNLOCK(stmt);
6589     return ret;
6590 }
6591 #endif
6592 
6593 #ifdef WINTERFACE
6594 /**
6595  * Retrieve information about indexed columns (UNICODE version).
6596  * @param stmt statement handle
6597  * @param id type of information, e.g. best row id
6598  * @param cat catalog name/pattern or NULL
6599  * @param catLen length of catalog name/pattern or SQL_NTS
6600  * @param schema schema name/pattern or NULL
6601  * @param schemaLen length of schema name/pattern or SQL_NTS
6602  * @param table table name/pattern or NULL
6603  * @param tableLen length of table name/pattern or SQL_NTS
6604  * @param scope
6605  * @param nullable
6606  * @result ODBC error code
6607  */
6608 
6609 SQLRETURN SQL_API
SQLSpecialColumnsW(SQLHSTMT stmt,SQLUSMALLINT id,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6610 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
6611 		   SQLWCHAR *cat, SQLSMALLINT catLen,
6612 		   SQLWCHAR *schema, SQLSMALLINT schemaLen,
6613 		   SQLWCHAR *table, SQLSMALLINT tableLen,
6614 		   SQLUSMALLINT scope, SQLUSMALLINT nullable)
6615 {
6616     char *c = NULL, *s = NULL, *t = NULL;
6617     SQLRETURN ret;
6618 
6619     HSTMT_LOCK(stmt);
6620     if (cat) {
6621 	c = uc_to_utf_c(cat, catLen);
6622 	if (!c) {
6623 	    ret = nomem((STMT *) stmt);
6624 	    goto done;
6625 	}
6626     }
6627     if (schema) {
6628 	s = uc_to_utf_c(schema, schemaLen);
6629 	if (!s) {
6630 	    ret = nomem((STMT *) stmt);
6631 	    goto done;
6632 	}
6633     }
6634     if (table) {
6635 	t = uc_to_utf_c(table, tableLen);
6636 	if (!t) {
6637 	    ret = nomem((STMT *) stmt);
6638 	    goto done;
6639 	}
6640     }
6641     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
6642 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
6643 			    scope, nullable);
6644 done:
6645     uc_free(t);
6646     uc_free(s);
6647     uc_free(c);
6648     HSTMT_UNLOCK(stmt);
6649     return ret;
6650 }
6651 #endif
6652 
6653 /**
6654  * Columns for result set of SQLForeignKeys().
6655  */
6656 
6657 static COL fkeySpec2[] = {
6658     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6659     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
6660     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
6661     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6662     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6663     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
6664     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
6665     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6666     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
6667     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
6668     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
6669     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
6670     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
6671     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
6672 };
6673 
6674 static COL fkeySpec3[] = {
6675     { "SYSTEM", "FOREIGNKEY", "PKTABLE_CAT", SCOL_VARCHAR, 50 },
6676     { "SYSTEM", "FOREIGNKEY", "PKTABLE_SCHEM", SCOL_VARCHAR, 50 },
6677     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
6678     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6679     { "SYSTEM", "FOREIGNKEY", "FKTABLE_CAT", SCOL_VARCHAR, 50 },
6680     { "SYSTEM", "FOREIGNKEY", "FKTABLE_SCHEM", SCOL_VARCHAR, 50 },
6681     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
6682     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6683     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
6684     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
6685     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
6686     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
6687     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
6688     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
6689 };
6690 
6691 /**
6692  * Internal retrieve information about primary/foreign keys.
6693  * @param stmt statement handle
6694  * @param PKcatalog primary key catalog name/pattern or NULL
6695  * @param PKcatalogLen length of PKcatalog or SQL_NTS
6696  * @param PKschema primary key schema name/pattern or NULL
6697  * @param PKschemaLen length of PKschema or SQL_NTS
6698  * @param PKtable primary key table name/pattern or NULL
6699  * @param PKtableLen length of PKtable or SQL_NTS
6700  * @param FKcatalog foreign key catalog name/pattern or NULL
6701  * @param FKcatalogLen length of FKcatalog or SQL_NTS
6702  * @param FKschema foreign key schema name/pattern or NULL
6703  * @param FKschemaLen length of FKschema or SQL_NTS
6704  * @param FKtable foreign key table name/pattern or NULL
6705  * @param FKtableLen length of FKtable or SQL_NTS
6706  * @result ODBC error code
6707  */
6708 
6709 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)6710 drvforeignkeys(SQLHSTMT stmt,
6711 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
6712 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
6713 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
6714 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
6715 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
6716 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
6717 {
6718     STMT *s;
6719     DBC *d;
6720     SQLRETURN sret;
6721     int i, asize, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
6722     int onu, ond;
6723     PTRDIFF_T size;
6724     char **rowp, *errp = NULL, *sql, pname[512], fname[512];
6725 
6726     sret = mkresultset(stmt, fkeySpec2, array_size(fkeySpec2),
6727 		       fkeySpec3, array_size(fkeySpec3), &asize);
6728     if (sret != SQL_SUCCESS) {
6729 	return sret;
6730     }
6731     s = (STMT *) stmt;
6732     sret = starttran(s);
6733     if (sret != SQL_SUCCESS) {
6734 	return sret;
6735     }
6736     d = (DBC *) s->dbc;
6737     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
6738 	(!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
6739 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
6740 	return SQL_ERROR;
6741     }
6742     size = 0;
6743     if (PKtable) {
6744 	if (PKtableLen == SQL_NTS) {
6745 	    size = sizeof (pname) - 1;
6746 	} else {
6747 	    size = min(sizeof (pname) - 1, PKtableLen);
6748 	}
6749 	strncpy(pname, (char *) PKtable, size);
6750     }
6751     pname[size] = '\0';
6752     size = 0;
6753     if (FKtable) {
6754 
6755 	if (FKtableLen == SQL_NTS) {
6756 	    size = sizeof (fname) - 1;
6757 	} else {
6758 	    size = min(sizeof (fname) - 1, FKtableLen);
6759 	}
6760 	strncpy(fname, (char *) FKtable, size);
6761     }
6762     fname[size] = '\0';
6763     if (fname[0] != '\0') {
6764 	int plen;
6765 
6766 	ret = SQLITE_ERROR;
6767 	sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", fname);
6768 	if (sql) {
6769 	    dbtraceapi(d, "sqlite3_get_table", sql);
6770 	    ret = sqlite3_get_table(d->sqlite, sql, &rowp,
6771 				    &nrows, &ncols, &errp);
6772 	    sqlite3_free(sql);
6773 	}
6774 	if (ret != SQLITE_OK) {
6775 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6776 		    errp ? errp : "unknown error", ret);
6777 	    if (errp) {
6778 		sqlite3_free(errp);
6779 		errp = NULL;
6780 	    }
6781 	    return SQL_ERROR;
6782 	}
6783 	if (errp) {
6784 	    sqlite3_free(errp);
6785 	    errp = NULL;
6786 	}
6787 	if (ncols * nrows <= 0) {
6788 nodata:
6789 	    sqlite3_free_table(rowp);
6790 	    return SQL_SUCCESS;
6791 	}
6792 	size = 0;
6793 	namec = findcol(rowp, ncols, "table");
6794 	seqc = findcol(rowp, ncols, "seq");
6795 	fromc = findcol(rowp, ncols, "from");
6796 	toc = findcol(rowp, ncols, "to");
6797 	onu = findcol(rowp, ncols, "on_update");
6798 	ond = findcol(rowp, ncols, "on_delete");
6799 	if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
6800 	    goto nodata;
6801 	}
6802 	plen = strlen(pname);
6803 	for (i = 1; i <= nrows; i++) {
6804 	    char *ptab = unquote(rowp[i * ncols + namec]);
6805 
6806 	    if (plen && ptab) {
6807 		int len = strlen(ptab);
6808 
6809 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
6810 		    continue;
6811 		}
6812 	    }
6813 	    size++;
6814 	}
6815 	if (size == 0) {
6816 	    goto nodata;
6817 	}
6818 	s->nrows = size;
6819 	size = (size + 1) * asize;
6820 	s->rows = xmalloc((size + 1) * sizeof (char *));
6821 	if (!s->rows) {
6822 	    s->nrows = 0;
6823 	    return nomem(s);
6824 	}
6825 	s->rows[0] = (char *) size;
6826 	s->rows += 1;
6827 	memset(s->rows, 0, sizeof (char *) * size);
6828 	s->rowfree = freerows;
6829 	offs = 0;
6830 	for (i = 1; i <= nrows; i++) {
6831 	    int pos = 0, roffs = (offs + 1) * s->ncols;
6832 	    char *ptab = rowp[i * ncols + namec];
6833 	    char buf[32];
6834 
6835 	    if (plen && ptab) {
6836 		int len = strlen(ptab);
6837 
6838 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
6839 		    continue;
6840 		}
6841 	    }
6842 	    s->rows[roffs + 0] = xstrdup("");
6843 #if defined(_WIN32) || defined(_WIN64)
6844 	    s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
6845 #else
6846 	    s->rows[roffs + 1] = xstrdup("");
6847 #endif
6848 	    s->rows[roffs + 2] = xstrdup(ptab);
6849 	    s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
6850 	    s->rows[roffs + 4] = xstrdup("");
6851 	    s->rows[roffs + 5] = xstrdup("");
6852 	    s->rows[roffs + 6] = xstrdup(fname);
6853 	    s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
6854 	    sscanf(rowp[i * ncols + seqc], "%d", &pos);
6855 	    sprintf(buf, "%d", pos + 1);
6856 	    s->rows[roffs + 8] = xstrdup(buf);
6857 	    if (onu < 0) {
6858 		s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
6859 	    } else {
6860 		if (strcmp(rowp[i * ncols + onu], "SET NULL") == 0) {
6861 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
6862 		} else if (strcmp(rowp[i * ncols + onu], "SET DEFAULT") == 0) {
6863 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_DEFAULT));
6864 		} else if (strcmp(rowp[i * ncols + onu], "CASCADE") == 0) {
6865 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
6866 		} else if (strcmp(rowp[i * ncols + onu], "RESTRICT") == 0) {
6867 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
6868 		} else {
6869 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
6870 		}
6871 	    }
6872 	    if (ond < 0) {
6873 		s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
6874 	    } else {
6875 		if (strcmp(rowp[i * ncols + ond], "SET NULL") == 0) {
6876 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
6877 		} else if (strcmp(rowp[i * ncols + ond], "SET DEFAULT") == 0) {
6878 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_DEFAULT));
6879 		} else if (strcmp(rowp[i * ncols + ond], "CASCADE") == 0) {
6880 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
6881 		} else if (strcmp(rowp[i * ncols + ond], "RESTRICT") == 0) {
6882 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
6883 		} else {
6884 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
6885 		}
6886 	    }
6887 	    s->rows[roffs + 11] = NULL;
6888 	    s->rows[roffs + 12] = NULL;
6889 	    s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
6890 	    offs++;
6891 	}
6892 	sqlite3_free_table(rowp);
6893     } else {
6894 	int nnrows, nncols, plen = strlen(pname);
6895 	char **rowpp;
6896 
6897 	sql = "select name from sqlite_master where type='table'";
6898 	dbtraceapi(d, "sqlite3_get_table", sql);
6899 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
6900 	if (ret != SQLITE_OK) {
6901 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6902 		    errp ? errp : "unknown error", ret);
6903 	    if (errp) {
6904 		sqlite3_free(errp);
6905 		errp = NULL;
6906 	    }
6907 	    return SQL_ERROR;
6908 	}
6909 	if (errp) {
6910 	    sqlite3_free(errp);
6911 	    errp = NULL;
6912 	}
6913 	if (ncols * nrows <= 0) {
6914 	    goto nodata;
6915 	}
6916 	size = 0;
6917 	for (i = 1; i <= nrows; i++) {
6918 	    int k;
6919 
6920 	    if (!rowp[i]) {
6921 		continue;
6922 	    }
6923 	    rowpp = NULL;
6924 	    ret = SQLITE_ERROR;
6925 	    sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
6926 	    if (sql) {
6927 		dbtraceapi(d, "sqlite3_get_table", sql);
6928 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6929 				      &nnrows, &nncols, NULL);
6930 		sqlite3_free(sql);
6931 	    }
6932 	    if (ret != SQLITE_OK || nncols * nnrows <= 0) {
6933 		sqlite3_free_table(rowpp);
6934 		continue;
6935 	    }
6936 	    namec = findcol(rowpp, nncols, "table");
6937 	    seqc = findcol(rowpp, nncols, "seq");
6938 	    fromc = findcol(rowpp, nncols, "from");
6939 	    toc = findcol(rowpp, nncols, "to");
6940 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
6941 		sqlite3_free_table(rowpp);
6942 		continue;
6943 	    }
6944 	    for (k = 1; k <= nnrows; k++) {
6945 		char *ptab = unquote(rowpp[k * nncols + namec]);
6946 
6947 		if (plen && ptab) {
6948 		    int len = strlen(ptab);
6949 
6950 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
6951 			continue;
6952 		    }
6953 		}
6954 		size++;
6955 	    }
6956 	    sqlite3_free_table(rowpp);
6957 	}
6958 	if (size == 0) {
6959 	    goto nodata;
6960 	}
6961 	s->nrows = size;
6962 	size = (size + 1) * asize;
6963 	s->rows = xmalloc((size + 1) * sizeof (char *));
6964 	if (!s->rows) {
6965 	    s->nrows = 0;
6966 	    return nomem(s);
6967 	}
6968 	s->rows[0] = (char *) size;
6969 	s->rows += 1;
6970 	memset(s->rows, 0, sizeof (char *) * size);
6971 	s->rowfree = freerows;
6972 	offs = 0;
6973 	for (i = 1; i <= nrows; i++) {
6974 	    int k;
6975 
6976 	    if (!rowp[i]) {
6977 		continue;
6978 	    }
6979 	    rowpp = NULL;
6980 	    ret = SQLITE_ERROR;
6981 	    sql = sqlite3_mprintf("PRAGMA foreign_key_list(%Q)", rowp[i]);
6982 	    if (sql) {
6983 		dbtraceapi(d, "sqlite3_get_table", sql);
6984 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
6985 					&nnrows, &nncols, NULL);
6986 		sqlite3_free(sql);
6987 	    }
6988 	    if (ret != SQLITE_OK || nncols * nnrows <= 0) {
6989 		sqlite3_free_table(rowpp);
6990 		continue;
6991 	    }
6992 	    namec = findcol(rowpp, nncols, "table");
6993 	    seqc = findcol(rowpp, nncols, "seq");
6994 	    fromc = findcol(rowpp, nncols, "from");
6995 	    toc = findcol(rowpp, nncols, "to");
6996 	    onu = findcol(rowpp, nncols, "on_update");
6997 	    ond = findcol(rowpp, nncols, "on_delete");
6998 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
6999 		sqlite3_free_table(rowpp);
7000 		continue;
7001 	    }
7002 	    for (k = 1; k <= nnrows; k++) {
7003 		int pos = 0, roffs = (offs + 1) * s->ncols;
7004 		char *ptab = unquote(rowpp[k * nncols + namec]);
7005 		char buf[32];
7006 
7007 		if (plen && ptab) {
7008 		    int len = strlen(ptab);
7009 
7010 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
7011 			continue;
7012 		    }
7013 		}
7014 		s->rows[roffs + 0] = xstrdup("");
7015 #if defined(_WIN32) || defined(_WIN64)
7016 		s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
7017 #else
7018 		s->rows[roffs + 1] = xstrdup("");
7019 #endif
7020 		s->rows[roffs + 2] = xstrdup(ptab);
7021 		s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
7022 		s->rows[roffs + 4] = xstrdup("");
7023 		s->rows[roffs + 5] = xstrdup("");
7024 		s->rows[roffs + 6] = xstrdup(rowp[i]);
7025 		s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
7026 		sscanf(rowpp[k * nncols + seqc], "%d", &pos);
7027 		sprintf(buf, "%d", pos + 1);
7028 		s->rows[roffs + 8] = xstrdup(buf);
7029 		if (onu < 0) {
7030 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7031 		} else {
7032 		    if (strcmp(rowpp[k * nncols + onu], "SET NULL") == 0) {
7033 			s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
7034 		    } else if (strcmp(rowpp[k * nncols + onu], "SET DEFAULT")
7035 			       == 0) {
7036 			s->rows[roffs + 9] =
7037 			    xstrdup(stringify(SQL_SET_DEFAULT));
7038 		    } else if (strcmp(rowpp[k * nncols + onu], "CASCADE")
7039 			       == 0) {
7040 			s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
7041 		    } else if (strcmp(rowpp[k * nncols + onu], "RESTRICT")
7042 			       == 0) {
7043 			s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
7044 		    } else {
7045 			s->rows[roffs + 9] =
7046 			    xstrdup(stringify(SQL_NO_ACTION));
7047 		    }
7048 		}
7049 		if (ond < 0) {
7050 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7051 		} else {
7052 		    if (strcmp(rowpp[k * nncols + ond], "SET NULL") == 0) {
7053 			s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
7054 		    } else if (strcmp(rowpp[k * nncols + ond], "SET DEFAULT")
7055 			       == 0) {
7056 			s->rows[roffs + 10] =
7057 			    xstrdup(stringify(SQL_SET_DEFAULT));
7058 		    } else if (strcmp(rowpp[k * nncols + ond], "CASCADE")
7059 			       == 0) {
7060 			s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
7061 		    } else if (strcmp(rowpp[k * nncols + ond], "RESTRICT")
7062 			       == 0) {
7063 			s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
7064 		    } else {
7065 			s->rows[roffs + 10] =
7066 			    xstrdup(stringify(SQL_NO_ACTION));
7067 		    }
7068 		}
7069 		s->rows[roffs + 11] = NULL;
7070 		s->rows[roffs + 12] = NULL;
7071 		s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
7072 		offs++;
7073 	    }
7074 	    sqlite3_free_table(rowpp);
7075 	}
7076 	sqlite3_free_table(rowp);
7077     }
7078     return SQL_SUCCESS;
7079 }
7080 
7081 #ifndef WINTERFACE
7082 /**
7083  * Retrieve information about primary/foreign keys.
7084  * @param stmt statement handle
7085  * @param PKcatalog primary key catalog name/pattern or NULL
7086  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7087  * @param PKschema primary key schema name/pattern or NULL
7088  * @param PKschemaLen length of PKschema or SQL_NTS
7089  * @param PKtable primary key table name/pattern or NULL
7090  * @param PKtableLen length of PKtable or SQL_NTS
7091  * @param FKcatalog foreign key catalog name/pattern or NULL
7092  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7093  * @param FKschema foreign key schema name/pattern or NULL
7094  * @param FKschemaLen length of FKschema or SQL_NTS
7095  * @param FKtable foreign key table name/pattern or NULL
7096  * @param FKtableLen length of FKtable or SQL_NTS
7097  * @result ODBC error code
7098  */
7099 
7100 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)7101 SQLForeignKeys(SQLHSTMT stmt,
7102 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7103 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
7104 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
7105 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7106 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
7107 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
7108 {
7109 #if defined(_WIN32) || defined(_WIN64)
7110     char *pc = NULL, *ps = NULL, *pt = NULL;
7111     char *fc = NULL, *fs = NULL, *ft = NULL;
7112 #endif
7113     SQLRETURN ret;
7114 
7115     HSTMT_LOCK(stmt);
7116 #if defined(_WIN32) || defined(_WIN64)
7117     if (!((STMT *) stmt)->oemcp[0]) {
7118 	ret = drvforeignkeys(stmt,
7119 			     PKcatalog, PKcatalogLen,
7120 			     PKschema, PKschemaLen, PKtable, PKtableLen,
7121 			     FKcatalog, FKcatalogLen,
7122 			     FKschema, FKschemaLen,
7123 			     FKtable, FKtableLen);
7124 	goto done2;
7125     }
7126     if (PKcatalog) {
7127 	pc = wmb_to_utf_c((char *) PKcatalog, PKcatalogLen);
7128 	if (!pc) {
7129 	    ret = nomem((STMT *) stmt);
7130 	    goto done;
7131 	}
7132     }
7133     if (PKschema) {
7134 	ps = wmb_to_utf_c((char *) PKschema, PKschemaLen);
7135 	if (!ps) {
7136 	    ret = nomem((STMT *) stmt);
7137 	    goto done;
7138 	}
7139     }
7140     if (PKtable) {
7141 	pt = wmb_to_utf_c((char *) PKtable, PKtableLen);
7142 	if (!pt) {
7143 	    ret = nomem((STMT *) stmt);
7144 	    goto done;
7145 	}
7146     }
7147     if (FKcatalog) {
7148 	fc = wmb_to_utf_c((char *) FKcatalog, FKcatalogLen);
7149 	if (!fc) {
7150 	    ret = nomem((STMT *) stmt);
7151 	    goto done;
7152 	}
7153     }
7154     if (FKschema) {
7155 	fs = wmb_to_utf_c((char *) FKschema, FKschemaLen);
7156 	if (!fs) {
7157 	    ret = nomem((STMT *) stmt);
7158 	    goto done;
7159 	}
7160     }
7161     if (FKtable) {
7162 	ft = wmb_to_utf_c((char *) FKtable, FKtableLen);
7163 	if (!ft) {
7164 	    ret = nomem((STMT *) stmt);
7165 	    goto done;
7166 	}
7167     }
7168     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
7169 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
7170 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
7171 			 (SQLCHAR *) ft, SQL_NTS);
7172 #else
7173     ret = drvforeignkeys(stmt,
7174 			 PKcatalog, PKcatalogLen,
7175 			 PKschema, PKschemaLen, PKtable, PKtableLen,
7176 			 FKcatalog, FKcatalogLen,
7177 			 FKschema, FKschemaLen,
7178 			 FKtable, FKtableLen);
7179 #endif
7180 #if defined(_WIN32) || defined(_WIN64)
7181 done:
7182     uc_free(ft);
7183     uc_free(fs);
7184     uc_free(fc);
7185     uc_free(pt);
7186     uc_free(ps);
7187     uc_free(pc);
7188 done2:
7189     ;
7190 #endif
7191     HSTMT_UNLOCK(stmt);
7192     return ret;
7193 }
7194 #endif
7195 
7196 #ifdef WINTERFACE
7197 /**
7198  * Retrieve information about primary/foreign keys (UNICODE version).
7199  * @param stmt statement handle
7200  * @param PKcatalog primary key catalog name/pattern or NULL
7201  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7202  * @param PKschema primary key schema name/pattern or NULL
7203  * @param PKschemaLen length of PKschema or SQL_NTS
7204  * @param PKtable primary key table name/pattern or NULL
7205  * @param PKtableLen length of PKtable or SQL_NTS
7206  * @param FKcatalog foreign key catalog name/pattern or NULL
7207  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7208  * @param FKschema foreign key schema name/pattern or NULL
7209  * @param FKschemaLen length of FKschema or SQL_NTS
7210  * @param FKtable foreign key table name/pattern or NULL
7211  * @param FKtableLen length of FKtable or SQL_NTS
7212  * @result ODBC error code
7213  */
7214 
7215 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)7216 SQLForeignKeysW(SQLHSTMT stmt,
7217 		SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7218 		SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
7219 		SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
7220 		SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7221 		SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
7222 		SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
7223 {
7224     char *pc = NULL, *ps = NULL, *pt = NULL;
7225     char *fc = NULL, *fs = NULL, *ft = NULL;
7226     SQLRETURN ret;
7227 
7228     HSTMT_LOCK(stmt);
7229     if (PKcatalog) {
7230 	pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
7231 	if (!pc) {
7232 	    ret = nomem((STMT *) stmt);
7233 	    goto done;
7234 	}
7235     }
7236     if (PKschema) {
7237 	ps = uc_to_utf_c(PKschema, PKschemaLen);
7238 	if (!ps) {
7239 	    ret = nomem((STMT *) stmt);
7240 	    goto done;
7241 	}
7242     }
7243     if (PKtable) {
7244 	pt = uc_to_utf_c(PKtable, PKtableLen);
7245 	if (!pt) {
7246 	    ret = nomem((STMT *) stmt);
7247 	    goto done;
7248 	}
7249     }
7250     if (FKcatalog) {
7251 	fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
7252 	if (!fc) {
7253 	    ret = nomem((STMT *) stmt);
7254 	    goto done;
7255 	}
7256     }
7257     if (FKschema) {
7258 	fs = uc_to_utf_c(FKschema, FKschemaLen);
7259 	if (!fs) {
7260 	    ret = nomem((STMT *) stmt);
7261 	    goto done;
7262 	}
7263     }
7264     if (FKtable) {
7265 	ft = uc_to_utf_c(FKtable, FKtableLen);
7266 	if (!ft) {
7267 	    ret = nomem((STMT *) stmt);
7268 	    goto done;
7269 	}
7270     }
7271     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
7272 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
7273 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
7274 			 (SQLCHAR *) ft, SQL_NTS);
7275 done:
7276     uc_free(ft);
7277     uc_free(fs);
7278     uc_free(fc);
7279     uc_free(pt);
7280     uc_free(ps);
7281     uc_free(pc);
7282     HSTMT_UNLOCK(stmt);
7283     return ret;
7284 }
7285 #endif
7286 
7287 /**
7288  * Start transaction when autocommit off
7289  * @param s statement pointer
7290  * @result ODBC error code
7291  */
7292 
7293 static SQLRETURN
starttran(STMT * s)7294 starttran(STMT *s)
7295 {
7296     int ret = SQL_SUCCESS, rc, busy_count = 0;
7297     char *errp = NULL;
7298     DBC *d = (DBC *) s->dbc;
7299 
7300     if (!d->autocommit && !d->intrans && !d->trans_disable) {
7301 begin_again:
7302 	rc = sqlite3_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL, &errp);
7303 	if (rc == SQLITE_BUSY) {
7304 	    if (busy_handler((void *) d, ++busy_count)) {
7305 		if (errp) {
7306 		    sqlite3_free(errp);
7307 		    errp = NULL;
7308 		}
7309 		goto begin_again;
7310 	    }
7311 	}
7312 	dbtracerc(d, rc, errp);
7313 	if (rc != SQLITE_OK) {
7314 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7315 		    errp ? errp : "unknown error", rc);
7316 	    ret = SQL_ERROR;
7317 	} else {
7318 	    d->intrans = 1;
7319 	}
7320 	if (errp) {
7321 	    sqlite3_free(errp);
7322 	    errp = NULL;
7323 	}
7324     }
7325     return ret;
7326 }
7327 
7328 /**
7329  * Internal commit or rollback transaction.
7330  * @param d database connection pointer
7331  * @param comptype type of transaction's end, SQL_COMMIT or SQL_ROLLBACK
7332  * @param force force action regardless of DBC's autocommit state
7333  * @result ODBC error code
7334  */
7335 
7336 static SQLRETURN
endtran(DBC * d,SQLSMALLINT comptype,int force)7337 endtran(DBC *d, SQLSMALLINT comptype, int force)
7338 {
7339     int ret, busy_count = 0;
7340     char *sql, *errp = NULL;
7341 
7342     if (!d->sqlite) {
7343 	setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
7344 	return SQL_ERROR;
7345     }
7346     if ((!force && d->autocommit) || !d->intrans) {
7347 	return SQL_SUCCESS;
7348     }
7349     switch (comptype) {
7350     case SQL_COMMIT:
7351 	sql = "COMMIT TRANSACTION";
7352 	goto doit;
7353     case SQL_ROLLBACK:
7354 	sql = "ROLLBACK TRANSACTION";
7355     doit:
7356 	ret = sqlite3_exec(d->sqlite, sql, NULL, NULL, &errp);
7357 	dbtracerc(d, ret, errp);
7358 	if (ret == SQLITE_BUSY && busy_count < 10) {
7359 	    if (busy_handler((void *) d, ++busy_count)) {
7360 		if (errp) {
7361 		    sqlite3_free(errp);
7362 		    errp = NULL;
7363 		}
7364 		goto doit;
7365 	    }
7366 	}
7367 	d->intrans = 0;
7368 	if (ret != SQLITE_OK) {
7369 	    setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
7370 		     errp ? errp : "transaction failed");
7371 	    if (errp) {
7372 		sqlite3_free(errp);
7373 		errp = NULL;
7374 	    }
7375 	    return SQL_ERROR;
7376 	}
7377 	if (errp) {
7378 	    sqlite3_free(errp);
7379 	    errp = NULL;
7380 	}
7381 	return SQL_SUCCESS;
7382     }
7383     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
7384     return SQL_ERROR;
7385 }
7386 
7387 /**
7388  * Internal commit or rollback transaction.
7389  * @param type type of handle
7390  * @param handle HDBC, HENV, or HSTMT handle
7391  * @param comptype SQL_COMMIT or SQL_ROLLBACK
7392  * @result ODBC error code
7393  */
7394 
7395 static SQLRETURN
drvendtran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)7396 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
7397 {
7398     DBC *d;
7399     int fail = 0;
7400     SQLRETURN ret;
7401 #if defined(_WIN32) || defined(_WIN64)
7402     ENV *e;
7403 #endif
7404 
7405     switch (type) {
7406     case SQL_HANDLE_DBC:
7407 	HDBC_LOCK((SQLHDBC) handle);
7408 	if (handle == SQL_NULL_HDBC) {
7409 	    return SQL_INVALID_HANDLE;
7410 	}
7411 	d = (DBC *) handle;
7412 	ret = endtran(d, comptype, 0);
7413 	HDBC_UNLOCK((SQLHDBC) handle);
7414 	return ret;
7415     case SQL_HANDLE_ENV:
7416 	if (handle == SQL_NULL_HENV) {
7417 	    return SQL_INVALID_HANDLE;
7418 	}
7419 #if defined(_WIN32) || defined(_WIN64)
7420 	e = (ENV *) handle;
7421 	if (e->magic != ENV_MAGIC) {
7422 	    return SQL_INVALID_HANDLE;
7423 	}
7424 	EnterCriticalSection(&e->cs);
7425 	e->owner = GetCurrentThreadId();
7426 #endif
7427 	d = ((ENV *) handle)->dbcs;
7428 	while (d) {
7429 	    ret = endtran(d, comptype, 0);
7430 	    if (ret != SQL_SUCCESS) {
7431 		fail++;
7432 	    }
7433 	    d = d->next;
7434 	}
7435 #if defined(_WIN32) || defined(_WIN64)
7436 	e->owner = 0;
7437 	LeaveCriticalSection(&e->cs);
7438 #endif
7439 	return fail ? SQL_ERROR : SQL_SUCCESS;
7440     }
7441     return SQL_INVALID_HANDLE;
7442 }
7443 
7444 /**
7445  * Commit or rollback transaction.
7446  * @param type type of handle
7447  * @param handle HDBC, HENV, or HSTMT handle
7448  * @param comptype SQL_COMMIT or SQL_ROLLBACK
7449  * @result ODBC error code
7450  */
7451 
7452 SQLRETURN SQL_API
SQLEndTran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)7453 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
7454 {
7455     return drvendtran(type, handle, comptype);
7456 }
7457 
7458 /**
7459  * Commit or rollback transaction.
7460  * @param env environment handle or NULL
7461  * @param dbc database connection handle or NULL
7462  * @param type SQL_COMMIT or SQL_ROLLBACK
7463  * @result ODBC error code
7464  */
7465 
7466 SQLRETURN SQL_API
SQLTransact(SQLHENV env,SQLHDBC dbc,SQLUSMALLINT type)7467 SQLTransact(SQLHENV env, SQLHDBC dbc, SQLUSMALLINT type)
7468 {
7469     if (env != SQL_NULL_HENV) {
7470 	return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
7471     }
7472     return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
7473 }
7474 
7475 /**
7476  * Function not implemented.
7477  */
7478 
7479 SQLRETURN SQL_API
SQLCopyDesc(SQLHDESC source,SQLHDESC target)7480 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
7481 {
7482     return SQL_ERROR;
7483 }
7484 
7485 #ifndef WINTERFACE
7486 /**
7487  * Translate SQL string.
7488  * @param stmt statement handle
7489  * @param sqlin input string
7490  * @param sqlinLen length of input string
7491  * @param sql output string
7492  * @param sqlMax max space in output string
7493  * @param sqlLen value return for length of output string
7494  * @result ODBC error code
7495  */
7496 
7497 SQLRETURN SQL_API
SQLNativeSql(SQLHSTMT stmt,SQLCHAR * sqlin,SQLINTEGER sqlinLen,SQLCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)7498 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
7499 	     SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
7500 {
7501     int outLen = 0;
7502     SQLRETURN ret = SQL_SUCCESS;
7503 
7504     HSTMT_LOCK(stmt);
7505     if (sqlinLen == SQL_NTS) {
7506 	sqlinLen = strlen((char *) sqlin);
7507     }
7508     if (sql) {
7509 	if (sqlMax > 0) {
7510 	    strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
7511 	    sqlin[sqlMax - 1] = '\0';
7512 	    outLen = min(sqlMax - 1, sqlinLen);
7513 	}
7514     } else {
7515 	outLen = sqlinLen;
7516     }
7517     if (sqlLen) {
7518 	*sqlLen = outLen;
7519     }
7520     if (sql && outLen < sqlinLen) {
7521 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
7522 	ret = SQL_SUCCESS_WITH_INFO;
7523     }
7524     HSTMT_UNLOCK(stmt);
7525     return ret;
7526 }
7527 #endif
7528 
7529 #ifdef WINTERFACE
7530 /**
7531  * Translate SQL string (UNICODE version).
7532  * @param stmt statement handle
7533  * @param sqlin input string
7534  * @param sqlinLen length of input string
7535  * @param sql output string
7536  * @param sqlMax max space in output string
7537  * @param sqlLen value return for length of output string
7538  * @result ODBC error code
7539  */
7540 
7541 SQLRETURN SQL_API
SQLNativeSqlW(SQLHSTMT stmt,SQLWCHAR * sqlin,SQLINTEGER sqlinLen,SQLWCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)7542 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
7543 	      SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
7544 {
7545     int outLen = 0;
7546     SQLRETURN ret = SQL_SUCCESS;
7547 
7548     HSTMT_LOCK(stmt);
7549     if (sqlinLen == SQL_NTS) {
7550 	sqlinLen = uc_strlen(sqlin);
7551     }
7552     if (sql) {
7553 	if (sqlMax > 0) {
7554 	    uc_strncpy(sql, sqlin, sqlMax - 1);
7555 	    sqlin[sqlMax - 1] = 0;
7556 	    outLen = min(sqlMax  - 1, sqlinLen);
7557 	}
7558     } else {
7559 	outLen = sqlinLen;
7560     }
7561     if (sqlLen) {
7562 	*sqlLen = outLen;
7563     }
7564     if (sql && outLen < sqlinLen) {
7565 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
7566 	ret = SQL_SUCCESS_WITH_INFO;
7567     }
7568     HSTMT_UNLOCK(stmt);
7569     return ret;
7570 }
7571 #endif
7572 
7573 /**
7574  * Columns for result set of SQLProcedures().
7575  */
7576 
7577 static COL procSpec2[] = {
7578     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
7579     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
7580     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7581     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
7582     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
7583     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
7584     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
7585     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
7586 };
7587 
7588 static COL procSpec3[] = {
7589     { "SYSTEM", "PROCEDURE", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
7590     { "SYSTEM", "PROCEDURE", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
7591     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7592     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
7593     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
7594     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
7595     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
7596     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
7597 };
7598 
7599 #ifndef WINTERFACE
7600 /**
7601  * Retrieve information about stored procedures.
7602  * @param stmt statement handle
7603  * @param catalog catalog name/pattern or NULL
7604  * @param catalogLen length of catalog or SQL_NTS
7605  * @param schema schema name/pattern or NULL
7606  * @param schemaLen length of schema or SQL_NTS
7607  * @param proc procedure name/pattern or NULL
7608  * @param procLen length of proc or SQL_NTS
7609  * @result ODBC error code
7610  */
7611 
7612 SQLRETURN SQL_API
SQLProcedures(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen)7613 SQLProcedures(SQLHSTMT stmt,
7614 	      SQLCHAR *catalog, SQLSMALLINT catalogLen,
7615 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
7616 	      SQLCHAR *proc, SQLSMALLINT procLen)
7617 {
7618     SQLRETURN ret;
7619 
7620     HSTMT_LOCK(stmt);
7621     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
7622 		      procSpec3, array_size(procSpec3), NULL);
7623     HSTMT_UNLOCK(stmt);
7624     return ret;
7625 }
7626 #endif
7627 
7628 #ifdef WINTERFACE
7629 /**
7630  * Retrieve information about stored procedures (UNICODE version).
7631  * @param stmt statement handle
7632  * @param catalog catalog name/pattern or NULL
7633  * @param catalogLen length of catalog or SQL_NTS
7634  * @param schema schema name/pattern or NULL
7635  * @param schemaLen length of schema or SQL_NTS
7636  * @param proc procedure name/pattern or NULL
7637  * @param procLen length of proc or SQL_NTS
7638  * @result ODBC error code
7639  */
7640 
7641 SQLRETURN SQL_API
SQLProceduresW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen)7642 SQLProceduresW(SQLHSTMT stmt,
7643 	       SQLWCHAR *catalog, SQLSMALLINT catalogLen,
7644 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
7645 	       SQLWCHAR *proc, SQLSMALLINT procLen)
7646 {
7647     SQLRETURN ret;
7648 
7649     HSTMT_LOCK(stmt);
7650     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
7651 		      procSpec3, array_size(procSpec3), NULL);
7652     HSTMT_UNLOCK(stmt);
7653     return ret;
7654 }
7655 #endif
7656 
7657 /**
7658  * Columns for result set of SQLProcedureColumns().
7659  */
7660 
7661 static COL procColSpec2[] = {
7662     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
7663     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
7664     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7665     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
7666     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
7667     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
7668     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
7669     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
7670     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
7671     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
7672     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
7673     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
7674     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
7675     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
7676     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
7677     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
7678     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
7679     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
7680     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
7681 };
7682 
7683 static COL procColSpec3[] = {
7684     { "SYSTEM", "PROCCOL", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
7685     { "SYSTEM", "PROCCOL", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
7686     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7687     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
7688     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
7689     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
7690     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
7691     { "SYSTEM", "PROCCOL", "COLUMN_SIZE", SQL_INTEGER, 10 },
7692     { "SYSTEM", "PROCCOL", "BUFFER_LENGTH", SQL_INTEGER, 10 },
7693     { "SYSTEM", "PROCCOL", "DECIMAL_DIGITS", SQL_SMALLINT, 5 },
7694     { "SYSTEM", "PROCCOL", "NUM_PREC_RADIX", SQL_SMALLINT, 5 },
7695     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
7696     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
7697     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
7698     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
7699     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
7700     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
7701     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
7702     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
7703 };
7704 
7705 #ifndef WINTERFACE
7706 /**
7707  * Retrieve information about columns in result set of stored procedures.
7708  * @param stmt statement handle
7709  * @param catalog catalog name/pattern or NULL
7710  * @param catalogLen length of catalog or SQL_NTS
7711  * @param schema schema name/pattern or NULL
7712  * @param schemaLen length of schema or SQL_NTS
7713  * @param proc procedure name/pattern or NULL
7714  * @param procLen length of proc or SQL_NTS
7715  * @param column column name/pattern or NULL
7716  * @param columnLen length of column or SQL_NTS
7717  * @result ODBC error code
7718  */
7719 
7720 SQLRETURN SQL_API
SQLProcedureColumns(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen,SQLCHAR * column,SQLSMALLINT columnLen)7721 SQLProcedureColumns(SQLHSTMT stmt,
7722 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
7723 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
7724 		    SQLCHAR *proc, SQLSMALLINT procLen,
7725 		    SQLCHAR *column, SQLSMALLINT columnLen)
7726 {
7727     SQLRETURN ret;
7728 
7729     HSTMT_LOCK(stmt);
7730     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
7731 		      procColSpec3, array_size(procColSpec3), NULL);
7732     HSTMT_UNLOCK(stmt);
7733     return ret;
7734 }
7735 #endif
7736 
7737 #ifdef WINTERFACE
7738 /**
7739  * Retrieve information about columns in result
7740  * set of stored procedures (UNICODE version).
7741  * @param stmt statement handle
7742  * @param catalog catalog name/pattern or NULL
7743  * @param catalogLen length of catalog or SQL_NTS
7744  * @param schema schema name/pattern or NULL
7745  * @param schemaLen length of schema or SQL_NTS
7746  * @param proc procedure name/pattern or NULL
7747  * @param procLen length of proc or SQL_NTS
7748  * @param column column name/pattern or NULL
7749  * @param columnLen length of column or SQL_NTS
7750  * @result ODBC error code
7751  */
7752 
7753 SQLRETURN SQL_API
SQLProcedureColumnsW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen,SQLWCHAR * column,SQLSMALLINT columnLen)7754 SQLProcedureColumnsW(SQLHSTMT stmt,
7755 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
7756 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
7757 		     SQLWCHAR *proc, SQLSMALLINT procLen,
7758 		     SQLWCHAR *column, SQLSMALLINT columnLen)
7759 {
7760     SQLRETURN ret;
7761 
7762     HSTMT_LOCK(stmt);
7763     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
7764 		      procColSpec3, array_size(procColSpec3), NULL);
7765     HSTMT_UNLOCK(stmt);
7766     return ret;
7767 }
7768 #endif
7769 
7770 /**
7771  * Get information of HENV.
7772  * @param env environment handle
7773  * @param attr attribute to be retrieved
7774  * @param val output buffer
7775  * @param len length of output buffer
7776  * @param lenp output length
7777  * @result ODBC error code
7778  */
7779 
7780 SQLRETURN SQL_API
SQLGetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len,SQLINTEGER * lenp)7781 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
7782 	      SQLINTEGER len, SQLINTEGER *lenp)
7783 {
7784     ENV *e;
7785     SQLRETURN ret = SQL_ERROR;
7786 
7787     if (env == SQL_NULL_HENV) {
7788 	return SQL_INVALID_HANDLE;
7789     }
7790     e = (ENV *) env;
7791     if (!e || e->magic != ENV_MAGIC) {
7792 	return SQL_INVALID_HANDLE;
7793     }
7794 #if defined(_WIN32) || defined(_WIN64)
7795     EnterCriticalSection(&e->cs);
7796     e->owner = GetCurrentThreadId();
7797 #endif
7798     switch (attr) {
7799     case SQL_ATTR_CONNECTION_POOLING:
7800 	ret = SQL_ERROR;
7801 	break;
7802     case SQL_ATTR_CP_MATCH:
7803 	ret = SQL_NO_DATA;
7804 	break;
7805     case SQL_ATTR_OUTPUT_NTS:
7806 	if (val) {
7807 	    *((SQLINTEGER *) val) = SQL_TRUE;
7808 	}
7809 	if (lenp) {
7810 	    *lenp = sizeof (SQLINTEGER);
7811 	}
7812 	ret = SQL_SUCCESS;
7813 	break;
7814     case SQL_ATTR_ODBC_VERSION:
7815 	if (val) {
7816 	    *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
7817 	}
7818 	if (lenp) {
7819 	    *lenp = sizeof (SQLINTEGER);
7820 	}
7821 	ret = SQL_SUCCESS;
7822 	break;
7823     }
7824 #if defined(_WIN32) || defined(_WIN64)
7825     e->owner = 0;
7826     LeaveCriticalSection(&e->cs);
7827 #endif
7828     return ret;
7829 }
7830 
7831 /**
7832  * Set information in HENV.
7833  * @param env environment handle
7834  * @param attr attribute to be retrieved
7835  * @param val parameter buffer
7836  * @param len length of parameter
7837  * @result ODBC error code
7838  */
7839 
7840 SQLRETURN SQL_API
SQLSetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)7841 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
7842 {
7843     ENV *e;
7844     SQLRETURN ret = SQL_ERROR;
7845 
7846     if (env == SQL_NULL_HENV) {
7847 	return SQL_INVALID_HANDLE;
7848     }
7849     e = (ENV *) env;
7850     if (!e || e->magic != ENV_MAGIC) {
7851 	return SQL_INVALID_HANDLE;
7852     }
7853 #if defined(_WIN32) || defined(_WIN64)
7854     EnterCriticalSection(&e->cs);
7855     e->owner = GetCurrentThreadId();
7856 #endif
7857     switch (attr) {
7858     case SQL_ATTR_CONNECTION_POOLING:
7859 	ret = SQL_SUCCESS;
7860 	break;
7861     case SQL_ATTR_CP_MATCH:
7862 	ret = SQL_NO_DATA;
7863 	break;
7864     case SQL_ATTR_OUTPUT_NTS:
7865 	if (val == (SQLPOINTER) SQL_TRUE) {
7866 	    ret = SQL_SUCCESS;
7867 	}
7868 	break;
7869     case SQL_ATTR_ODBC_VERSION:
7870 	if (!val) {
7871 	    break;
7872 	}
7873 	if (val == (SQLPOINTER) SQL_OV_ODBC2) {
7874 	    e->ov3 = 0;
7875 	    ret = SQL_SUCCESS;
7876 	}
7877 	if (val == (SQLPOINTER) SQL_OV_ODBC3) {
7878 	    e->ov3 = 1;
7879 	    ret = SQL_SUCCESS;
7880 	}
7881 	break;
7882     }
7883 #if defined(_WIN32) || defined(_WIN64)
7884     e->owner = 0;
7885     LeaveCriticalSection(&e->cs);
7886 #endif
7887     return ret;
7888 }
7889 
7890 /**
7891  * Internal get error message given handle (HENV, HDBC, or HSTMT).
7892  * @param htype handle type
7893  * @param handle HENV, HDBC, or HSTMT
7894  * @param recno
7895  * @param sqlstate output buffer for SQL state
7896  * @param nativeerr output buffer of native error code
7897  * @param msg output buffer for error message
7898  * @param buflen length of output buffer
7899  * @param msglen output length
7900  * @result ODBC error code
7901  */
7902 
7903 static SQLRETURN
drvgetdiagrec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)7904 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
7905 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
7906 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
7907 {
7908     DBC *d = NULL;
7909     STMT *s = NULL;
7910     int len, naterr;
7911     char *logmsg, *sqlst;
7912     SQLRETURN ret = SQL_ERROR;
7913 
7914     if (handle == SQL_NULL_HANDLE) {
7915 	return SQL_INVALID_HANDLE;
7916     }
7917     if (sqlstate) {
7918 	sqlstate[0] = '\0';
7919     }
7920     if (msg && buflen > 0) {
7921 	msg[0] = '\0';
7922     }
7923     if (msglen) {
7924 	*msglen = 0;
7925     }
7926     if (nativeerr) {
7927 	*nativeerr = 0;
7928     }
7929     switch (htype) {
7930     case SQL_HANDLE_ENV:
7931     case SQL_HANDLE_DESC:
7932 	return SQL_NO_DATA;
7933     case SQL_HANDLE_DBC:
7934 	HDBC_LOCK((SQLHDBC) handle);
7935 	d = (DBC *) handle;
7936 	logmsg = (char *) d->logmsg;
7937 	sqlst = d->sqlstate;
7938 	naterr = d->naterr;
7939 	break;
7940     case SQL_HANDLE_STMT:
7941 	HSTMT_LOCK((SQLHSTMT) handle);
7942 	s = (STMT *) handle;
7943 	logmsg = (char *) s->logmsg;
7944 	sqlst = s->sqlstate;
7945 	naterr = s->naterr;
7946 	break;
7947     default:
7948 	return SQL_INVALID_HANDLE;
7949     }
7950     if (buflen < 0) {
7951 	goto done;
7952     }
7953     if (recno > 1) {
7954 	ret = SQL_NO_DATA;
7955 	goto done;
7956     }
7957     len = strlen(logmsg);
7958     if (len == 0) {
7959 	ret = SQL_NO_DATA;
7960 	goto done;
7961     }
7962     if (nativeerr) {
7963 	*nativeerr = naterr;
7964     }
7965     if (sqlstate) {
7966 	strcpy((char *) sqlstate, sqlst);
7967     }
7968     if (msglen) {
7969 	*msglen = len;
7970     }
7971     if (len >= buflen) {
7972 	if (msg && buflen > 0) {
7973 	    strncpy((char *) msg, logmsg, buflen);
7974 	    msg[buflen - 1] = '\0';
7975 	    logmsg[0] = '\0';
7976 	}
7977     } else if (msg) {
7978 	strcpy((char *) msg, logmsg);
7979 	logmsg[0] = '\0';
7980     }
7981     ret = SQL_SUCCESS;
7982 done:
7983     switch (htype) {
7984     case SQL_HANDLE_DBC:
7985 	HDBC_UNLOCK((SQLHDBC) handle);
7986 	break;
7987     case SQL_HANDLE_STMT:
7988 	HSTMT_UNLOCK((SQLHSTMT) handle);
7989 	break;
7990     }
7991     return ret;
7992 }
7993 
7994 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
7995 /**
7996  * Get error message given handle (HENV, HDBC, or HSTMT).
7997  * @param htype handle type
7998  * @param handle HENV, HDBC, or HSTMT
7999  * @param recno
8000  * @param sqlstate output buffer for SQL state
8001  * @param nativeerr output buffer of native error code
8002  * @param msg output buffer for error message
8003  * @param buflen length of output buffer
8004  * @param msglen output length
8005  * @result ODBC error code
8006  */
8007 
8008 SQLRETURN SQL_API
SQLGetDiagRec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8009 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8010 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
8011 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8012 {
8013     return drvgetdiagrec(htype, handle, recno, sqlstate,
8014 			 nativeerr, msg, buflen, msglen);
8015 }
8016 #endif
8017 
8018 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
8019 #ifdef WINTERFACE
8020 /**
8021  * Get error message given handle (HENV, HDBC, or HSTMT)
8022  * (UNICODE version).
8023  * @param htype handle type
8024  * @param handle HENV, HDBC, or HSTMT
8025  * @param recno
8026  * @param sqlstate output buffer for SQL state
8027  * @param nativeerr output buffer of native error code
8028  * @param msg output buffer for error message
8029  * @param buflen length of output buffer
8030  * @param msglen output length
8031  * @result ODBC error code
8032  */
8033 
8034 SQLRETURN SQL_API
SQLGetDiagRecW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLWCHAR * sqlstate,SQLINTEGER * nativeerr,SQLWCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8035 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8036 	      SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
8037 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8038 {
8039     char state[16];
8040     SQLSMALLINT len;
8041     SQLRETURN ret;
8042 
8043     ret = drvgetdiagrec(htype, handle, recno, (SQLCHAR *) state,
8044 			nativeerr, (SQLCHAR *) msg, buflen, &len);
8045     if (ret == SQL_SUCCESS) {
8046 	if (sqlstate) {
8047 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlstate,
8048 			    6 * sizeof (SQLWCHAR));
8049 	}
8050 	if (msg) {
8051 	    if (len > 0) {
8052 		SQLWCHAR *m = NULL;
8053 
8054 		m = uc_from_utf((unsigned char *) msg, len);
8055 		if (m) {
8056 		    if (buflen) {
8057 			buflen /= sizeof (SQLWCHAR);
8058 			uc_strncpy(msg, m, buflen);
8059 			m[len] = 0;
8060 			len = min(buflen, uc_strlen(m));
8061 		    } else {
8062 			len = uc_strlen(m);
8063 		    }
8064 		    uc_free(m);
8065 		} else {
8066 		    len = 0;
8067 		}
8068 	    }
8069 	    if (len <= 0) {
8070 		len = 0;
8071 		if (buflen > 0) {
8072 		    msg[0] = 0;
8073 		}
8074 	    }
8075 	} else {
8076 	    /* estimated length !!! */
8077 	    len *= sizeof (SQLWCHAR);
8078 	}
8079 	if (msglen) {
8080 	    *msglen = len;
8081 	}
8082     } else if (ret == SQL_NO_DATA) {
8083 	if (sqlstate) {
8084 	    sqlstate[0] = 0;
8085 	}
8086 	if (msg) {
8087 	    if (buflen > 0) {
8088 		msg[0] = 0;
8089 	    }
8090 	}
8091 	if (msglen) {
8092 	    *msglen = 0;
8093 	}
8094     }
8095     return ret;
8096 }
8097 #endif
8098 #endif
8099 
8100 /**
8101  * Get error record given handle (HDBC or HSTMT).
8102  * @param htype handle type
8103  * @param handle HDBC or HSTMT
8104  * @param recno diag record number for which info to be retrieved
8105  * @param id diag id for which info to be retrieved
8106  * @param info output buffer for error message
8107  * @param buflen length of output buffer
8108  * @param stringlen output length
8109  * @result ODBC error code
8110  */
8111 
8112 static SQLRETURN
drvgetdiagfield(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8113 drvgetdiagfield(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8114 		SQLSMALLINT id, SQLPOINTER info,
8115 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8116 {
8117     DBC *d = NULL;
8118     STMT *s = NULL;
8119     int len, naterr;
8120     char *logmsg, *sqlst, *clrmsg = NULL;
8121     SQLRETURN ret = SQL_ERROR;
8122 
8123     if (handle == SQL_NULL_HANDLE) {
8124 	return SQL_INVALID_HANDLE;
8125     }
8126     if (stringlen) {
8127 	*stringlen = 0;
8128     }
8129     switch (htype) {
8130     case SQL_HANDLE_ENV:
8131     case SQL_HANDLE_DESC:
8132 	return SQL_NO_DATA;
8133     case SQL_HANDLE_DBC:
8134 	HDBC_LOCK((SQLHDBC) handle);
8135 	d = (DBC *) handle;
8136 	logmsg = (char *) d->logmsg;
8137 	sqlst = d->sqlstate;
8138 	naterr = d->naterr;
8139 	break;
8140     case SQL_HANDLE_STMT:
8141 	HSTMT_LOCK((SQLHSTMT) handle);
8142 	s = (STMT *) handle;
8143 	d = (DBC *) s->dbc;
8144 	logmsg = (char *) s->logmsg;
8145 	sqlst = s->sqlstate;
8146 	naterr = s->naterr;
8147 	break;
8148     default:
8149 	return SQL_INVALID_HANDLE;
8150     }
8151     if (buflen < 0) {
8152 	goto done;
8153     }
8154     if (recno > 1) {
8155 	ret = SQL_NO_DATA;
8156 	goto done;
8157     }
8158     switch (id) {
8159     case SQL_DIAG_CLASS_ORIGIN:
8160 	logmsg = "ISO 9075";
8161 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
8162 	    logmsg = "ODBC 3.0";
8163 	}
8164 	break;
8165     case SQL_DIAG_SUBCLASS_ORIGIN:
8166 	logmsg = "ISO 9075";
8167 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
8168 	    logmsg = "ODBC 3.0";
8169 	} else if (sqlst[0] == 'H' && sqlst[1] == 'Y') {
8170 	    logmsg = "ODBC 3.0";
8171 	} else if (sqlst[0] == '2' || sqlst[0] == '0' || sqlst[0] == '4') {
8172 	    logmsg = "ODBC 3.0";
8173 	}
8174 	break;
8175     case SQL_DIAG_CONNECTION_NAME:
8176     case SQL_DIAG_SERVER_NAME:
8177 	logmsg = d->dsn ? d->dsn : "No DSN";
8178 	break;
8179     case SQL_DIAG_SQLSTATE:
8180 	logmsg = sqlst;
8181 	break;
8182     case SQL_DIAG_MESSAGE_TEXT:
8183 	clrmsg = logmsg;
8184 	break;
8185     case SQL_DIAG_NUMBER:
8186 	naterr = 1;
8187 	/* fall through */
8188     case SQL_DIAG_NATIVE:
8189 	len = strlen(logmsg);
8190 	if (len == 0) {
8191 	    ret = SQL_NO_DATA;
8192 	    goto done;
8193 	}
8194 	if (info) {
8195 	    *((SQLINTEGER *) info) = naterr;
8196 	}
8197 	ret = SQL_SUCCESS;
8198 	goto done;
8199     default:
8200 	goto done;
8201     }
8202     if (info && buflen > 0) {
8203 	((char *) info)[0] = '\0';
8204     }
8205     len = strlen(logmsg);
8206     if (len == 0) {
8207 	ret = SQL_NO_DATA;
8208 	goto done;
8209     }
8210     if (stringlen) {
8211 	*stringlen = len;
8212     }
8213     if (len >= buflen) {
8214 	if (info && buflen > 0) {
8215 	    if (stringlen) {
8216 		*stringlen = buflen - 1;
8217 	    }
8218 	    strncpy((char *) info, logmsg, buflen);
8219 	    ((char *) info)[buflen - 1] = '\0';
8220 	}
8221     } else if (info) {
8222 	strcpy((char *) info, logmsg);
8223     }
8224     if (clrmsg) {
8225 	*clrmsg = '\0';
8226     }
8227     ret = SQL_SUCCESS;
8228 done:
8229     switch (htype) {
8230     case SQL_HANDLE_DBC:
8231 	HDBC_UNLOCK((SQLHDBC) handle);
8232 	break;
8233     case SQL_HANDLE_STMT:
8234 	HSTMT_UNLOCK((SQLHSTMT) handle);
8235 	break;
8236     }
8237     return ret;
8238 }
8239 
8240 #ifndef WINTERFACE
8241 /**
8242  * Get error record given handle (HDBC or HSTMT).
8243  * @param htype handle type
8244  * @param handle HDBC or HSTMT
8245  * @param recno diag record number for which info to be retrieved
8246  * @param id diag id for which info to be retrieved
8247  * @param info output buffer for error message
8248  * @param buflen length of output buffer
8249  * @param stringlen output length
8250  * @result ODBC error code
8251  */
8252 
8253 SQLRETURN SQL_API
SQLGetDiagField(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8254 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8255 		SQLSMALLINT id, SQLPOINTER info,
8256 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8257 {
8258     return drvgetdiagfield(htype, handle, recno, id, info, buflen, stringlen);
8259 }
8260 #endif
8261 
8262 #ifdef WINTERFACE
8263 /**
8264  * Get error record given handle (HDBC or HSTMT).
8265  * @param htype handle type
8266  * @param handle HDBC or HSTMT
8267  * @param recno diag record number for which info to be retrieved
8268  * @param id diag id for which info to be retrieved
8269  * @param info output buffer for error message
8270  * @param buflen length of output buffer
8271  * @param stringlen output length
8272  * @result ODBC error code
8273  */
8274 
8275 SQLRETURN SQL_API
SQLGetDiagFieldW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8276 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8277 		 SQLSMALLINT id, SQLPOINTER info,
8278 		 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8279 {
8280     SQLSMALLINT len;
8281     SQLRETURN ret;
8282 
8283     ret = drvgetdiagfield(htype, handle, recno, id, info, buflen, &len);
8284     if (ret == SQL_SUCCESS) {
8285 	if (info) {
8286 	    switch (id) {
8287 	    case SQL_DIAG_CLASS_ORIGIN:
8288 	    case SQL_DIAG_SUBCLASS_ORIGIN:
8289 	    case SQL_DIAG_CONNECTION_NAME:
8290 	    case SQL_DIAG_SERVER_NAME:
8291 	    case SQL_DIAG_SQLSTATE:
8292 	    case SQL_DIAG_MESSAGE_TEXT:
8293 		if (len > 0) {
8294 		    SQLWCHAR *m = NULL;
8295 
8296 		    m = uc_from_utf((unsigned char *) info, len);
8297 		    if (m) {
8298 			if (buflen) {
8299 			    buflen /= sizeof (SQLWCHAR);
8300 			    uc_strncpy(info, m, buflen);
8301 			    m[len] = 0;
8302 			    len = min(buflen, uc_strlen(m));
8303 			} else {
8304 			    len = uc_strlen(m);
8305 			}
8306 			uc_free(m);
8307 			len *= sizeof (SQLWCHAR);
8308 		    } else {
8309 			len = 0;
8310 		    }
8311 		}
8312 		if (len <= 0) {
8313 		    len = 0;
8314 		    if (buflen > 0) {
8315 			((SQLWCHAR *) info)[0] = 0;
8316 		    }
8317 		}
8318 	    }
8319 	} else {
8320 	    switch (id) {
8321 	    case SQL_DIAG_CLASS_ORIGIN:
8322 	    case SQL_DIAG_SUBCLASS_ORIGIN:
8323 	    case SQL_DIAG_CONNECTION_NAME:
8324 	    case SQL_DIAG_SERVER_NAME:
8325 	    case SQL_DIAG_SQLSTATE:
8326 	    case SQL_DIAG_MESSAGE_TEXT:
8327 		len *= sizeof (SQLWCHAR);
8328 		break;
8329 	    }
8330 	}
8331 	if (stringlen) {
8332 	    *stringlen = len;
8333 	}
8334     }
8335     return ret;
8336 }
8337 #endif
8338 
8339 /**
8340  * Internal get option of HSTMT.
8341  * @param stmt statement handle
8342  * @param attr attribute to be retrieved
8343  * @param val output buffer
8344  * @param bufmax length of output buffer
8345  * @param buflen output length
8346  * @result ODBC error code
8347  */
8348 
8349 static SQLRETURN
drvgetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)8350 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8351 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
8352 {
8353     STMT *s = (STMT *) stmt;
8354     SQLULEN *uval = (SQLULEN *) val;
8355 
8356     switch (attr) {
8357     case SQL_QUERY_TIMEOUT:
8358 	*uval = 0;
8359 	return SQL_SUCCESS;
8360     case SQL_ATTR_CURSOR_TYPE:
8361 	*uval = s->curtype;
8362 	return SQL_SUCCESS;
8363     case SQL_ATTR_CURSOR_SCROLLABLE:
8364 	*uval = (s->curtype != SQL_CURSOR_FORWARD_ONLY) ?
8365 	    SQL_SCROLLABLE : SQL_NONSCROLLABLE;
8366 	return SQL_SUCCESS;
8367 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
8368     case SQL_ATTR_CURSOR_SENSITIVITY:
8369 	*uval = SQL_UNSPECIFIED;
8370 	return SQL_SUCCESS;
8371 #endif
8372     case SQL_ATTR_ROW_NUMBER:
8373 	if (s->s3stmt) {
8374 	    *uval = (s->s3stmt_rownum < 0) ?
8375 		    SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
8376 	} else {
8377 	    *uval = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
8378 	}
8379 	return SQL_SUCCESS;
8380     case SQL_ATTR_ASYNC_ENABLE:
8381 	*uval = SQL_ASYNC_ENABLE_OFF;
8382 	return SQL_SUCCESS;
8383     case SQL_CONCURRENCY:
8384 	*uval = SQL_CONCUR_LOCK;
8385 	return SQL_SUCCESS;
8386     case SQL_ATTR_RETRIEVE_DATA:
8387 	*uval = s->retr_data;
8388 	return SQL_SUCCESS;
8389     case SQL_ROWSET_SIZE:
8390     case SQL_ATTR_ROW_ARRAY_SIZE:
8391 	*uval = s->rowset_size;
8392 	return SQL_SUCCESS;
8393     /* Needed for some driver managers, but dummies for now */
8394     case SQL_ATTR_IMP_ROW_DESC:
8395     case SQL_ATTR_APP_ROW_DESC:
8396     case SQL_ATTR_IMP_PARAM_DESC:
8397     case SQL_ATTR_APP_PARAM_DESC:
8398 	*((SQLHDESC *) val) = (SQLHDESC) DEAD_MAGIC;
8399 	return SQL_SUCCESS;
8400     case SQL_ATTR_ROW_STATUS_PTR:
8401 	*((SQLUSMALLINT **) val) = s->row_status;
8402 	return SQL_SUCCESS;
8403     case SQL_ATTR_ROWS_FETCHED_PTR:
8404 	*((SQLULEN **) val) = s->row_count;
8405 	return SQL_SUCCESS;
8406     case SQL_ATTR_USE_BOOKMARKS: {
8407 	STMT *s = (STMT *) stmt;
8408 
8409 	*(SQLUINTEGER *) val = s->bkmrk ? SQL_UB_ON : SQL_UB_OFF;
8410 	return SQL_SUCCESS;
8411     }
8412     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
8413 	*((SQLULEN **) val) = s->parm_bind_offs;
8414 	return SQL_SUCCESS;
8415     case SQL_ATTR_PARAM_BIND_TYPE:
8416 	*((SQLULEN *) val) = s->parm_bind_type;
8417 	return SQL_SUCCESS;
8418     case SQL_ATTR_PARAM_OPERATION_PTR:
8419 	*((SQLUSMALLINT **) val) = s->parm_oper;
8420 	return SQL_SUCCESS;
8421     case SQL_ATTR_PARAM_STATUS_PTR:
8422 	*((SQLUSMALLINT **) val) = s->parm_status;
8423 	return SQL_SUCCESS;
8424     case SQL_ATTR_PARAMS_PROCESSED_PTR:
8425 	*((SQLULEN **) val) = s->parm_proc;
8426 	return SQL_SUCCESS;
8427     case SQL_ATTR_PARAMSET_SIZE:
8428 	*((SQLULEN *) val) = s->paramset_size;
8429 	return SQL_SUCCESS;
8430     case SQL_ATTR_ROW_BIND_TYPE:
8431 	*(SQLULEN *) val = s->bind_type;
8432 	return SQL_SUCCESS;
8433     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
8434 	*((SQLULEN **) val) = s->bind_offs;
8435 	return SQL_SUCCESS;
8436     case SQL_ATTR_MAX_ROWS:
8437 	*((SQLULEN *) val) = s->max_rows;
8438     case SQL_ATTR_MAX_LENGTH:
8439 	*((SQLINTEGER *) val) = 1000000000;
8440 	return SQL_SUCCESS;
8441 #ifdef SQL_ATTR_METADATA_ID
8442     case SQL_ATTR_METADATA_ID:
8443 	*((SQLULEN *) val) = SQL_FALSE;
8444 	return SQL_SUCCESS;
8445 #endif
8446     }
8447     return drvunimplstmt(stmt);
8448 }
8449 
8450 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
8451 /**
8452  * Get option of HSTMT.
8453  * @param stmt statement handle
8454  * @param attr attribute to be retrieved
8455  * @param val output buffer
8456  * @param bufmax length of output buffer
8457  * @param buflen output length
8458  * @result ODBC error code
8459  */
8460 
8461 SQLRETURN SQL_API
SQLGetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)8462 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8463 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
8464 {
8465     SQLRETURN ret;
8466 
8467     HSTMT_LOCK(stmt);
8468     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
8469     HSTMT_UNLOCK(stmt);
8470     return ret;
8471 }
8472 #endif
8473 
8474 #ifdef WINTERFACE
8475 /**
8476  * Get option of HSTMT (UNICODE version).
8477  * @param stmt statement handle
8478  * @param attr attribute to be retrieved
8479  * @param val output buffer
8480  * @param bufmax length of output buffer
8481  * @param buflen output length
8482  * @result ODBC error code
8483  */
8484 
8485 SQLRETURN SQL_API
SQLGetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)8486 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8487 		SQLINTEGER bufmax, SQLINTEGER *buflen)
8488 {
8489     SQLRETURN ret;
8490 
8491     HSTMT_LOCK(stmt);
8492     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
8493     HSTMT_UNLOCK(stmt);
8494     return ret;
8495 }
8496 #endif
8497 
8498 /**
8499  * Internal set option on HSTMT.
8500  * @param stmt statement handle
8501  * @param attr attribute to be set
8502  * @param val input buffer (attribute value)
8503  * @param buflen length of input buffer
8504  * @result ODBC error code
8505  */
8506 
8507 static SQLRETURN
drvsetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)8508 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8509 	       SQLINTEGER buflen)
8510 {
8511     STMT *s = (STMT *) stmt;
8512 #if defined(SQL_BIGINT) && defined(__WORDSIZE) && (__WORDSIZE == 64)
8513     SQLBIGINT uval;
8514 
8515     uval = (SQLBIGINT) val;
8516 #else
8517     SQLULEN uval;
8518 
8519     uval = (SQLULEN) val;
8520 #endif
8521     switch (attr) {
8522     case SQL_ATTR_CURSOR_TYPE:
8523 	if (val == (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY) {
8524 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
8525 	} else {
8526 	    s->curtype = SQL_CURSOR_STATIC;
8527 	}
8528 	if (val != (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY &&
8529 	    val != (SQLPOINTER) SQL_CURSOR_STATIC) {
8530 	    goto e01s02;
8531 	}
8532 	return SQL_SUCCESS;
8533     case SQL_ATTR_CURSOR_SCROLLABLE:
8534 	if (val == (SQLPOINTER) SQL_NONSCROLLABLE) {
8535 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
8536 	} else {
8537 	    s->curtype = SQL_CURSOR_STATIC;
8538 	}
8539 	return SQL_SUCCESS;
8540     case SQL_ATTR_ASYNC_ENABLE:
8541 	if (val != (SQLPOINTER) SQL_ASYNC_ENABLE_OFF) {
8542     e01s02:
8543 	    setstat(s, -1, "option value changed", "01S02");
8544 	    return SQL_SUCCESS_WITH_INFO;
8545 	}
8546 	return SQL_SUCCESS;
8547     case SQL_CONCURRENCY:
8548 	if (val != (SQLPOINTER) SQL_CONCUR_LOCK) {
8549 	    goto e01s02;
8550 	}
8551 	return SQL_SUCCESS;
8552 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
8553     case SQL_ATTR_CURSOR_SENSITIVITY:
8554 	if (val != (SQLPOINTER) SQL_UNSPECIFIED) {
8555 	    goto e01s02;
8556 	}
8557 	return SQL_SUCCESS;
8558 #endif
8559     case SQL_ATTR_QUERY_TIMEOUT:
8560 	return SQL_SUCCESS;
8561     case SQL_ATTR_RETRIEVE_DATA:
8562 	if (val != (SQLPOINTER) SQL_RD_ON &&
8563 	    val != (SQLPOINTER) SQL_RD_OFF) {
8564 	    goto e01s02;
8565 	}
8566 	s->retr_data = uval;
8567 	return SQL_SUCCESS;
8568     case SQL_ROWSET_SIZE:
8569     case SQL_ATTR_ROW_ARRAY_SIZE:
8570 	if (uval < 1) {
8571 	    setstat(s, -1, "invalid rowset size", "HY000");
8572 	    return SQL_ERROR;
8573 	} else {
8574 	    SQLUSMALLINT *rst = &s->row_status1;
8575 
8576 	    if (uval > 1) {
8577 		rst = xmalloc(sizeof (SQLUSMALLINT) * uval);
8578 		if (!rst) {
8579 		    return nomem(s);
8580 		}
8581 	    }
8582 	    if (s->row_status0 != &s->row_status1) {
8583 		freep(&s->row_status0);
8584 	    }
8585 	    s->row_status0 = rst;
8586 	    s->rowset_size = uval;
8587 	}
8588 	return SQL_SUCCESS;
8589     case SQL_ATTR_ROW_STATUS_PTR:
8590 	s->row_status = (SQLUSMALLINT *) val;
8591 	return SQL_SUCCESS;
8592     case SQL_ATTR_ROWS_FETCHED_PTR:
8593 	s->row_count = (SQLULEN *) val;
8594 	return SQL_SUCCESS;
8595     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
8596 	s->parm_bind_offs = (SQLULEN *) val;
8597 	return SQL_SUCCESS;
8598     case SQL_ATTR_PARAM_BIND_TYPE:
8599 	s->parm_bind_type = uval;
8600 	return SQL_SUCCESS;
8601     case SQL_ATTR_PARAM_OPERATION_PTR:
8602 	s->parm_oper = (SQLUSMALLINT *) val;
8603 	return SQL_SUCCESS;
8604     case SQL_ATTR_PARAM_STATUS_PTR:
8605 	s->parm_status = (SQLUSMALLINT *) val;
8606 	return SQL_SUCCESS;
8607     case SQL_ATTR_PARAMS_PROCESSED_PTR:
8608 	s->parm_proc = (SQLULEN *) val;
8609 	return SQL_SUCCESS;
8610     case SQL_ATTR_PARAMSET_SIZE:
8611 	if (uval < 1) {
8612 	    goto e01s02;
8613 	}
8614 	s->paramset_size = uval;
8615 	s->paramset_count = 0;
8616 	return SQL_SUCCESS;
8617     case SQL_ATTR_ROW_BIND_TYPE:
8618 	s->bind_type = uval;
8619 	return SQL_SUCCESS;
8620     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
8621 	s->bind_offs = (SQLULEN *) val;
8622 	return SQL_SUCCESS;
8623     case SQL_ATTR_USE_BOOKMARKS:
8624 	if (val != (SQLPOINTER) SQL_UB_OFF &&
8625 	    val != (SQLPOINTER) SQL_UB_ON) {
8626 	    goto e01s02;
8627 	}
8628 	s->bkmrk = val == (SQLPOINTER) SQL_UB_ON;
8629 	return SQL_SUCCESS;
8630     case SQL_ATTR_MAX_ROWS:
8631 	s->max_rows = uval;
8632 	return SQL_SUCCESS;
8633     case SQL_ATTR_MAX_LENGTH:
8634 	if (val != (SQLPOINTER) 1000000000) {
8635 	    goto e01s02;
8636 	}
8637 	return SQL_SUCCESS;
8638 #ifdef SQL_ATTR_METADATA_ID
8639     case SQL_ATTR_METADATA_ID:
8640 	if (val != (SQLPOINTER) SQL_FALSE) {
8641 	    goto e01s02;
8642 	}
8643 	return SQL_SUCCESS;
8644 #endif
8645     }
8646     return drvunimplstmt(stmt);
8647 }
8648 
8649 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
8650 /**
8651  * Set option on HSTMT.
8652  * @param stmt statement handle
8653  * @param attr attribute to be set
8654  * @param val input buffer (attribute value)
8655  * @param buflen length of input buffer
8656  * @result ODBC error code
8657  */
8658 
8659 SQLRETURN SQL_API
SQLSetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)8660 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8661 	       SQLINTEGER buflen)
8662 {
8663     SQLRETURN ret;
8664 
8665     HSTMT_LOCK(stmt);
8666     ret = drvsetstmtattr(stmt, attr, val, buflen);
8667     HSTMT_UNLOCK(stmt);
8668     return ret;
8669 }
8670 #endif
8671 
8672 #ifdef WINTERFACE
8673 /**
8674  * Set option on HSTMT (UNICODE version).
8675  * @param stmt statement handle
8676  * @param attr attribute to be set
8677  * @param val input buffer (attribute value)
8678  * @param buflen length of input buffer
8679  * @result ODBC error code
8680  */
8681 
8682 SQLRETURN SQL_API
SQLSetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)8683 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8684 		SQLINTEGER buflen)
8685 {
8686     SQLRETURN ret;
8687 
8688     HSTMT_LOCK(stmt);
8689     ret = drvsetstmtattr(stmt, attr, val, buflen);
8690     HSTMT_UNLOCK(stmt);
8691     return ret;
8692 }
8693 #endif
8694 
8695 /**
8696  * Internal get option of HSTMT.
8697  * @param stmt statement handle
8698  * @param opt option to be retrieved
8699  * @param param output buffer
8700  * @result ODBC error code
8701  */
8702 
8703 static SQLRETURN
drvgetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)8704 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
8705 {
8706     STMT *s = (STMT *) stmt;
8707     SQLUINTEGER *ret = (SQLUINTEGER *) param;
8708 
8709     switch (opt) {
8710     case SQL_QUERY_TIMEOUT:
8711 	*ret = 0;
8712 	return SQL_SUCCESS;
8713     case SQL_CURSOR_TYPE:
8714 	*ret = s->curtype;
8715 	return SQL_SUCCESS;
8716     case SQL_ROW_NUMBER:
8717 	if (s->s3stmt) {
8718 	    *ret = (s->s3stmt_rownum < 0) ?
8719 		   SQL_ROW_NUMBER_UNKNOWN : (s->s3stmt_rownum + 1);
8720 	} else {
8721 	    *ret = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
8722 	}
8723 	return SQL_SUCCESS;
8724     case SQL_ASYNC_ENABLE:
8725 	*ret = SQL_ASYNC_ENABLE_OFF;
8726 	return SQL_SUCCESS;
8727     case SQL_CONCURRENCY:
8728 	*ret = SQL_CONCUR_LOCK;
8729 	return SQL_SUCCESS;
8730     case SQL_ATTR_RETRIEVE_DATA:
8731 	*ret = s->retr_data;
8732 	return SQL_SUCCESS;
8733     case SQL_ROWSET_SIZE:
8734     case SQL_ATTR_ROW_ARRAY_SIZE:
8735 	*ret = s->rowset_size;
8736 	return SQL_SUCCESS;
8737     case SQL_ATTR_MAX_ROWS:
8738 	*ret = s->max_rows;
8739 	return SQL_SUCCESS;
8740     case SQL_ATTR_MAX_LENGTH:
8741 	*ret = 1000000000;
8742 	return SQL_SUCCESS;
8743     }
8744     return drvunimplstmt(stmt);
8745 }
8746 
8747 /**
8748  * Get option of HSTMT.
8749  * @param stmt statement handle
8750  * @param opt option to be retrieved
8751  * @param param output buffer
8752  * @result ODBC error code
8753  */
8754 
8755 SQLRETURN SQL_API
SQLGetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)8756 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
8757 {
8758     SQLRETURN ret;
8759 
8760     HSTMT_LOCK(stmt);
8761     ret = drvgetstmtoption(stmt, opt, param);
8762     HSTMT_UNLOCK(stmt);
8763     return ret;
8764 }
8765 
8766 #ifdef WINTERFACE
8767 /**
8768  * Get option of HSTMT (UNICODE version).
8769  * @param stmt statement handle
8770  * @param opt option to be retrieved
8771  * @param param output buffer
8772  * @result ODBC error code
8773  */
8774 
8775 SQLRETURN SQL_API
SQLGetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)8776 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
8777 {
8778     SQLRETURN ret;
8779 
8780     HSTMT_LOCK(stmt);
8781     ret = drvgetstmtoption(stmt, opt, param);
8782     HSTMT_UNLOCK(stmt);
8783     return ret;
8784 }
8785 #endif
8786 
8787 /**
8788  * Internal set option on HSTMT.
8789  * @param stmt statement handle
8790  * @param opt option to be set
8791  * @param param input buffer (option value)
8792  * @result ODBC error code
8793  */
8794 
8795 static SQLRETURN
drvsetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLUINTEGER param)8796 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
8797 {
8798     STMT *s = (STMT *) stmt;
8799 
8800     switch (opt) {
8801     case SQL_CURSOR_TYPE:
8802 	if (param == SQL_CURSOR_FORWARD_ONLY) {
8803 	    s->curtype = param;
8804 	} else {
8805 	    s->curtype = SQL_CURSOR_STATIC;
8806 	}
8807 	if (param != SQL_CURSOR_FORWARD_ONLY &&
8808 	    param != SQL_CURSOR_STATIC) {
8809 	    goto e01s02;
8810 	}
8811 	return SQL_SUCCESS;
8812     case SQL_ASYNC_ENABLE:
8813 	if (param != SQL_ASYNC_ENABLE_OFF) {
8814 	    goto e01s02;
8815 	}
8816 	return SQL_SUCCESS;
8817     case SQL_CONCURRENCY:
8818 	if (param != SQL_CONCUR_LOCK) {
8819 	    goto e01s02;
8820 	}
8821 	return SQL_SUCCESS;
8822     case SQL_QUERY_TIMEOUT:
8823 	return SQL_SUCCESS;
8824     case SQL_RETRIEVE_DATA:
8825 	if (param != SQL_RD_ON && param != SQL_RD_OFF) {
8826     e01s02:
8827 	    setstat(s, -1, "option value changed", "01S02");
8828 	    return SQL_SUCCESS_WITH_INFO;
8829 	}
8830 	s->retr_data = (int) param;
8831 	return SQL_SUCCESS;
8832     case SQL_ROWSET_SIZE:
8833     case SQL_ATTR_ROW_ARRAY_SIZE:
8834 	if (param < 1) {
8835 	    setstat(s, -1, "invalid rowset size", "HY000");
8836 	    return SQL_ERROR;
8837 	} else {
8838 	    SQLUSMALLINT *rst = &s->row_status1;
8839 
8840 	    if (param > 1) {
8841 		rst = xmalloc(sizeof (SQLUSMALLINT) * param);
8842 		if (!rst) {
8843 		    return nomem(s);
8844 		}
8845 	    }
8846 	    if (s->row_status0 != &s->row_status1) {
8847 		freep(&s->row_status0);
8848 	    }
8849 	    s->row_status0 = rst;
8850 	    s->rowset_size = param;
8851 	}
8852 	return SQL_SUCCESS;
8853     case SQL_ATTR_MAX_ROWS:
8854 	s->max_rows = param;
8855 	return SQL_SUCCESS;
8856     case SQL_ATTR_MAX_LENGTH:
8857 	if (param != 1000000000) {
8858 	    goto e01s02;
8859 	}
8860 	return SQL_SUCCESS;
8861     }
8862     return drvunimplstmt(stmt);
8863 }
8864 
8865 /**
8866  * Set option on HSTMT.
8867  * @param stmt statement handle
8868  * @param opt option to be set
8869  * @param param input buffer (option value)
8870  * @result ODBC error code
8871  */
8872 
8873 SQLRETURN SQL_API
SQLSetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)8874 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt,
8875 		 SETSTMTOPTION_LAST_ARG_TYPE param)
8876 {
8877     SQLRETURN ret;
8878 
8879     HSTMT_LOCK(stmt);
8880     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
8881     HSTMT_UNLOCK(stmt);
8882     return ret;
8883 }
8884 
8885 #ifdef WINTERFACE
8886 /**
8887  * Set option on HSTMT (UNICODE version).
8888  * @param stmt statement handle
8889  * @param opt option to be set
8890  * @param param input buffer (option value)
8891  * @result ODBC error code
8892  */
8893 
8894 SQLRETURN SQL_API
SQLSetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)8895 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt,
8896 		  SETSTMTOPTION_LAST_ARG_TYPE param)
8897 {
8898     SQLRETURN ret;
8899 
8900     HSTMT_LOCK(stmt);
8901     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
8902     HSTMT_UNLOCK(stmt);
8903     return ret;
8904 }
8905 #endif
8906 
8907 /**
8908  * Internal set position on result in HSTMT.
8909  * @param stmt statement handle
8910  * @param row row to be positioned
8911  * @param op operation code
8912  * @param lock locking type
8913  * @result ODBC error code
8914  */
8915 
8916 static SQLRETURN
drvsetpos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)8917 drvsetpos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
8918 {
8919     STMT *s = (STMT *) stmt;
8920     int rowp;
8921 
8922     if (op != SQL_POSITION) {
8923 	return drvunimplstmt(stmt);
8924     }
8925     rowp = s->rowp + row - 1;
8926     if (!s->rows || row <= 0 || rowp < -1 || rowp >= s->nrows) {
8927 	setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
8928 	return SQL_ERROR;
8929     }
8930     s->rowp = rowp;
8931     return SQL_SUCCESS;
8932 }
8933 
8934 /**
8935  * Set position on result in HSTMT.
8936  * @param stmt statement handle
8937  * @param row row to be positioned
8938  * @param op operation code
8939  * @param lock locking type
8940  * @result ODBC error code
8941  */
8942 
8943 SQLRETURN SQL_API
SQLSetPos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)8944 SQLSetPos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
8945 {
8946     SQLRETURN ret;
8947 
8948     HSTMT_LOCK(stmt);
8949     ret = drvsetpos(stmt, row, op, lock);
8950     HSTMT_UNLOCK(stmt);
8951     return ret;
8952 }
8953 
8954 /**
8955  * Function not implemented.
8956  */
8957 
8958 SQLRETURN SQL_API
SQLSetScrollOptions(SQLHSTMT stmt,SQLUSMALLINT concur,SQLLEN rowkeyset,SQLUSMALLINT rowset)8959 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
8960 		    SQLUSMALLINT rowset)
8961 {
8962     SQLRETURN ret;
8963 
8964     HSTMT_LOCK(stmt);
8965     ret = drvunimplstmt(stmt);
8966     HSTMT_UNLOCK(stmt);
8967     return ret;
8968 }
8969 
8970 #define strmak(dst, src, max, lenp) { \
8971     int len = strlen(src); \
8972     int cnt = min(len + 1, max); \
8973     strncpy(dst, src, cnt); \
8974     *lenp = (cnt > len) ? len : cnt; \
8975 }
8976 
8977 /**
8978  * Internal return information about what this ODBC driver supports.
8979  * @param dbc database connection handle
8980  * @param type type of information to be retrieved
8981  * @param val output buffer
8982  * @param valMax length of output buffer
8983  * @param valLen output length
8984  * @result ODBC error code
8985  */
8986 
8987 static SQLRETURN
drvgetinfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)8988 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
8989 	   SQLSMALLINT *valLen)
8990 {
8991     DBC *d;
8992     char dummyc[16];
8993     SQLSMALLINT dummy;
8994 #if defined(_WIN32) || defined(_WIN64)
8995     char drvname[301];
8996 #else
8997     static char drvname[] = "sqlite3odbc.so";
8998 #endif
8999 
9000     if (dbc == SQL_NULL_HDBC) {
9001 	return SQL_INVALID_HANDLE;
9002     }
9003     d = (DBC *) dbc;
9004     if (valMax) {
9005 	valMax--;
9006     }
9007     if (!valLen) {
9008 	valLen = &dummy;
9009     }
9010     if (!val) {
9011 	val = dummyc;
9012 	valMax = sizeof (dummyc) - 1;
9013     }
9014     switch (type) {
9015     case SQL_MAX_USER_NAME_LEN:
9016 	*((SQLSMALLINT *) val) = 16;
9017 	*valLen = sizeof (SQLSMALLINT);
9018 	break;
9019     case SQL_USER_NAME:
9020 	strmak(val, "", valMax, valLen);
9021 	break;
9022     case SQL_DRIVER_ODBC_VER:
9023 #if 0
9024 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
9025 #else
9026 	strmak(val, "03.00", valMax, valLen);
9027 #endif
9028 	break;
9029     case SQL_ACTIVE_CONNECTIONS:
9030     case SQL_ACTIVE_STATEMENTS:
9031 	*((SQLSMALLINT *) val) = 0;
9032 	*valLen = sizeof (SQLSMALLINT);
9033 	break;
9034 #ifdef SQL_ASYNC_MODE
9035     case SQL_ASYNC_MODE:
9036 	*((SQLUINTEGER *) val) = SQL_AM_NONE;
9037 	*valLen = sizeof (SQLUINTEGER);
9038 	break;
9039 #endif
9040 #ifdef SQL_CREATE_TABLE
9041     case SQL_CREATE_TABLE:
9042 	*((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
9043 				 SQL_CT_COLUMN_DEFAULT |
9044 				 SQL_CT_COLUMN_CONSTRAINT |
9045 				 SQL_CT_CONSTRAINT_NON_DEFERRABLE;
9046 	*valLen = sizeof (SQLUINTEGER);
9047 	break;
9048 #endif
9049 #ifdef SQL_CREATE_VIEW
9050     case SQL_CREATE_VIEW:
9051 	*((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
9052 	*valLen = sizeof (SQLUINTEGER);
9053 	break;
9054 #endif
9055 #ifdef SQL_DDL_INDEX
9056     case SQL_DDL_INDEX:
9057 	*((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
9058 	*valLen = sizeof (SQLUINTEGER);
9059 	break;
9060 #endif
9061 #ifdef SQL_DROP_TABLE
9062     case SQL_DROP_TABLE:
9063 	*((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
9064 	*valLen = sizeof (SQLUINTEGER);
9065 	break;
9066 #endif
9067 #ifdef SQL_DROP_VIEW
9068     case SQL_DROP_VIEW:
9069 	*((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
9070 	*valLen = sizeof (SQLUINTEGER);
9071 	break;
9072 #endif
9073 #ifdef SQL_INDEX_KEYWORDS
9074     case SQL_INDEX_KEYWORDS:
9075 	*((SQLUINTEGER *) val) = SQL_IK_ALL;
9076 	*valLen = sizeof (SQLUINTEGER);
9077 	break;
9078 #endif
9079     case SQL_DATA_SOURCE_NAME:
9080 	strmak(val, d->dsn ? d->dsn : "", valMax, valLen);
9081 	break;
9082     case SQL_DRIVER_NAME:
9083 #if defined(_WIN32) || defined(_WIN64)
9084 	GetModuleFileName(hModule, drvname, sizeof (drvname));
9085 #endif
9086 	strmak(val, drvname, valMax, valLen);
9087 	break;
9088     case SQL_DRIVER_VER:
9089 	strmak(val, DRIVER_VER_INFO, valMax, valLen);
9090 	break;
9091     case SQL_FETCH_DIRECTION:
9092 	*((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
9093 	    SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
9094 	*valLen = sizeof (SQLUINTEGER);
9095 	break;
9096     case SQL_ODBC_VER:
9097 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
9098 	break;
9099     case SQL_ODBC_SAG_CLI_CONFORMANCE:
9100 	*((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
9101 	*valLen = sizeof (SQLSMALLINT);
9102 	break;
9103     case SQL_STANDARD_CLI_CONFORMANCE:
9104 	*((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
9105 	*valLen = sizeof (SQLUINTEGER);
9106 	break;
9107     case SQL_SERVER_NAME:
9108     case SQL_DATABASE_NAME:
9109 	strmak(val, d->dbname ? d->dbname : "", valMax, valLen);
9110 	break;
9111     case SQL_SEARCH_PATTERN_ESCAPE:
9112 	strmak(val, "\\", valMax, valLen);
9113 	break;
9114     case SQL_ODBC_SQL_CONFORMANCE:
9115 	*((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
9116 	*valLen = sizeof (SQLSMALLINT);
9117 	break;
9118     case SQL_ODBC_API_CONFORMANCE:
9119 	*((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
9120 	*valLen = sizeof (SQLSMALLINT);
9121 	break;
9122     case SQL_DBMS_NAME:
9123 	strmak(val, "SQLite", valMax, valLen);
9124 	break;
9125     case SQL_DBMS_VER:
9126 	strmak(val, SQLITE_VERSION, valMax, valLen);
9127 	break;
9128     case SQL_COLUMN_ALIAS:
9129     case SQL_NEED_LONG_DATA_LEN:
9130 	strmak(val, "Y", valMax, valLen);
9131 	break;
9132     case SQL_ROW_UPDATES:
9133     case SQL_ACCESSIBLE_PROCEDURES:
9134     case SQL_PROCEDURES:
9135     case SQL_EXPRESSIONS_IN_ORDERBY:
9136     case SQL_ODBC_SQL_OPT_IEF:
9137     case SQL_LIKE_ESCAPE_CLAUSE:
9138     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
9139     case SQL_OUTER_JOINS:
9140     case SQL_ACCESSIBLE_TABLES:
9141     case SQL_MULT_RESULT_SETS:
9142     case SQL_MULTIPLE_ACTIVE_TXN:
9143     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
9144 	strmak(val, "N", valMax, valLen);
9145 	break;
9146 #ifdef SQL_CATALOG_NAME
9147     case SQL_CATALOG_NAME:
9148 #if defined(_WIN32) || defined(_WIN64)
9149 	strmak(val, d->xcelqrx ? "Y" : "N", valMax, valLen);
9150 #else
9151 	strmak(val, "N", valMax, valLen);
9152 #endif
9153 	break;
9154 #endif
9155     case SQL_DATA_SOURCE_READ_ONLY:
9156 	strmak(val, "N", valMax, valLen);
9157 	break;
9158 #ifdef SQL_OJ_CAPABILITIES
9159     case SQL_OJ_CAPABILITIES:
9160 	*((SQLUINTEGER *) val) = 0;
9161 	*valLen = sizeof (SQLUINTEGER);
9162 	break;
9163 #endif
9164 #ifdef SQL_MAX_IDENTIFIER_LEN
9165     case SQL_MAX_IDENTIFIER_LEN:
9166 	*((SQLUSMALLINT *) val) = 255;
9167 	*valLen = sizeof (SQLUSMALLINT);
9168 	break;
9169 #endif
9170     case SQL_CONCAT_NULL_BEHAVIOR:
9171 	*((SQLSMALLINT *) val) = SQL_CB_NULL;
9172 	*valLen = sizeof (SQLSMALLINT);
9173 	break;
9174     case SQL_CURSOR_COMMIT_BEHAVIOR:
9175     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
9176 	*((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
9177 	*valLen = sizeof (SQLSMALLINT);
9178 	break;
9179 #ifdef SQL_CURSOR_SENSITIVITY
9180     case SQL_CURSOR_SENSITIVITY:
9181 	*((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
9182 	*valLen = sizeof (SQLUINTEGER);
9183 	break;
9184 #endif
9185     case SQL_DEFAULT_TXN_ISOLATION:
9186 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
9187 	*valLen = sizeof (SQLUINTEGER);
9188 	break;
9189 #ifdef SQL_DESCRIBE_PARAMETER
9190     case SQL_DESCRIBE_PARAMETER:
9191 	strmak(val, "Y", valMax, valLen);
9192 	break;
9193 #endif
9194     case SQL_TXN_ISOLATION_OPTION:
9195 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
9196 	*valLen = sizeof (SQLUINTEGER);
9197 	break;
9198     case SQL_IDENTIFIER_CASE:
9199 	*((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
9200 	*valLen = sizeof (SQLSMALLINT);
9201 	break;
9202     case SQL_IDENTIFIER_QUOTE_CHAR:
9203 	strmak(val, "\"", valMax, valLen);
9204 	break;
9205     case SQL_MAX_TABLE_NAME_LEN:
9206     case SQL_MAX_COLUMN_NAME_LEN:
9207 	*((SQLSMALLINT *) val) = 255;
9208 	*valLen = sizeof (SQLSMALLINT);
9209 	break;
9210     case SQL_MAX_CURSOR_NAME_LEN:
9211 	*((SQLSMALLINT *) val) = 255;
9212 	*valLen = sizeof (SQLSMALLINT);
9213 	break;
9214     case SQL_MAX_PROCEDURE_NAME_LEN:
9215 	*((SQLSMALLINT *) val) = 0;
9216 	break;
9217     case SQL_MAX_QUALIFIER_NAME_LEN:
9218     case SQL_MAX_OWNER_NAME_LEN:
9219 	*((SQLSMALLINT *) val) = 255;
9220 	break;
9221     case SQL_OWNER_TERM:
9222 	strmak(val, "", valMax, valLen);
9223 	break;
9224     case SQL_PROCEDURE_TERM:
9225 	strmak(val, "PROCEDURE", valMax, valLen);
9226 	break;
9227     case SQL_QUALIFIER_NAME_SEPARATOR:
9228 	strmak(val, ".", valMax, valLen);
9229 	break;
9230     case SQL_QUALIFIER_TERM:
9231 #if defined(_WIN32) || defined(_WIN64)
9232 	strmak(val, d->xcelqrx ? "catalog" : "", valMax, valLen);
9233 #else
9234 	strmak(val, "", valMax, valLen);
9235 #endif
9236 	break;
9237     case SQL_QUALIFIER_USAGE:
9238 #if defined(_WIN32) || defined(_WIN64)
9239 	*((SQLUINTEGER *) val) = d->xcelqrx ?
9240 	    (SQL_CU_DML_STATEMENTS | SQL_CU_INDEX_DEFINITION |
9241 	     SQL_CU_TABLE_DEFINITION) : 0;
9242 #else
9243 	*((SQLUINTEGER *) val) = 0;
9244 #endif
9245 	*valLen = sizeof (SQLUINTEGER);
9246 	break;
9247     case SQL_SCROLL_CONCURRENCY:
9248 	*((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
9249 	*valLen = sizeof (SQLUINTEGER);
9250 	break;
9251     case SQL_SCROLL_OPTIONS:
9252 	*((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
9253 	*valLen = sizeof (SQLUINTEGER);
9254 	break;
9255     case SQL_TABLE_TERM:
9256 	strmak(val, "TABLE", valMax, valLen);
9257 	break;
9258     case SQL_TXN_CAPABLE:
9259 	*((SQLSMALLINT *) val) = SQL_TC_ALL;
9260 	*valLen = sizeof (SQLSMALLINT);
9261 	break;
9262     case SQL_CONVERT_FUNCTIONS:
9263 	*((SQLUINTEGER *) val) = 0;
9264 	*valLen = sizeof (SQLUINTEGER);
9265        break;
9266     case SQL_SYSTEM_FUNCTIONS:
9267     case SQL_NUMERIC_FUNCTIONS:
9268     case SQL_STRING_FUNCTIONS:
9269     case SQL_TIMEDATE_FUNCTIONS:
9270 	*((SQLUINTEGER *) val) = 0;
9271 	*valLen = sizeof (SQLUINTEGER);
9272 	break;
9273     case SQL_CONVERT_BIGINT:
9274     case SQL_CONVERT_BIT:
9275     case SQL_CONVERT_CHAR:
9276     case SQL_CONVERT_DATE:
9277     case SQL_CONVERT_DECIMAL:
9278     case SQL_CONVERT_DOUBLE:
9279     case SQL_CONVERT_FLOAT:
9280     case SQL_CONVERT_INTEGER:
9281     case SQL_CONVERT_LONGVARCHAR:
9282     case SQL_CONVERT_NUMERIC:
9283     case SQL_CONVERT_REAL:
9284     case SQL_CONVERT_SMALLINT:
9285     case SQL_CONVERT_TIME:
9286     case SQL_CONVERT_TIMESTAMP:
9287     case SQL_CONVERT_TINYINT:
9288     case SQL_CONVERT_VARCHAR:
9289 	*((SQLUINTEGER *) val) =
9290 	    SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
9291 	    SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
9292 	    SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
9293 	    SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
9294 	    SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
9295 	*valLen = sizeof (SQLUINTEGER);
9296 	break;
9297     case SQL_CONVERT_BINARY:
9298     case SQL_CONVERT_VARBINARY:
9299     case SQL_CONVERT_LONGVARBINARY:
9300 	*((SQLUINTEGER *) val) = 0;
9301 	*valLen = sizeof (SQLUINTEGER);
9302 	break;
9303     case SQL_POSITIONED_STATEMENTS:
9304     case SQL_LOCK_TYPES:
9305 	*((SQLUINTEGER *) val) = 0;
9306 	*valLen = sizeof (SQLUINTEGER);
9307 	break;
9308     case SQL_BOOKMARK_PERSISTENCE:
9309 	*((SQLUINTEGER *) val) = SQL_BP_SCROLL;
9310 	*valLen = sizeof (SQLUINTEGER);
9311 	break;
9312     case SQL_UNION:
9313 	*((SQLUINTEGER *) val) = SQL_U_UNION | SQL_U_UNION_ALL;
9314 	*valLen = sizeof (SQLUINTEGER);
9315 	break;
9316     case SQL_OWNER_USAGE:
9317     case SQL_SUBQUERIES:
9318     case SQL_TIMEDATE_ADD_INTERVALS:
9319     case SQL_TIMEDATE_DIFF_INTERVALS:
9320 	*((SQLUINTEGER *) val) = 0;
9321 	*valLen = sizeof (SQLUINTEGER);
9322 	break;
9323     case SQL_QUOTED_IDENTIFIER_CASE:
9324 	*((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
9325 	*valLen = sizeof (SQLUSMALLINT);
9326 	break;
9327     case SQL_POS_OPERATIONS:
9328 	*((SQLUINTEGER *) val) = 0;
9329 	*valLen = sizeof (SQLUINTEGER);
9330 	break;
9331     case SQL_ALTER_TABLE:
9332 	*((SQLUINTEGER *) val) = 0;
9333 	*valLen = sizeof (SQLUINTEGER);
9334 	break;
9335     case SQL_CORRELATION_NAME:
9336 	*((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
9337 	*valLen = sizeof (SQLSMALLINT);
9338 	break;
9339     case SQL_NON_NULLABLE_COLUMNS:
9340 	*((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
9341 	*valLen = sizeof (SQLSMALLINT);
9342 	break;
9343     case SQL_NULL_COLLATION:
9344 	*((SQLSMALLINT *) val) = SQL_NC_START;
9345 	*valLen = sizeof (SQLSMALLINT);
9346 	break;
9347     case SQL_MAX_COLUMNS_IN_GROUP_BY:
9348     case SQL_MAX_COLUMNS_IN_ORDER_BY:
9349     case SQL_MAX_COLUMNS_IN_SELECT:
9350     case SQL_MAX_COLUMNS_IN_TABLE:
9351     case SQL_MAX_ROW_SIZE:
9352     case SQL_MAX_TABLES_IN_SELECT:
9353 	*((SQLSMALLINT *) val) = 0;
9354 	*valLen = sizeof (SQLSMALLINT);
9355 	break;
9356     case SQL_MAX_BINARY_LITERAL_LEN:
9357     case SQL_MAX_CHAR_LITERAL_LEN:
9358 	*((SQLUINTEGER *) val) = 0;
9359 	*valLen = sizeof (SQLUINTEGER);
9360 	break;
9361     case SQL_MAX_COLUMNS_IN_INDEX:
9362 	*((SQLSMALLINT *) val) = 0;
9363 	*valLen = sizeof (SQLSMALLINT);
9364 	break;
9365     case SQL_MAX_INDEX_SIZE:
9366 	*((SQLUINTEGER *) val) = 0;
9367 	*valLen = sizeof (SQLUINTEGER);
9368 	break;
9369 #ifdef SQL_MAX_IDENTIFIER_LENGTH
9370     case SQL_MAX_IDENTIFIER_LENGTH:
9371 	*((SQLUINTEGER *) val) = 255;
9372 	*valLen = sizeof (SQLUINTEGER);
9373 	break;
9374 #endif
9375     case SQL_MAX_STATEMENT_LEN:
9376 	*((SQLUINTEGER *) val) = 16384;
9377 	*valLen = sizeof (SQLUINTEGER);
9378 	break;
9379     case SQL_QUALIFIER_LOCATION:
9380 	*((SQLSMALLINT *) val) = SQL_QL_START;
9381 	*valLen = sizeof (SQLSMALLINT);
9382 	break;
9383     case SQL_GETDATA_EXTENSIONS:
9384 	*((SQLUINTEGER *) val) =
9385 	    SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
9386 	*valLen = sizeof (SQLUINTEGER);
9387 	break;
9388     case SQL_STATIC_SENSITIVITY:
9389 	*((SQLUINTEGER *) val) = 0;
9390 	*valLen = sizeof (SQLUINTEGER);
9391 	break;
9392     case SQL_FILE_USAGE:
9393 #if defined(_WIN32) || defined(_WIN64)
9394 	*((SQLSMALLINT *) val) =
9395 	    d->xcelqrx ? SQL_FILE_CATALOG : SQL_FILE_NOT_SUPPORTED;
9396 #else
9397 	*((SQLSMALLINT *) val) = SQL_FILE_NOT_SUPPORTED;
9398 #endif
9399 	*valLen = sizeof (SQLSMALLINT);
9400 	break;
9401     case SQL_GROUP_BY:
9402 	*((SQLSMALLINT *) val) = 0;
9403 	*valLen = sizeof (SQLSMALLINT);
9404 	break;
9405     case SQL_KEYWORDS:
9406 	strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
9407 	       "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
9408 	       valMax, valLen);
9409 	break;
9410     case SQL_SPECIAL_CHARACTERS:
9411 #ifdef SQL_COLLATION_SEQ
9412     case SQL_COLLATION_SEQ:
9413 #endif
9414 	strmak(val, "", valMax, valLen);
9415 	break;
9416     case SQL_BATCH_SUPPORT:
9417     case SQL_BATCH_ROW_COUNT:
9418     case SQL_PARAM_ARRAY_ROW_COUNTS:
9419 	*((SQLUINTEGER *) val) = 0;
9420 	*valLen = sizeof (SQLUINTEGER);
9421 	break;
9422     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
9423 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
9424 	*valLen = sizeof (SQLUINTEGER);
9425 	break;
9426     case SQL_STATIC_CURSOR_ATTRIBUTES1:
9427 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
9428 	    SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
9429 	*valLen = sizeof (SQLUINTEGER);
9430 	break;
9431     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
9432     case SQL_STATIC_CURSOR_ATTRIBUTES2:
9433 	*((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
9434 	    SQL_CA2_LOCK_CONCURRENCY;
9435 	*valLen = sizeof (SQLUINTEGER);
9436 	break;
9437     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
9438     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
9439     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
9440     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
9441 	*((SQLUINTEGER *) val) = 0;
9442 	*valLen = sizeof (SQLUINTEGER);
9443 	break;
9444     case SQL_ODBC_INTERFACE_CONFORMANCE:
9445 	*((SQLUINTEGER *) val) = SQL_OIC_CORE;
9446 	*valLen = sizeof (SQLUINTEGER);
9447 	break;
9448     default:
9449 	setstatd(d, -1, "unsupported info option %d",
9450 		 (*d->ov3) ? "HYC00" : "S1C00", type);
9451 	return SQL_ERROR;
9452     }
9453     return SQL_SUCCESS;
9454 }
9455 
9456 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
9457 /**
9458  * Return information about what this ODBC driver supports.
9459  * @param dbc database connection handle
9460  * @param type type of information to be retrieved
9461  * @param val output buffer
9462  * @param valMax length of output buffer
9463  * @param valLen output length
9464  * @result ODBC error code
9465  */
9466 
9467 SQLRETURN SQL_API
SQLGetInfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)9468 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
9469 	   SQLSMALLINT *valLen)
9470 {
9471     SQLRETURN ret;
9472 
9473     HDBC_LOCK(dbc);
9474     ret = drvgetinfo(dbc, type, val, valMax, valLen);
9475     HDBC_UNLOCK(dbc);
9476     return ret;
9477 }
9478 #endif
9479 
9480 #ifdef WINTERFACE
9481 /**
9482  * Return information about what this ODBC driver supports.
9483  * @param dbc database connection handle
9484  * @param type type of information to be retrieved
9485  * @param val output buffer
9486  * @param valMax length of output buffer
9487  * @param valLen output length
9488  * @result ODBC error code
9489  */
9490 
9491 SQLRETURN SQL_API
SQLGetInfoW(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)9492 SQLGetInfoW(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
9493 	    SQLSMALLINT *valLen)
9494 {
9495     SQLRETURN ret;
9496     SQLSMALLINT len = 0;
9497 
9498     HDBC_LOCK(dbc);
9499     ret = drvgetinfo(dbc, type, val, valMax, &len);
9500     HDBC_UNLOCK(dbc);
9501     if (ret == SQL_SUCCESS) {
9502 	SQLWCHAR *v = NULL;
9503 
9504 	switch (type) {
9505 	case SQL_USER_NAME:
9506 	case SQL_DRIVER_ODBC_VER:
9507 	case SQL_DATA_SOURCE_NAME:
9508 	case SQL_DRIVER_NAME:
9509 	case SQL_DRIVER_VER:
9510 	case SQL_ODBC_VER:
9511 	case SQL_SERVER_NAME:
9512 	case SQL_DATABASE_NAME:
9513 	case SQL_SEARCH_PATTERN_ESCAPE:
9514 	case SQL_DBMS_NAME:
9515 	case SQL_DBMS_VER:
9516 	case SQL_NEED_LONG_DATA_LEN:
9517 	case SQL_ROW_UPDATES:
9518 	case SQL_ACCESSIBLE_PROCEDURES:
9519 	case SQL_PROCEDURES:
9520 	case SQL_EXPRESSIONS_IN_ORDERBY:
9521 	case SQL_ODBC_SQL_OPT_IEF:
9522 	case SQL_LIKE_ESCAPE_CLAUSE:
9523 	case SQL_ORDER_BY_COLUMNS_IN_SELECT:
9524 	case SQL_OUTER_JOINS:
9525 	case SQL_COLUMN_ALIAS:
9526 	case SQL_ACCESSIBLE_TABLES:
9527 	case SQL_MULT_RESULT_SETS:
9528 	case SQL_MULTIPLE_ACTIVE_TXN:
9529 	case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
9530 	case SQL_DATA_SOURCE_READ_ONLY:
9531 #ifdef SQL_DESCRIBE_PARAMETER
9532 	case SQL_DESCRIBE_PARAMETER:
9533 #endif
9534 	case SQL_IDENTIFIER_QUOTE_CHAR:
9535 	case SQL_OWNER_TERM:
9536 	case SQL_PROCEDURE_TERM:
9537 	case SQL_QUALIFIER_NAME_SEPARATOR:
9538 	case SQL_QUALIFIER_TERM:
9539 	case SQL_TABLE_TERM:
9540 	case SQL_KEYWORDS:
9541 	case SQL_SPECIAL_CHARACTERS:
9542 #ifdef SQL_CATALOG_NAME
9543 	case SQL_CATALOG_NAME:
9544 #endif
9545 #ifdef SQL_COLLATION_SEQ
9546 	case SQL_COLLATION_SEQ:
9547 #endif
9548 	    if (val) {
9549 		if (len > 0) {
9550 		    v = uc_from_utf((SQLCHAR *) val, len);
9551 		    if (v) {
9552 			int vmax = valMax / sizeof (SQLWCHAR);
9553 
9554 			uc_strncpy(val, v, vmax);
9555 			v[len] = 0;
9556 			len = min(vmax, uc_strlen(v));
9557 			uc_free(v);
9558 			len *= sizeof (SQLWCHAR);
9559 		    } else {
9560 			len = 0;
9561 		    }
9562 		}
9563 		if (len <= 0) {
9564 		    len = 0;
9565 		    if (valMax >= sizeof (SQLWCHAR)) {
9566 			*((SQLWCHAR *)val) = 0;
9567 		    }
9568 		}
9569 	    } else {
9570 		len = 0;
9571 	    }
9572 	    break;
9573 	}
9574 	if (valLen) {
9575 	    *valLen = len;
9576 	}
9577     }
9578     return ret;
9579 }
9580 #endif
9581 
9582 /**
9583  * Return information about supported ODBC API functions.
9584  * @param dbc database connection handle
9585  * @param func function code to be retrieved
9586  * @param flags output indicator
9587  * @result ODBC error code
9588  */
9589 
9590 SQLRETURN SQL_API
SQLGetFunctions(SQLHDBC dbc,SQLUSMALLINT func,SQLUSMALLINT * flags)9591 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
9592 		SQLUSMALLINT *flags)
9593 {
9594     DBC *d;
9595     int i;
9596     SQLUSMALLINT exists[100];
9597 
9598     if (dbc == SQL_NULL_HDBC) {
9599 	return SQL_INVALID_HANDLE;
9600     }
9601     d = (DBC *) dbc;
9602     for (i = 0; i < array_size(exists); i++) {
9603 	exists[i] = SQL_FALSE;
9604     }
9605     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
9606     exists[SQL_API_SQLFETCH] = SQL_TRUE;
9607     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
9608     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
9609     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
9610     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
9611     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
9612     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
9613     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
9614     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
9615     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
9616     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
9617     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
9618     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
9619     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
9620     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
9621     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
9622     exists[SQL_API_SQLSETCURSORNAME] = SQL_FALSE;
9623     exists[SQL_API_SQLERROR] = SQL_TRUE;
9624     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
9625     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
9626     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
9627     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
9628     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
9629     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
9630     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
9631     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
9632     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
9633     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
9634     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
9635     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
9636     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
9637     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
9638     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
9639     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
9640     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
9641     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
9642     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
9643     exists[SQL_API_SQLTABLES] = SQL_TRUE;
9644     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
9645     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
9646     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
9647     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
9648     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
9649     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
9650     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
9651     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
9652     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
9653     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
9654     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
9655     exists[SQL_API_SQLSETPOS] = SQL_TRUE;
9656     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
9657     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
9658     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
9659     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_TRUE;
9660     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
9661     if (func == SQL_API_ALL_FUNCTIONS) {
9662 	memcpy(flags, exists, sizeof (exists));
9663     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
9664 	int i;
9665 #define SET_EXISTS(x) \
9666 	flags[(x) >> 4] |= (1 << ((x) & 0xF))
9667 #define CLR_EXISTS(x) \
9668 	flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
9669 
9670 	memset(flags, 0,
9671 	       sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
9672 	for (i = 0; i < array_size(exists); i++) {
9673 	    if (exists[i]) {
9674 		flags[i >> 4] |= (1 << (i & 0xF));
9675 	    }
9676 	}
9677 	SET_EXISTS(SQL_API_SQLALLOCHANDLE);
9678 	SET_EXISTS(SQL_API_SQLFREEHANDLE);
9679 	SET_EXISTS(SQL_API_SQLGETSTMTATTR);
9680 	SET_EXISTS(SQL_API_SQLSETSTMTATTR);
9681 	SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
9682 	SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
9683 	SET_EXISTS(SQL_API_SQLGETENVATTR);
9684 	SET_EXISTS(SQL_API_SQLSETENVATTR);
9685 	SET_EXISTS(SQL_API_SQLCLOSECURSOR);
9686 	SET_EXISTS(SQL_API_SQLBINDPARAM);
9687 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
9688 	/*
9689 	 * Some unixODBC versions have problems with
9690 	 * SQLError() vs. SQLGetDiagRec() with loss
9691 	 * of error/warning messages.
9692 	 */
9693 	SET_EXISTS(SQL_API_SQLGETDIAGREC);
9694 #endif
9695 	SET_EXISTS(SQL_API_SQLGETDIAGFIELD);
9696 	SET_EXISTS(SQL_API_SQLFETCHSCROLL);
9697 	SET_EXISTS(SQL_API_SQLENDTRAN);
9698     } else {
9699 	if (func < array_size(exists)) {
9700 	    *flags = exists[func];
9701 	} else {
9702 	    switch (func) {
9703 	    case SQL_API_SQLALLOCHANDLE:
9704 	    case SQL_API_SQLFREEHANDLE:
9705 	    case SQL_API_SQLGETSTMTATTR:
9706 	    case SQL_API_SQLSETSTMTATTR:
9707 	    case SQL_API_SQLGETCONNECTATTR:
9708 	    case SQL_API_SQLSETCONNECTATTR:
9709 	    case SQL_API_SQLGETENVATTR:
9710 	    case SQL_API_SQLSETENVATTR:
9711 	    case SQL_API_SQLCLOSECURSOR:
9712 	    case SQL_API_SQLBINDPARAM:
9713 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
9714 	    /*
9715 	     * Some unixODBC versions have problems with
9716 	     * SQLError() vs. SQLGetDiagRec() with loss
9717 	     * of error/warning messages.
9718 	     */
9719 	    case SQL_API_SQLGETDIAGREC:
9720 #endif
9721 	    case SQL_API_SQLGETDIAGFIELD:
9722 	    case SQL_API_SQLFETCHSCROLL:
9723 	    case SQL_API_SQLENDTRAN:
9724 		*flags = SQL_TRUE;
9725 		break;
9726 	    default:
9727 		*flags = SQL_FALSE;
9728 	    }
9729 	}
9730     }
9731     return SQL_SUCCESS;
9732 }
9733 
9734 /**
9735  * Internal allocate HENV.
9736  * @param env pointer to environment handle
9737  * @result ODBC error code
9738  */
9739 
9740 static SQLRETURN
drvallocenv(SQLHENV * env)9741 drvallocenv(SQLHENV *env)
9742 {
9743     ENV *e;
9744 
9745     if (env == NULL) {
9746 	return SQL_INVALID_HANDLE;
9747     }
9748     e = (ENV *) xmalloc(sizeof (ENV));
9749     if (e == NULL) {
9750 	*env = SQL_NULL_HENV;
9751 	return SQL_ERROR;
9752     }
9753     e->magic = ENV_MAGIC;
9754     e->ov3 = 0;
9755 #if defined(_WIN32) || defined(_WIN64)
9756     InitializeCriticalSection(&e->cs);
9757     e->owner = 0;
9758 #else
9759 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
9760     nvfs_init();
9761 #endif
9762 #endif
9763     e->dbcs = NULL;
9764     *env = (SQLHENV) e;
9765     return SQL_SUCCESS;
9766 }
9767 
9768 /**
9769  * Allocate HENV.
9770  * @param env pointer to environment handle
9771  * @result ODBC error code
9772  */
9773 
9774 SQLRETURN SQL_API
SQLAllocEnv(SQLHENV * env)9775 SQLAllocEnv(SQLHENV *env)
9776 {
9777     return drvallocenv(env);
9778 }
9779 
9780 /**
9781  * Internal free HENV.
9782  * @param env environment handle
9783  * @result ODBC error code
9784  */
9785 
9786 static SQLRETURN
drvfreeenv(SQLHENV env)9787 drvfreeenv(SQLHENV env)
9788 {
9789     ENV *e;
9790 
9791     if (env == SQL_NULL_HENV) {
9792 	return SQL_INVALID_HANDLE;
9793     }
9794     e = (ENV *) env;
9795     if (e->magic != ENV_MAGIC) {
9796 	return SQL_SUCCESS;
9797     }
9798 #if defined(_WIN32) || defined(_WIN64)
9799     EnterCriticalSection(&e->cs);
9800     e->owner = GetCurrentThreadId();
9801 #endif
9802     if (e->dbcs) {
9803 #if defined(_WIN32) || defined(_WIN64)
9804 	LeaveCriticalSection(&e->cs);
9805 	e->owner = 0;
9806 #endif
9807 	return SQL_ERROR;
9808     }
9809     e->magic = DEAD_MAGIC;
9810 #if defined(_WIN32) || defined(_WIN64)
9811     e->owner = 0;
9812     LeaveCriticalSection(&e->cs);
9813     DeleteCriticalSection(&e->cs);
9814 #endif
9815     xfree(e);
9816     return SQL_SUCCESS;
9817 }
9818 
9819 /**
9820  * Free HENV.
9821  * @param env environment handle
9822  * @result ODBC error code
9823  */
9824 
9825 SQLRETURN SQL_API
SQLFreeEnv(SQLHENV env)9826 SQLFreeEnv(SQLHENV env)
9827 {
9828     return drvfreeenv(env);
9829 }
9830 
9831 /**
9832  * Internal allocate HDBC.
9833  * @param env environment handle
9834  * @param dbc pointer to database connection handle
9835  * @result ODBC error code
9836  */
9837 
9838 static SQLRETURN
drvallocconnect(SQLHENV env,SQLHDBC * dbc)9839 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
9840 {
9841     DBC *d;
9842     ENV *e;
9843     const char *verstr;
9844     int maj = 0, min = 0, lev = 0;
9845 
9846     if (dbc == NULL) {
9847 	return SQL_ERROR;
9848     }
9849     d = (DBC *) xmalloc(sizeof (DBC));
9850     if (d == NULL) {
9851 	*dbc = SQL_NULL_HDBC;
9852 	return SQL_ERROR;
9853     }
9854     memset(d, 0, sizeof (DBC));
9855     d->curtype = SQL_CURSOR_STATIC;
9856     d->ov3 = &d->ov3val;
9857     verstr = sqlite3_libversion();
9858     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
9859     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
9860     e = (ENV *) env;
9861 #if defined(_WIN32) || defined(_WIN64)
9862     if (e->magic == ENV_MAGIC) {
9863 	EnterCriticalSection(&e->cs);
9864 	e->owner = GetCurrentThreadId();
9865     }
9866 #endif
9867     if (e->magic == ENV_MAGIC) {
9868 	DBC *n, *p;
9869 
9870 	d->env = e;
9871 	d->ov3 = &e->ov3;
9872 	p = NULL;
9873 	n = e->dbcs;
9874 	while (n) {
9875 	    p = n;
9876 	    n = n->next;
9877 	}
9878 	if (p) {
9879 	    p->next = d;
9880 	} else {
9881 	    e->dbcs = d;
9882 	}
9883     }
9884 #if defined(_WIN32) || defined(_WIN64)
9885     if (e->magic == ENV_MAGIC) {
9886 	e->owner = 0;
9887 	LeaveCriticalSection(&e->cs);
9888     }
9889     d->oemcp = 1;
9890 #endif
9891     d->autocommit = 1;
9892     d->magic = DBC_MAGIC;
9893     *dbc = (SQLHDBC) d;
9894     drvgetgpps(d);
9895     return SQL_SUCCESS;
9896 }
9897 
9898 /**
9899  * Allocate HDBC.
9900  * @param env environment handle
9901  * @param dbc pointer to database connection handle
9902  * @result ODBC error code
9903  */
9904 
9905 SQLRETURN SQL_API
SQLAllocConnect(SQLHENV env,SQLHDBC * dbc)9906 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
9907 {
9908     return drvallocconnect(env, dbc);
9909 }
9910 
9911 /**
9912  * Internal free connection (HDBC).
9913  * @param dbc database connection handle
9914  * @result ODBC error code
9915  */
9916 
9917 static SQLRETURN
drvfreeconnect(SQLHDBC dbc)9918 drvfreeconnect(SQLHDBC dbc)
9919 {
9920     DBC *d;
9921     ENV *e;
9922     SQLRETURN ret = SQL_ERROR;
9923 
9924     if (dbc == SQL_NULL_HDBC) {
9925 	return SQL_INVALID_HANDLE;
9926     }
9927     d = (DBC *) dbc;
9928     if (d->magic != DBC_MAGIC) {
9929 	return SQL_INVALID_HANDLE;
9930     }
9931     e = d->env;
9932     if (e && e->magic == ENV_MAGIC) {
9933 #if defined(_WIN32) || defined(_WIN64)
9934 	EnterCriticalSection(&e->cs);
9935 	e->owner = GetCurrentThreadId();
9936 #endif
9937     } else {
9938 	e = NULL;
9939     }
9940     if (d->sqlite) {
9941 	setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
9942 	goto done;
9943     }
9944     while (d->stmt) {
9945 	freestmt((HSTMT) d->stmt);
9946     }
9947     if (e && e->magic == ENV_MAGIC) {
9948 	DBC *n, *p;
9949 
9950 	p = NULL;
9951 	n = e->dbcs;
9952 	while (n) {
9953 	    if (n == d) {
9954 		break;
9955 	    }
9956 	    p = n;
9957 	    n = n->next;
9958 	}
9959 	if (n) {
9960 	    if (p) {
9961 		p->next = d->next;
9962 	    } else {
9963 		e->dbcs = d->next;
9964 	    }
9965 	}
9966     }
9967     drvrelgpps(d);
9968     d->magic = DEAD_MAGIC;
9969     if (d->trace) {
9970 	fclose(d->trace);
9971     }
9972     xfree(d);
9973     ret = SQL_SUCCESS;
9974 done:
9975 #if defined(_WIN32) || defined(_WIN64)
9976     if (e) {
9977 	e->owner = 0;
9978 	LeaveCriticalSection(&e->cs);
9979     }
9980 #endif
9981     return ret;
9982 }
9983 
9984 /**
9985  * Free connection (HDBC).
9986  * @param dbc database connection handle
9987  * @result ODBC error code
9988  */
9989 
9990 SQLRETURN SQL_API
SQLFreeConnect(SQLHDBC dbc)9991 SQLFreeConnect(SQLHDBC dbc)
9992 {
9993     return drvfreeconnect(dbc);
9994 }
9995 
9996 /**
9997  * Internal get connect attribute of HDBC.
9998  * @param dbc database connection handle
9999  * @param attr option to be retrieved
10000  * @param val output buffer
10001  * @param bufmax size of output buffer
10002  * @param buflen output length
10003  * @result ODBC error code
10004  */
10005 
10006 static SQLRETURN
drvgetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)10007 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10008 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
10009 {
10010     DBC *d;
10011     SQLINTEGER dummy;
10012 
10013     if (dbc == SQL_NULL_HDBC) {
10014 	return SQL_INVALID_HANDLE;
10015     }
10016     d = (DBC *) dbc;
10017     if (!val) {
10018 	val = (SQLPOINTER) &dummy;
10019     }
10020     if (!buflen) {
10021 	buflen = &dummy;
10022     }
10023     switch (attr) {
10024     case SQL_ATTR_CONNECTION_DEAD:
10025 	*((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
10026 	*buflen = sizeof (SQLINTEGER);
10027 	break;
10028     case SQL_ATTR_ACCESS_MODE:
10029 	*((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
10030 	*buflen = sizeof (SQLINTEGER);
10031 	break;
10032     case SQL_ATTR_AUTOCOMMIT:
10033 	*((SQLINTEGER *) val) =
10034 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
10035 	*buflen = sizeof (SQLINTEGER);
10036 	break;
10037     case SQL_ATTR_LOGIN_TIMEOUT:
10038 	*((SQLINTEGER *) val) = 100;
10039 	*buflen = sizeof (SQLINTEGER);
10040 	break;
10041     case SQL_ATTR_ODBC_CURSORS:
10042 	*((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
10043 	*buflen = sizeof (SQLINTEGER);
10044 	break;
10045     case SQL_ATTR_PACKET_SIZE:
10046 	*((SQLINTEGER *) val) = 16384;
10047 	*buflen = sizeof (SQLINTEGER);
10048 	break;
10049     case SQL_ATTR_TXN_ISOLATION:
10050 	*((SQLINTEGER *) val) = SQL_TXN_SERIALIZABLE;
10051 	*buflen = sizeof (SQLINTEGER);
10052 	break;
10053     case SQL_ATTR_TRACEFILE:
10054     case SQL_ATTR_TRANSLATE_LIB:
10055     case SQL_ATTR_CURRENT_CATALOG:
10056 	*((SQLCHAR *) val) = 0;
10057 	*buflen = 0;
10058 	break;
10059     case SQL_ATTR_TRACE:
10060     case SQL_ATTR_QUIET_MODE:
10061     case SQL_ATTR_TRANSLATE_OPTION:
10062     case SQL_ATTR_KEYSET_SIZE:
10063     case SQL_ATTR_QUERY_TIMEOUT:
10064 	*((SQLINTEGER *) val) = 0;
10065 	*buflen = sizeof (SQLINTEGER);
10066 	break;
10067     case SQL_ATTR_PARAM_BIND_TYPE:
10068 	*((SQLULEN *) val) = SQL_PARAM_BIND_BY_COLUMN;
10069 	*buflen = sizeof (SQLUINTEGER);
10070 	break;
10071     case SQL_ATTR_ROW_BIND_TYPE:
10072 	*((SQLULEN *) val) = SQL_BIND_BY_COLUMN;
10073 	*buflen = sizeof (SQLULEN);
10074 	break;
10075     case SQL_ATTR_USE_BOOKMARKS:
10076 	*((SQLINTEGER *) val) = SQL_UB_OFF;
10077 	*buflen = sizeof (SQLINTEGER);
10078 	break;
10079     case SQL_ATTR_ASYNC_ENABLE:
10080 	*((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
10081 	*buflen = sizeof (SQLINTEGER);
10082 	break;
10083     case SQL_ATTR_NOSCAN:
10084 	*((SQLINTEGER *) val) = SQL_NOSCAN_ON;
10085 	*buflen = sizeof (SQLINTEGER);
10086 	break;
10087     case SQL_ATTR_CONCURRENCY:
10088 	*((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
10089 	*buflen = sizeof (SQLINTEGER);
10090 	break;
10091 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
10092     case SQL_ATTR_CURSOR_SENSITIVITY:
10093 	*((SQLINTEGER *) val) = SQL_UNSPECIFIED;
10094 	*buflen = sizeof (SQLINTEGER);
10095 	break;
10096 #endif
10097     case SQL_ATTR_SIMULATE_CURSOR:
10098 	*((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
10099 	*buflen = sizeof (SQLINTEGER);
10100 	break;
10101     case SQL_ATTR_MAX_ROWS:
10102 	*((SQLINTEGER *) val) = 0;
10103 	*buflen = sizeof (SQLINTEGER);
10104     case SQL_ATTR_MAX_LENGTH:
10105 	*((SQLINTEGER *) val) = 1000000000;
10106 	*buflen = sizeof (SQLINTEGER);
10107 	break;
10108     case SQL_ATTR_CURSOR_TYPE:
10109 	*((SQLINTEGER *) val) = d->curtype;
10110 	*buflen = sizeof (SQLINTEGER);
10111 	break;
10112     case SQL_ATTR_RETRIEVE_DATA:
10113 	*((SQLINTEGER *) val) = SQL_RD_ON;
10114 	*buflen = sizeof (SQLINTEGER);
10115 	break;
10116 #ifdef SQL_ATTR_METADATA_ID
10117     case SQL_ATTR_METADATA_ID:
10118 	*((SQLULEN *) val) = SQL_FALSE;
10119 	return SQL_SUCCESS;
10120 #endif
10121     default:
10122 	*((SQLINTEGER *) val) = 0;
10123 	*buflen = sizeof (SQLINTEGER);
10124 	setstatd(d, -1, "unsupported connect attribute %d",
10125 		 (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
10126 	return SQL_ERROR;
10127     }
10128     return SQL_SUCCESS;
10129 }
10130 
10131 #ifndef WINTERFACE
10132 /**
10133  * Get connect attribute of HDBC.
10134  * @param dbc database connection handle
10135  * @param attr option to be retrieved
10136  * @param val output buffer
10137  * @param bufmax size of output buffer
10138  * @param buflen output length
10139  * @result ODBC error code
10140  */
10141 
10142 SQLRETURN SQL_API
SQLGetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)10143 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10144 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
10145 {
10146     SQLRETURN ret;
10147 
10148     HDBC_LOCK(dbc);
10149     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
10150     HDBC_UNLOCK(dbc);
10151     return ret;
10152 }
10153 #endif
10154 
10155 #ifdef WINTERFACE
10156 /**
10157  * Get connect attribute of HDBC (UNICODE version).
10158  * @param dbc database connection handle
10159  * @param attr option to be retrieved
10160  * @param val output buffer
10161  * @param bufmax size of output buffer
10162  * @param buflen output length
10163  * @result ODBC error code
10164  */
10165 
10166 SQLRETURN SQL_API
SQLGetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)10167 SQLGetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10168 		   SQLINTEGER bufmax, SQLINTEGER *buflen)
10169 {
10170     SQLRETURN ret;
10171 
10172     HDBC_LOCK(dbc);
10173     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
10174     if (SQL_SUCCEEDED(ret)) {
10175 	switch (attr) {
10176 	case SQL_ATTR_TRACEFILE:
10177 	case SQL_ATTR_CURRENT_CATALOG:
10178 	case SQL_ATTR_TRANSLATE_LIB:
10179 	    if (val && bufmax >= sizeof (SQLWCHAR)) {
10180 		*(SQLWCHAR *) val = 0;
10181 	    }
10182 	    break;
10183 	}
10184     }
10185     HDBC_UNLOCK(dbc);
10186     return ret;
10187 }
10188 #endif
10189 
10190 /**
10191  * Internal set connect attribute of HDBC.
10192  * @param dbc database connection handle
10193  * @param attr option to be set
10194  * @param val option value
10195  * @param len size of option
10196  * @result ODBC error code
10197  */
10198 
10199 static SQLRETURN
drvsetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)10200 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10201 		  SQLINTEGER len)
10202 {
10203     DBC *d;
10204 
10205     if (dbc == SQL_NULL_HDBC) {
10206 	return SQL_INVALID_HANDLE;
10207     }
10208     d = (DBC *) dbc;
10209     switch (attr) {
10210     case SQL_AUTOCOMMIT:
10211 	d->autocommit = val == (SQLPOINTER) SQL_AUTOCOMMIT_ON;
10212 	if (d->autocommit && d->intrans) {
10213 	    return endtran(d, SQL_COMMIT, 1);
10214 	} else if (!d->autocommit) {
10215 	    s3stmt_end(d->cur_s3stmt);
10216 	}
10217 	return SQL_SUCCESS;
10218 #ifdef SQL_ATTR_METADATA_ID
10219     case SQL_ATTR_METADATA_ID:
10220 	if (val == (SQLPOINTER) SQL_FALSE) {
10221 	    return SQL_SUCCESS;
10222 	}
10223 	/* fall through */
10224 #endif
10225     default:
10226 	setstatd(d, -1, "option value changed", "01S02");
10227 	return SQL_SUCCESS_WITH_INFO;
10228     }
10229     return SQL_SUCCESS;
10230 }
10231 
10232 #ifndef WINTERFACE
10233 /**
10234  * Set connect attribute of HDBC.
10235  * @param dbc database connection handle
10236  * @param attr option to be set
10237  * @param val option value
10238  * @param len size of option
10239  * @result ODBC error code
10240  */
10241 
10242 SQLRETURN SQL_API
SQLSetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)10243 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10244 		  SQLINTEGER len)
10245 {
10246     SQLRETURN ret;
10247 
10248     HDBC_LOCK(dbc);
10249     ret = drvsetconnectattr(dbc, attr, val, len);
10250     HDBC_UNLOCK(dbc);
10251     return ret;
10252 }
10253 #endif
10254 
10255 #ifdef WINTERFACE
10256 /**
10257  * Set connect attribute of HDBC (UNICODE version).
10258  * @param dbc database connection handle
10259  * @param attr option to be set
10260  * @param val option value
10261  * @param len size of option
10262  * @result ODBC error code
10263  */
10264 
10265 SQLRETURN SQL_API
SQLSetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)10266 SQLSetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
10267 		   SQLINTEGER len)
10268 {
10269     SQLRETURN ret;
10270 
10271     HDBC_LOCK(dbc);
10272     ret = drvsetconnectattr(dbc, attr, val, len);
10273     HDBC_UNLOCK(dbc);
10274     return ret;
10275 }
10276 #endif
10277 
10278 /**
10279  * Internal get connect option of HDBC.
10280  * @param dbc database connection handle
10281  * @param opt option to be retrieved
10282  * @param param output buffer
10283  * @result ODBC error code
10284  */
10285 
10286 static SQLRETURN
drvgetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)10287 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
10288 {
10289     DBC *d;
10290     SQLINTEGER dummy;
10291 
10292     if (dbc == SQL_NULL_HDBC) {
10293 	return SQL_INVALID_HANDLE;
10294     }
10295     d = (DBC *) dbc;
10296     if (!param) {
10297 	param = (SQLPOINTER) &dummy;
10298     }
10299     switch (opt) {
10300     case SQL_ACCESS_MODE:
10301 	*((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
10302 	break;
10303     case SQL_AUTOCOMMIT:
10304 	*((SQLINTEGER *) param) =
10305 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
10306 	break;
10307     case SQL_LOGIN_TIMEOUT:
10308 	*((SQLINTEGER *) param) = 100;
10309 	break;
10310     case SQL_ODBC_CURSORS:
10311 	*((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
10312 	break;
10313     case SQL_PACKET_SIZE:
10314 	*((SQLINTEGER *) param) = 16384;
10315 	break;
10316     case SQL_TXN_ISOLATION:
10317 	*((SQLINTEGER *) param) = SQL_TXN_SERIALIZABLE;
10318 	break;
10319     case SQL_OPT_TRACE:
10320     case SQL_OPT_TRACEFILE:
10321     case SQL_QUIET_MODE:
10322     case SQL_TRANSLATE_DLL:
10323     case SQL_TRANSLATE_OPTION:
10324     case SQL_KEYSET_SIZE:
10325     case SQL_QUERY_TIMEOUT:
10326     case SQL_BIND_TYPE:
10327     case SQL_CURRENT_QUALIFIER:
10328 	*((SQLINTEGER *) param) = 0;
10329 	break;
10330     case SQL_USE_BOOKMARKS:
10331 	*((SQLINTEGER *) param) = SQL_UB_OFF;
10332 	break;
10333     case SQL_ASYNC_ENABLE:
10334 	*((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
10335 	break;
10336     case SQL_NOSCAN:
10337 	*((SQLINTEGER *) param) = SQL_NOSCAN_ON;
10338 	break;
10339     case SQL_CONCURRENCY:
10340 	*((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
10341 	break;
10342     case SQL_SIMULATE_CURSOR:
10343 	*((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
10344 	break;
10345     case SQL_MAX_ROWS:
10346 	*((SQLINTEGER *) param) = 0;
10347 	break;
10348     case SQL_ROWSET_SIZE:
10349     case SQL_MAX_LENGTH:
10350 	*((SQLINTEGER *) param) = 1000000000;
10351 	break;
10352     case SQL_CURSOR_TYPE:
10353 	*((SQLINTEGER *) param) = d->curtype;
10354 	break;
10355     case SQL_RETRIEVE_DATA:
10356 	*((SQLINTEGER *) param) = SQL_RD_ON;
10357 	break;
10358     default:
10359 	*((SQLINTEGER *) param) = 0;
10360 	setstatd(d, -1, "unsupported connect option %d",
10361 		 (*d->ov3) ? "HYC00" : "S1C00", opt);
10362 	return SQL_ERROR;
10363     }
10364     return SQL_SUCCESS;
10365 }
10366 
10367 #ifndef WINTERFACE
10368 /**
10369  * Get connect option of HDBC.
10370  * @param dbc database connection handle
10371  * @param opt option to be retrieved
10372  * @param param output buffer
10373  * @result ODBC error code
10374  */
10375 
10376 SQLRETURN SQL_API
SQLGetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)10377 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
10378 {
10379     SQLRETURN ret;
10380 
10381     HDBC_LOCK(dbc);
10382     ret = drvgetconnectoption(dbc, opt, param);
10383     HDBC_UNLOCK(dbc);
10384     return ret;
10385 }
10386 #endif
10387 
10388 #ifdef WINTERFACE
10389 /**
10390  * Get connect option of HDBC (UNICODE version).
10391  * @param dbc database connection handle
10392  * @param opt option to be retrieved
10393  * @param param output buffer
10394  * @result ODBC error code
10395  */
10396 
10397 SQLRETURN SQL_API
SQLGetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)10398 SQLGetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
10399 {
10400     SQLRETURN ret;
10401 
10402     HDBC_LOCK(dbc);
10403     ret = drvgetconnectoption(dbc, opt, param);
10404     if (SQL_SUCCEEDED(ret)) {
10405 	switch (opt) {
10406 	case SQL_OPT_TRACEFILE:
10407 	case SQL_CURRENT_QUALIFIER:
10408 	case SQL_TRANSLATE_DLL:
10409 	    if (param) {
10410 		*(SQLWCHAR *) param = 0;
10411 	    }
10412 	    break;
10413 	}
10414     }
10415     HDBC_UNLOCK(dbc);
10416     return ret;
10417 }
10418 #endif
10419 
10420 /**
10421  * Internal set option on HDBC.
10422  * @param dbc database connection handle
10423  * @param opt option to be set
10424  * @param param option value
10425  * @result ODBC error code
10426  */
10427 
10428 static SQLRETURN
drvsetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLUINTEGER param)10429 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
10430 {
10431     DBC *d;
10432 
10433     if (dbc == SQL_NULL_HDBC) {
10434 	return SQL_INVALID_HANDLE;
10435     }
10436     d = (DBC *) dbc;
10437     switch (opt) {
10438     case SQL_AUTOCOMMIT:
10439 	d->autocommit = param == SQL_AUTOCOMMIT_ON;
10440 	if (d->autocommit && d->intrans) {
10441 	    return endtran(d, SQL_COMMIT, 1);
10442 	} else if (!d->autocommit) {
10443 	    s3stmt_end(d->cur_s3stmt);
10444 	}
10445 	break;
10446     default:
10447 	setstatd(d, -1, "option value changed", "01S02");
10448 	return SQL_SUCCESS_WITH_INFO;
10449     }
10450     return SQL_SUCCESS;
10451 }
10452 
10453 #ifndef WINTERFACE
10454 /**
10455  * Set option on HDBC.
10456  * @param dbc database connection handle
10457  * @param opt option to be set
10458  * @param param option value
10459  * @result ODBC error code
10460  */
10461 
10462 SQLRETURN SQL_API
SQLSetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)10463 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
10464 {
10465     SQLRETURN ret;
10466 
10467     HDBC_LOCK(dbc);
10468     ret = drvsetconnectoption(dbc, opt, param);
10469     HDBC_UNLOCK(dbc);
10470     return ret;
10471 }
10472 #endif
10473 
10474 #ifdef WINTERFACE
10475 /**
10476  * Set option on HDBC (UNICODE version).
10477  * @param dbc database connection handle
10478  * @param opt option to be set
10479  * @param param option value
10480  * @result ODBC error code
10481  */
10482 
10483 SQLRETURN SQL_API
SQLSetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)10484 SQLSetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
10485 {
10486     SQLRETURN ret;
10487 
10488     HDBC_LOCK(dbc);
10489     ret = drvsetconnectoption(dbc, opt, param);
10490     HDBC_UNLOCK(dbc);
10491     return ret;
10492 }
10493 #endif
10494 
10495 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
10496 
10497 /**
10498  * Handling of SQLConnect() connection attributes
10499  * for standalone operation without driver manager.
10500  * @param dsn DSN/driver connection string
10501  * @param attr attribute string to be retrieved
10502  * @param out output buffer
10503  * @param outLen length of output buffer
10504  * @result true or false
10505  */
10506 
10507 static int
getdsnattr(char * dsn,char * attr,char * out,int outLen)10508 getdsnattr(char *dsn, char *attr, char *out, int outLen)
10509 {
10510     char *str = dsn, *start;
10511     int len = strlen(attr);
10512 
10513     while (*str) {
10514 	while (*str && *str == ';') {
10515 	    ++str;
10516 	}
10517 	start = str;
10518 	if ((str = strchr(str, '=')) == NULL) {
10519 	    return 0;
10520 	}
10521 	if (str - start == len && strncasecmp(start, attr, len) == 0) {
10522 	    start = ++str;
10523 	    while (*str && *str != ';') {
10524 		++str;
10525 	    }
10526 	    len = min(outLen - 1, str - start);
10527 	    strncpy(out, start, len);
10528 	    out[len] = '\0';
10529 	    return 1;
10530 	}
10531 	while (*str && *str != ';') {
10532 	    ++str;
10533 	}
10534     }
10535     return 0;
10536 }
10537 #endif
10538 
10539 /**
10540  * Internal connect to SQLite database.
10541  * @param dbc database connection handle
10542  * @param dsn DSN string
10543  * @param dsnLen length of DSN string or SQL_NTS
10544  * @param pwd password or NULL
10545  * @param pwdLen length of password or SQL_NTS
10546  * @param isu true/false: file name is UTF8 encoded
10547  * @result ODBC error code
10548  */
10549 
10550 static SQLRETURN
drvconnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,char * pwd,int pwdLen,int isu)10551 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen, char *pwd,
10552 	   int pwdLen, int isu)
10553 {
10554     DBC *d;
10555     int len;
10556     SQLRETURN ret;
10557     char buf[SQL_MAX_MESSAGE_LENGTH], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
10558     char busy[SQL_MAX_MESSAGE_LENGTH / 4], tracef[SQL_MAX_MESSAGE_LENGTH];
10559     char loadext[SQL_MAX_MESSAGE_LENGTH];
10560     char sflag[32], spflag[32], ntflag[32], nwflag[32], biflag[32];
10561     char snflag[32], lnflag[32], ncflag[32], fkflag[32], jmode[32];
10562 #if defined(_WIN32) || defined(_WIN64)
10563     char oemcp[32];
10564 #endif
10565 
10566     if (dbc == SQL_NULL_HDBC) {
10567 	return SQL_INVALID_HANDLE;
10568     }
10569     d = (DBC *) dbc;
10570     if (d->magic != DBC_MAGIC) {
10571 	return SQL_INVALID_HANDLE;
10572     }
10573     if (d->sqlite != NULL) {
10574 	setstatd(d, -1, "connection already established", "08002");
10575 	return SQL_ERROR;
10576     }
10577     buf[0] = '\0';
10578     if (dsnLen == SQL_NTS) {
10579 	len = sizeof (buf) - 1;
10580     } else {
10581 	len = min(sizeof (buf) - 1, dsnLen);
10582     }
10583     if (dsn != NULL) {
10584 	strncpy(buf, (char *) dsn, len);
10585     }
10586     buf[len] = '\0';
10587     if (buf[0] == '\0') {
10588 	setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
10589 	return SQL_ERROR;
10590     }
10591 #if defined(_WIN32) || defined(_WIN64)
10592     /*
10593      * When DSN is in UTF it must be converted to ANSI
10594      * here for ANSI SQLGetPrivateProfileString()
10595      */
10596     if (isu) {
10597 	char *cdsn = utf_to_wmb(buf, len);
10598 
10599 	if (!cdsn) {
10600 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
10601 	    return SQL_ERROR;
10602 	}
10603 	strcpy(buf, cdsn);
10604 	uc_free(cdsn);
10605     }
10606 #endif
10607     busy[0] = '\0';
10608     dbname[0] = '\0';
10609 #ifdef WITHOUT_DRIVERMGR
10610     getdsnattr(buf, "database", dbname, sizeof (dbname));
10611     if (dbname[0] == '\0') {
10612 	strncpy(dbname, buf, sizeof (dbname));
10613 	dbname[sizeof (dbname) - 1] = '\0';
10614     }
10615     getdsnattr(buf, "timeout", busy, sizeof (busy));
10616     sflag[0] = '\0';
10617     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
10618     spflag[0] = '\0';
10619     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
10620     ntflag[0] = '\0';
10621     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
10622     nwflag[0] = '\0';
10623     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
10624     snflag[0] = '\0';
10625     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
10626     lnflag[0] = '\0';
10627     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
10628     ncflag[0] = '\0';
10629     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
10630     fkflag[0] = '\0';
10631     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
10632     loadext[0] = '\0';
10633     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
10634     jmode[0] = '\0';
10635     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
10636 #if defined(_WIN32) || defined(_WIN64)
10637     oemcp[0] = '\0';
10638     getdsnattr(buf, "oemcp", oemcp, sizeof (oemcp));
10639 #endif
10640     biflag[0] = '\0';
10641     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
10642 #else
10643     SQLGetPrivateProfileString(buf, "timeout", "100000",
10644 			       busy, sizeof (busy), ODBC_INI);
10645     SQLGetPrivateProfileString(buf, "database", "",
10646 			       dbname, sizeof (dbname), ODBC_INI);
10647 #if defined(_WIN32) || defined(_WIN64)
10648     /* database name read from registry is not UTF8 !!! */
10649     isu = 0;
10650 #endif
10651     SQLGetPrivateProfileString(buf, "stepapi", "",
10652 			       sflag, sizeof (sflag), ODBC_INI);
10653     SQLGetPrivateProfileString(buf, "syncpragma", "NORMAL",
10654 			       spflag, sizeof (spflag), ODBC_INI);
10655     SQLGetPrivateProfileString(buf, "notxn", "",
10656 			       ntflag, sizeof (ntflag), ODBC_INI);
10657     SQLGetPrivateProfileString(buf, "nowchar", "",
10658 			       nwflag, sizeof (nwflag), ODBC_INI);
10659     SQLGetPrivateProfileString(buf, "shortnames", "",
10660 			       snflag, sizeof (snflag), ODBC_INI);
10661     SQLGetPrivateProfileString(buf, "longnames", "",
10662 			       lnflag, sizeof (lnflag), ODBC_INI);
10663     SQLGetPrivateProfileString(buf, "nocreat", "",
10664 			       ncflag, sizeof (ncflag), ODBC_INI);
10665     SQLGetPrivateProfileString(buf, "fksupport", "",
10666 			       fkflag, sizeof (fkflag), ODBC_INI);
10667     SQLGetPrivateProfileString(buf, "loadext", "",
10668 			       loadext, sizeof (loadext), ODBC_INI);
10669     SQLGetPrivateProfileString(buf, "journalmode", "",
10670 			       jmode, sizeof (jmode), ODBC_INI);
10671 #if defined(_WIN32) || defined(_WIN64)
10672     SQLGetPrivateProfileString(buf, "oemcp", "1",
10673 			       oemcp, sizeof (oemcp), ODBC_INI);
10674 #endif
10675     SQLGetPrivateProfileString(buf, "bigint", "",
10676 			       biflag, sizeof (biflag), ODBC_INI);
10677 #endif
10678     tracef[0] = '\0';
10679 #ifdef WITHOUT_DRIVERMGR
10680     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
10681 #else
10682     SQLGetPrivateProfileString(buf, "tracefile", "",
10683 			       tracef, sizeof (tracef), ODBC_INI);
10684 #endif
10685     if (tracef[0] != '\0') {
10686 	d->trace = fopen(tracef, "a");
10687     }
10688     d->nowchar = getbool(nwflag);
10689     d->shortnames = getbool(snflag);
10690     d->longnames = getbool(lnflag);
10691     d->nocreat = getbool(ncflag);
10692     d->fksupport = getbool(fkflag);
10693 #if defined(_WIN32) || defined(_WIN64)
10694     d->oemcp = getbool(oemcp);
10695 #else
10696     d->oemcp = 0;
10697 #endif
10698     d->dobigint = getbool(biflag);
10699     d->pwd = pwd;
10700     d->pwdLen = 0;
10701     if (d->pwd) {
10702 	d->pwdLen = (pwdLen == SQL_NTS) ? strlen(d->pwd) : pwdLen;
10703     }
10704     ret = dbopen(d, dbname, isu, (char *) dsn, sflag, spflag, ntflag,
10705 		  jmode, busy);
10706     if (ret == SQL_SUCCESS) {
10707 	dbloadext(d, loadext);
10708     }
10709     return ret;
10710 }
10711 
10712 #ifndef WINTERFACE
10713 /**
10714  * Connect to SQLite database.
10715  * @param dbc database connection handle
10716  * @param dsn DSN string
10717  * @param dsnLen length of DSN string or SQL_NTS
10718  * @param uid user id string or NULL
10719  * @param uidLen length of user id string or SQL_NTS
10720  * @param pwd password string or NULL
10721  * @param pwdLen length of password string or SQL_NTS
10722  * @result ODBC error code
10723  */
10724 
10725 SQLRETURN SQL_API
SQLConnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,SQLCHAR * uid,SQLSMALLINT uidLen,SQLCHAR * pwd,SQLSMALLINT pwdLen)10726 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
10727 	   SQLCHAR *uid, SQLSMALLINT uidLen,
10728 	   SQLCHAR *pwd, SQLSMALLINT pwdLen)
10729 {
10730     SQLRETURN ret;
10731 
10732     HDBC_LOCK(dbc);
10733     ret = drvconnect(dbc, dsn, dsnLen, (char *) pwd, pwdLen, 0);
10734     HDBC_UNLOCK(dbc);
10735     return ret;
10736 }
10737 #endif
10738 
10739 #ifdef WINTERFACE
10740 /**
10741  * Connect to SQLite database.
10742  * @param dbc database connection handle
10743  * @param dsn DSN string
10744  * @param dsnLen length of DSN string or SQL_NTS
10745  * @param uid user id string or NULL
10746  * @param uidLen length of user id string or SQL_NTS
10747  * @param pwd password string or NULL
10748  * @param pwdLen length of password string or SQL_NTS
10749  * @result ODBC error code
10750  */
10751 
10752 SQLRETURN SQL_API
SQLConnectW(SQLHDBC dbc,SQLWCHAR * dsn,SQLSMALLINT dsnLen,SQLWCHAR * uid,SQLSMALLINT uidLen,SQLWCHAR * pwd,SQLSMALLINT pwdLen)10753 SQLConnectW(SQLHDBC dbc, SQLWCHAR *dsn, SQLSMALLINT dsnLen,
10754 	    SQLWCHAR *uid, SQLSMALLINT uidLen,
10755 	    SQLWCHAR *pwd, SQLSMALLINT pwdLen)
10756 {
10757     char *dsna = NULL;
10758     char *pwda = NULL;
10759     SQLRETURN ret;
10760 
10761     HDBC_LOCK(dbc);
10762     if (dsn) {
10763 	dsna = uc_to_utf_c(dsn, dsnLen);
10764 	if (!dsna) {
10765 	    DBC *d = (DBC *) dbc;
10766 
10767 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
10768 	    ret = SQL_ERROR;
10769 	    goto done;
10770 	}
10771     }
10772     if (pwd) {
10773 	pwda = uc_to_utf_c(pwd, pwdLen);
10774 	if (!pwda) {
10775 	    DBC *d = (DBC *) dbc;
10776 
10777 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
10778 	    ret = SQL_ERROR;
10779 	    goto done;
10780 	}
10781     }
10782     ret = drvconnect(dbc, (SQLCHAR *) dsna, SQL_NTS, pwda, SQL_NTS, 1);
10783 done:
10784     HDBC_UNLOCK(dbc);
10785     uc_free(dsna);
10786     uc_free(pwda);
10787     return ret;
10788 }
10789 #endif
10790 
10791 /**
10792  * Internal disconnect given HDBC.
10793  * @param dbc database connection handle
10794  * @result ODBC error code
10795  */
10796 
10797 static SQLRETURN
drvdisconnect(SQLHDBC dbc)10798 drvdisconnect(SQLHDBC dbc)
10799 {
10800     DBC *d;
10801 
10802     if (dbc == SQL_NULL_HDBC) {
10803 	return SQL_INVALID_HANDLE;
10804     }
10805     d = (DBC *) dbc;
10806     if (d->magic != DBC_MAGIC) {
10807 	return SQL_INVALID_HANDLE;
10808     }
10809     if (d->intrans) {
10810 	setstatd(d, -1, "incomplete transaction", "25000");
10811 	return SQL_ERROR;
10812     }
10813     if (d->cur_s3stmt) {
10814 	s3stmt_end(d->cur_s3stmt);
10815     }
10816     if (d->sqlite) {
10817 	if (d->trace) {
10818 	    fprintf(d->trace, "-- sqlite3_close: '%s'\n",
10819 		    d->dbname);
10820 	    fflush(d->trace);
10821 	}
10822 	sqlite3_close(d->sqlite);
10823 	d->sqlite = NULL;
10824     }
10825     freep(&d->dbname);
10826     freep(&d->dsn);
10827     return SQL_SUCCESS;
10828 }
10829 
10830 /**
10831  * Disconnect given HDBC.
10832  * @param dbc database connection handle
10833  * @result ODBC error code
10834  */
10835 
10836 SQLRETURN SQL_API
SQLDisconnect(SQLHDBC dbc)10837 SQLDisconnect(SQLHDBC dbc)
10838 {
10839     SQLRETURN ret;
10840 
10841     HDBC_LOCK(dbc);
10842     ret = drvdisconnect(dbc);
10843     HDBC_UNLOCK(dbc);
10844     return ret;
10845 }
10846 
10847 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
10848 
10849 /**
10850  * Internal standalone (w/o driver manager) database connect.
10851  * @param dbc database connection handle
10852  * @param hwnd dummy window handle or NULL
10853  * @param connIn driver connect input string
10854  * @param connInLen length of driver connect input string or SQL_NTS
10855  * @param connOut driver connect output string
10856  * @param connOutMax length of driver connect output string
10857  * @param connOutLen output length of driver connect output string
10858  * @param drvcompl completion type
10859  * @result ODBC error code
10860  */
10861 
10862 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)10863 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
10864 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
10865 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
10866 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
10867 {
10868     DBC *d;
10869     int len;
10870     SQLRETURN ret;
10871     char buf[SQL_MAX_MESSAGE_LENGTH * 2], dbname[SQL_MAX_MESSAGE_LENGTH / 4];
10872     char dsn[SQL_MAX_MESSAGE_LENGTH / 4], busy[SQL_MAX_MESSAGE_LENGTH / 4];
10873     char tracef[SQL_MAX_MESSAGE_LENGTH], loadext[SQL_MAX_MESSAGE_LENGTH];
10874     char pwd[SQL_MAX_MESSAGE_LENGTH];
10875     char sflag[32], spflag[32], ntflag[32], snflag[32], lnflag[32];
10876     char ncflag[32], nwflag[32], fkflag[32], jmode[32], biflag[32];
10877 
10878     if (dbc == SQL_NULL_HDBC) {
10879 	return SQL_INVALID_HANDLE;
10880     }
10881     if (drvcompl != SQL_DRIVER_COMPLETE &&
10882 	drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
10883 	drvcompl != SQL_DRIVER_PROMPT &&
10884 	drvcompl != SQL_DRIVER_NOPROMPT) {
10885 	return SQL_NO_DATA;
10886     }
10887     d = (DBC *) dbc;
10888     if (d->sqlite) {
10889 	setstatd(d, -1, "connection already established", "08002");
10890 	return SQL_ERROR;
10891     }
10892     buf[0] = '\0';
10893     if (connInLen == SQL_NTS) {
10894 	len = sizeof (buf) - 1;
10895     } else {
10896 	len = min(connInLen, sizeof (buf) - 1);
10897     }
10898     if (connIn != NULL) {
10899 	strncpy(buf, (char *) connIn, len);
10900     }
10901     buf[len] = '\0';
10902     if (!buf[0]) {
10903 	setstatd(d, -1, "invalid connect attributes",
10904 		 (*d->ov3) ? "HY090" : "S1090");
10905 	return SQL_ERROR;
10906     }
10907     dsn[0] = '\0';
10908     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
10909 
10910     /* special case: connIn is sole DSN value without keywords */
10911     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
10912 	strncpy(dsn, buf, sizeof (dsn) - 1);
10913 	dsn[sizeof (dsn) - 1] = '\0';
10914     }
10915 
10916     busy[0] = '\0';
10917     getdsnattr(buf, "timeout", busy, sizeof (busy));
10918 #ifndef WITHOUT_DRIVERMGR
10919     if (dsn[0] && !busy[0]) {
10920 	SQLGetPrivateProfileString(dsn, "timeout", "100000",
10921 				   busy, sizeof (busy), ODBC_INI);
10922     }
10923 #endif
10924     dbname[0] = '\0';
10925     getdsnattr(buf, "database", dbname, sizeof (dbname));
10926 #ifndef WITHOUT_DRIVERMGR
10927     if (dsn[0] && !dbname[0]) {
10928 	SQLGetPrivateProfileString(dsn, "database", "",
10929 				   dbname, sizeof (dbname), ODBC_INI);
10930     }
10931 #endif
10932     sflag[0] = '\0';
10933     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
10934 #ifndef WITHOUT_DRIVERMGR
10935     if (dsn[0] && !sflag[0]) {
10936 	SQLGetPrivateProfileString(dsn, "stepapi", "",
10937 				   sflag, sizeof (sflag), ODBC_INI);
10938     }
10939 #endif
10940     spflag[0] = '\0';
10941     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
10942 #ifndef WITHOUT_DRIVERMGR
10943     if (dsn[0] && !spflag[0]) {
10944 	SQLGetPrivateProfileString(dsn, "syncpragma", "NORMAL",
10945 				   spflag, sizeof (spflag), ODBC_INI);
10946     }
10947 #endif
10948     ntflag[0] = '\0';
10949     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
10950 #ifndef WITHOUT_DRIVERMGR
10951     if (dsn[0] && !ntflag[0]) {
10952 	SQLGetPrivateProfileString(dsn, "notxn", "",
10953 				   ntflag, sizeof (ntflag), ODBC_INI);
10954     }
10955 #endif
10956     snflag[0] = '\0';
10957     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
10958 #ifndef WITHOUT_DRIVERMGR
10959     if (dsn[0] && !snflag[0]) {
10960 	SQLGetPrivateProfileString(dsn, "shortnames", "",
10961 				   snflag, sizeof (snflag), ODBC_INI);
10962     }
10963 #endif
10964     lnflag[0] = '\0';
10965     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
10966 #ifndef WITHOUT_DRIVERMGR
10967     if (dsn[0] && !lnflag[0]) {
10968 	SQLGetPrivateProfileString(dsn, "longnames", "",
10969 				   lnflag, sizeof (lnflag), ODBC_INI);
10970     }
10971 #endif
10972     ncflag[0] = '\0';
10973     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
10974 #ifndef WITHOUT_DRIVERMGR
10975     if (dsn[0] && !ncflag[0]) {
10976 	SQLGetPrivateProfileString(dsn, "nocreat", "",
10977 				   ncflag, sizeof (ncflag), ODBC_INI);
10978     }
10979 #endif
10980     nwflag[0] = '\0';
10981     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
10982 #ifndef WITHOUT_DRIVERMGR
10983     if (dsn[0] && !nwflag[0]) {
10984 	SQLGetPrivateProfileString(dsn, "nowchar", "",
10985 				   nwflag, sizeof (nwflag), ODBC_INI);
10986     }
10987 #endif
10988     fkflag[0] = '\0';
10989     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
10990 #ifndef WITHOUT_DRIVERMGR
10991     if (dsn[0] && !fkflag[0]) {
10992 	SQLGetPrivateProfileString(dsn, "fksupport", "",
10993 				   fkflag, sizeof (fkflag), ODBC_INI);
10994     }
10995 #endif
10996     loadext[0] = '\0';
10997     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
10998 #ifndef WITHOUT_DRIVERMGR
10999     if (dsn[0] && !loadext[0]) {
11000 	SQLGetPrivateProfileString(dsn, "loadext", "",
11001 				   loadext, sizeof (loadext), ODBC_INI);
11002     }
11003 #endif
11004     jmode[0] = '\0';
11005     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
11006 #ifndef WITHOUT_DRIVERMGR
11007     if (dsn[0] && !jmode[0]) {
11008 	SQLGetPrivateProfileString(dsn, "journalmode", "",
11009 				   jmode, sizeof (jmode), ODBC_INI);
11010     }
11011 #endif
11012     biflag[0] = '\0';
11013     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
11014 #ifndef WITHOUT_DRIVERMGR
11015     if (dsn[0] && !biflag[0]) {
11016 	SQLGetPrivateProfileString(dsn, "bigint", "",
11017 				   biflag, sizeof (biflag), ODBC_INI);
11018     }
11019 #endif
11020     pwd[0] = '\0';
11021     getdsnattr(buf, "pwd", pwd, sizeof (pwd));
11022 #ifndef WITHOUT_DRIVERMGR
11023     if (dsn[0] && !pwd[0]) {
11024 	SQLGetPrivateProfileString(dsn, "pwd", "",
11025 				   pwd, sizeof (pwd), ODBC_INI);
11026     }
11027 #endif
11028 
11029     if (!dbname[0] && !dsn[0]) {
11030 	strcpy(dsn, "SQLite");
11031 	strncpy(dbname, buf, sizeof (dbname));
11032 	dbname[sizeof (dbname) - 1] = '\0';
11033     }
11034     tracef[0] = '\0';
11035     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
11036 #ifndef WITHOUT_DRIVERMGR
11037     if (dsn[0] && !tracef[0]) {
11038 	SQLGetPrivateProfileString(dsn, "tracefile", "",
11039 				   tracef, sizeof (tracef), ODBC_INI);
11040     }
11041 #endif
11042     if (connOut || connOutLen) {
11043 	int count;
11044 
11045 	buf[0] = '\0';
11046 	count = snprintf(buf, sizeof (buf),
11047 			 "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s;"
11048 			 "SyncPragma=%s;NoTXN=%s;ShortNames=%s;LongNames=%s;"
11049 			 "NoCreat=%s;NoWCHAR=%s;FKSupport=%s;Tracefile=%s;"
11050 			 "JournalMode=%s;LoadExt=%s;BigInt=%s;PWD=%s",
11051 			 dsn, dbname, sflag, busy, spflag, ntflag,
11052 			 snflag, lnflag, ncflag, nwflag, fkflag, tracef,
11053 			 jmode, loadext, biflag,pwd);
11054 	if (count < 0) {
11055 	    buf[sizeof (buf) - 1] = '\0';
11056 	}
11057 	len = min(connOutMax - 1, strlen(buf));
11058 	if (connOut) {
11059 	    strncpy((char *) connOut, buf, len);
11060 	    connOut[len] = '\0';
11061 	}
11062 	if (connOutLen) {
11063 	    *connOutLen = len;
11064 	}
11065     }
11066     if (tracef[0] != '\0') {
11067 	d->trace = fopen(tracef, "a");
11068     }
11069     d->shortnames = getbool(snflag);
11070     d->longnames = getbool(lnflag);
11071     d->nocreat = getbool(ncflag);
11072     d->nowchar = getbool(nwflag);
11073     d->fksupport = getbool(fkflag);
11074     d->dobigint = getbool(biflag);
11075     d->oemcp = 0;
11076     d->pwdLen = strlen(pwd);
11077     d->pwd = (d->pwdLen > 0) ? pwd : NULL;
11078     ret = dbopen(d, dbname, 0, dsn, sflag, spflag, ntflag, jmode, busy);
11079     memset(pwd, 0, sizeof (pwd));
11080     if (ret == SQL_SUCCESS) {
11081 	dbloadext(d, loadext);
11082     }
11083     return ret;
11084 }
11085 #endif
11086 
11087 /**
11088  * Internal free function for HSTMT.
11089  * @param stmt statement handle
11090  * @result ODBC error code
11091  */
11092 
11093 static SQLRETURN
freestmt(SQLHSTMT stmt)11094 freestmt(SQLHSTMT stmt)
11095 {
11096     STMT *s;
11097     DBC *d;
11098 
11099     if (stmt == SQL_NULL_HSTMT) {
11100 	return SQL_INVALID_HANDLE;
11101     }
11102     s = (STMT *) stmt;
11103     s3stmt_drop(s);
11104     freeresult(s, 1);
11105     freep(&s->query);
11106     d = (DBC *) s->dbc;
11107     if (d && d->magic == DBC_MAGIC) {
11108 	STMT *p, *n;
11109 
11110 	p = NULL;
11111 	n = d->stmt;
11112 	while (n) {
11113 	    if (n == s) {
11114 		break;
11115 	    }
11116 	    p = n;
11117 	    n = n->next;
11118 	}
11119 	if (n) {
11120 	    if (p) {
11121 		p->next = s->next;
11122 	    } else {
11123 		d->stmt = s->next;
11124 	    }
11125 	}
11126     }
11127     freeparams(s);
11128     freep(&s->bindparms);
11129     if (s->row_status0 != &s->row_status1) {
11130 	freep(&s->row_status0);
11131 	s->rowset_size = 1;
11132 	s->row_status0 = &s->row_status1;
11133     }
11134     xfree(s);
11135     return SQL_SUCCESS;
11136 }
11137 
11138 /**
11139  * Allocate HSTMT given HDBC (driver internal version).
11140  * @param dbc database connection handle
11141  * @param stmt pointer to statement handle
11142  * @result ODBC error code
11143  */
11144 
11145 static SQLRETURN
drvallocstmt(SQLHDBC dbc,SQLHSTMT * stmt)11146 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
11147 {
11148     DBC *d;
11149     STMT *s, *sl, *pl;
11150 
11151     if (dbc == SQL_NULL_HDBC) {
11152 	return SQL_INVALID_HANDLE;
11153     }
11154     d = (DBC *) dbc;
11155     if (d->magic != DBC_MAGIC || stmt == NULL) {
11156 	return SQL_INVALID_HANDLE;
11157     }
11158     s = (STMT *) xmalloc(sizeof (STMT));
11159     if (s == NULL) {
11160 	*stmt = SQL_NULL_HSTMT;
11161 	return SQL_ERROR;
11162     }
11163     *stmt = (SQLHSTMT) s;
11164     memset(s, 0, sizeof (STMT));
11165     s->dbc = dbc;
11166     s->ov3 = d->ov3;
11167     s->oemcp = &d->oemcp;
11168     s->nowchar[0] = d->nowchar;
11169     s->nowchar[1] = 0;
11170     s->dobigint = d->dobigint;
11171     s->curtype = d->curtype;
11172     s->row_status0 = &s->row_status1;
11173     s->rowset_size = 1;
11174     s->longnames = d->longnames;
11175     s->retr_data = SQL_RD_ON;
11176     s->max_rows = 0;
11177     s->bind_type = SQL_BIND_BY_COLUMN;
11178     s->bind_offs = NULL;
11179     s->paramset_size = 1;
11180     s->parm_bind_type = SQL_PARAM_BIND_BY_COLUMN;
11181 #ifdef _WIN64
11182     sprintf((char *) s->cursorname, "CUR_%I64X", (SQLUBIGINT) *stmt);
11183 #else
11184     sprintf((char *) s->cursorname, "CUR_%016lX", (long) *stmt);
11185 #endif
11186     sl = d->stmt;
11187     pl = NULL;
11188     while (sl) {
11189 	pl = sl;
11190 	sl = sl->next;
11191     }
11192     if (pl) {
11193 	pl->next = s;
11194     } else {
11195 	d->stmt = s;
11196     }
11197     return SQL_SUCCESS;
11198 }
11199 
11200 /**
11201  * Allocate HSTMT given HDBC.
11202  * @param dbc database connection handle
11203  * @param stmt pointer to statement handle
11204  * @result ODBC error code
11205  */
11206 
11207 SQLRETURN SQL_API
SQLAllocStmt(SQLHDBC dbc,SQLHSTMT * stmt)11208 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
11209 {
11210     SQLRETURN ret;
11211 
11212     HDBC_LOCK(dbc);
11213     ret = drvallocstmt(dbc, stmt);
11214     HDBC_UNLOCK(dbc);
11215     return ret;
11216 }
11217 
11218 /**
11219  * Internal function to perform certain kinds of free/close on STMT.
11220  * @param stmt statement handle
11221  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
11222  * @result ODBC error code
11223  */
11224 
11225 static SQLRETURN
drvfreestmt(SQLHSTMT stmt,SQLUSMALLINT opt)11226 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
11227 {
11228     STMT *s;
11229     SQLRETURN ret = SQL_SUCCESS;
11230     SQLHDBC dbc;
11231 
11232     if (stmt == SQL_NULL_HSTMT) {
11233 	return SQL_INVALID_HANDLE;
11234     }
11235     HSTMT_LOCK(stmt);
11236     s = (STMT *) stmt;
11237     dbc = s->dbc;
11238     switch (opt) {
11239     case SQL_RESET_PARAMS:
11240 	freeparams(s);
11241 	break;
11242     case SQL_UNBIND:
11243 	unbindcols(s);
11244 	break;
11245     case SQL_CLOSE:
11246 	s3stmt_end_if(s);
11247 	freeresult(s, 0);
11248 	break;
11249     case SQL_DROP:
11250 	s3stmt_end_if(s);
11251 	ret = freestmt(stmt);
11252 	break;
11253     default:
11254 	setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
11255 	ret = SQL_ERROR;
11256 	break;
11257     }
11258     HDBC_UNLOCK(dbc);
11259     return ret;
11260 }
11261 
11262 /**
11263  * Free HSTMT.
11264  * @param stmt statement handle
11265  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
11266  * @result ODBC error code
11267  */
11268 
11269 SQLRETURN SQL_API
SQLFreeStmt(SQLHSTMT stmt,SQLUSMALLINT opt)11270 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
11271 {
11272     return drvfreestmt(stmt, opt);
11273 }
11274 
11275 /**
11276  * Cancel HSTMT closing cursor.
11277  * @param stmt statement handle
11278  * @result ODBC error code
11279  */
11280 
11281 SQLRETURN SQL_API
SQLCancel(SQLHSTMT stmt)11282 SQLCancel(SQLHSTMT stmt)
11283 {
11284     if (stmt != SQL_NULL_HSTMT) {
11285 	DBC *d = (DBC *) ((STMT *) stmt)->dbc;
11286 #if defined(_WIN32) || defined(_WIN64)
11287 	/* interrupt when other thread owns critical section */
11288 	int i;
11289 
11290 	for (i = 0; i < 2; i++) {
11291 	    if (d->magic == DBC_MAGIC && d->env &&
11292 		d->env->magic == ENV_MAGIC &&
11293 		d->env->owner != GetCurrentThreadId() &&
11294 		d->env->owner != 0) {
11295 		d->busyint = 1;
11296 		sqlite3_interrupt(d->sqlite);
11297 	    }
11298 	    Sleep(1);
11299 	}
11300 
11301 #else
11302 	if (d->magic == DBC_MAGIC) {
11303 	    d->busyint = 1;
11304 	    sqlite3_interrupt(d->sqlite);
11305 	}
11306 #endif
11307     }
11308     return drvfreestmt(stmt, SQL_CLOSE);
11309 }
11310 
11311 /**
11312  * Internal function to get cursor name of STMT.
11313  * @param stmt statement handle
11314  * @param cursor output buffer
11315  * @param buflen length of output buffer
11316  * @param lenp output length
11317  * @result ODBC error code
11318  */
11319 
11320 static SQLRETURN
drvgetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)11321 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
11322 		 SQLSMALLINT *lenp)
11323 {
11324     STMT *s;
11325 
11326     if (stmt == SQL_NULL_HSTMT) {
11327 	return SQL_INVALID_HANDLE;
11328     }
11329     s = (STMT *) stmt;
11330     if (lenp && !cursor) {
11331 	*lenp = strlen((char *) s->cursorname);
11332 	return SQL_SUCCESS;
11333     }
11334     if (cursor) {
11335 	if (buflen > 0) {
11336 	    strncpy((char *) cursor, (char *) s->cursorname, buflen - 1);
11337 	    cursor[buflen - 1] = '\0';
11338 	}
11339 	if (lenp) {
11340 	    *lenp = min(strlen((char *) s->cursorname), buflen - 1);
11341 	}
11342     }
11343     return SQL_SUCCESS;
11344 }
11345 
11346 #ifndef WINTERFACE
11347 /**
11348  * Get cursor name of STMT.
11349  * @param stmt statement handle
11350  * @param cursor output buffer
11351  * @param buflen length of output buffer
11352  * @param lenp output length
11353  * @result ODBC error code
11354  */
11355 
11356 SQLRETURN SQL_API
SQLGetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)11357 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
11358 		 SQLSMALLINT *lenp)
11359 {
11360     SQLRETURN ret;
11361 #if defined(_WIN32) || defined(_WIN64)
11362     SQLSMALLINT len = 0;
11363 #endif
11364 
11365     HSTMT_LOCK(stmt);
11366 #if defined(_WIN32) || defined(_WIN64)
11367     if (!((STMT *) stmt)->oemcp[0]) {
11368 	ret = drvgetcursorname(stmt, cursor, buflen, lenp);
11369 	goto done;
11370     }
11371     ret = drvgetcursorname(stmt, cursor, buflen, &len);
11372     if (ret == SQL_SUCCESS) {
11373 	char *c = NULL;
11374 
11375 	if (cursor) {
11376 	    c = utf_to_wmb((char *) cursor, len);
11377 	    if (!c) {
11378 		ret = nomem((STMT *) stmt);
11379 		goto done;
11380 	    }
11381 	    c[len] = 0;
11382 	    len = strlen(c);
11383 	    if (buflen > 0) {
11384 		strncpy((char *) cursor, c, buflen - 1);
11385 		cursor[buflen - 1] = 0;
11386 	    }
11387 	    uc_free(c);
11388 	}
11389 	if (lenp) {
11390 	    *lenp = min(len, buflen - 1);
11391 	}
11392     }
11393 done:
11394     ;
11395 #else
11396     ret = drvgetcursorname(stmt, cursor, buflen, lenp);
11397 #endif
11398     HSTMT_UNLOCK(stmt);
11399     return ret;
11400 }
11401 #endif
11402 
11403 #ifdef WINTERFACE
11404 /**
11405  * Get cursor name of STMT (UNICODE version).
11406  * @param stmt statement handle
11407  * @param cursor output buffer
11408  * @param buflen length of output buffer
11409  * @param lenp output length
11410  * @result ODBC error code
11411  */
11412 
11413 SQLRETURN SQL_API
SQLGetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)11414 SQLGetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT buflen,
11415 		  SQLSMALLINT *lenp)
11416 {
11417     SQLRETURN ret;
11418     SQLSMALLINT len = 0;
11419 
11420     HSTMT_LOCK(stmt);
11421     ret = drvgetcursorname(stmt, (SQLCHAR *) cursor, buflen, &len);
11422     if (ret == SQL_SUCCESS) {
11423 	SQLWCHAR *c = NULL;
11424 
11425 	if (cursor) {
11426 	    c = uc_from_utf((SQLCHAR *) cursor, len);
11427 	    if (!c) {
11428 		ret = nomem((STMT *) stmt);
11429 		goto done;
11430 	    }
11431 	    c[len] = 0;
11432 	    len = uc_strlen(c);
11433 	    if (buflen > 0) {
11434 		uc_strncpy(cursor, c, buflen - 1);
11435 		cursor[buflen - 1] = 0;
11436 	    }
11437 	    uc_free(c);
11438 	}
11439 	if (lenp) {
11440 	    *lenp = min(len, buflen - 1);
11441 	}
11442     }
11443 done:
11444     HSTMT_UNLOCK(stmt);
11445     return ret;
11446 }
11447 #endif
11448 
11449 /**
11450  * Internal function to set cursor name on STMT.
11451  * @param stmt statement handle
11452  * @param cursor new cursor name
11453  * @param len length of cursor name or SQL_NTS
11454  * @result ODBC error code
11455  */
11456 
11457 static SQLRETURN
drvsetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)11458 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
11459 {
11460     STMT *s;
11461 
11462     if (stmt == SQL_NULL_HSTMT) {
11463 	return SQL_INVALID_HANDLE;
11464     }
11465     s = (STMT *) stmt;
11466     if (!cursor ||
11467 	!((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
11468 	  (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
11469 	setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
11470 	return SQL_ERROR;
11471     }
11472     if (len == SQL_NTS) {
11473 	len = sizeof (s->cursorname) - 1;
11474     } else {
11475 	len = min(sizeof (s->cursorname) - 1, len);
11476     }
11477     strncpy((char *) s->cursorname, (char *) cursor, len);
11478     s->cursorname[len] = '\0';
11479     return SQL_SUCCESS;
11480 }
11481 
11482 #ifndef WINTERFACE
11483 /**
11484  * Set cursor name on STMT.
11485  * @param stmt statement handle
11486  * @param cursor new cursor name
11487  * @param len length of cursor name or SQL_NTS
11488  * @result ODBC error code
11489  */
11490 
11491 SQLRETURN SQL_API
SQLSetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)11492 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
11493 {
11494 #if defined(_WIN32) || defined(_WIN64)
11495     char *c = NULL;
11496 #endif
11497     SQLRETURN ret;
11498 
11499     HSTMT_LOCK(stmt);
11500 #if defined(_WIN32) || defined(_WIN64)
11501     if (!((STMT *) stmt)->oemcp[0]) {
11502 	ret = drvsetcursorname(stmt, cursor, len);
11503 	goto done2;
11504     }
11505     if (cursor) {
11506 	c = wmb_to_utf_c((char *) cursor, len);
11507 	if (!c) {
11508 	    ret = nomem((STMT *) stmt);
11509 	    goto done;
11510 	}
11511     }
11512     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
11513 #else
11514     ret = drvsetcursorname(stmt, cursor, len);
11515 #endif
11516 #if defined(_WIN32) || defined(_WIN64)
11517 done:
11518     uc_free(c);
11519 done2:
11520     ;
11521 #endif
11522     HSTMT_UNLOCK(stmt);
11523     return ret;
11524 }
11525 #endif
11526 
11527 #ifdef WINTERFACE
11528 /**
11529  * Set cursor name on STMT (UNICODE version).
11530  * @param stmt statement handle
11531  * @param cursor new cursor name
11532  * @param len length of cursor name or SQL_NTS
11533  * @result ODBC error code
11534  */
11535 
11536 SQLRETURN SQL_API
SQLSetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT len)11537 SQLSetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT len)
11538 {
11539     char *c = NULL;
11540     SQLRETURN ret;
11541 
11542     HSTMT_LOCK(stmt);
11543     if (cursor) {
11544 	c = uc_to_utf_c(cursor, len);
11545 	if (!c) {
11546 	    ret = nomem((STMT *) stmt);
11547 	    goto done;
11548 	}
11549     }
11550     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
11551 done:
11552     uc_free(c);
11553     HSTMT_UNLOCK(stmt);
11554     return ret;
11555 }
11556 #endif
11557 
11558 /**
11559  * Close open cursor.
11560  * @param stmt statement handle
11561  * @return ODBC error code
11562  */
11563 
11564 SQLRETURN SQL_API
SQLCloseCursor(SQLHSTMT stmt)11565 SQLCloseCursor(SQLHSTMT stmt)
11566 {
11567     return drvfreestmt(stmt, SQL_CLOSE);
11568 }
11569 
11570 /**
11571  * Allocate a HENV, HDBC, or HSTMT handle.
11572  * @param type handle type
11573  * @param input input handle (HENV, HDBC)
11574  * @param output pointer to output handle (HENV, HDBC, HSTMT)
11575  * @result ODBC error code
11576  */
11577 
11578 SQLRETURN SQL_API
SQLAllocHandle(SQLSMALLINT type,SQLHANDLE input,SQLHANDLE * output)11579 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
11580 {
11581     SQLRETURN ret;
11582 
11583     switch (type) {
11584     case SQL_HANDLE_ENV:
11585 	ret = drvallocenv((SQLHENV *) output);
11586 	if (ret == SQL_SUCCESS) {
11587 	    ENV *e = (ENV *) *output;
11588 
11589 	    if (e && e->magic == ENV_MAGIC) {
11590 		e->ov3 = 1;
11591 	    }
11592 	}
11593 	return ret;
11594     case SQL_HANDLE_DBC:
11595 	return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
11596     case SQL_HANDLE_STMT:
11597 	HDBC_LOCK((SQLHDBC) input);
11598 	ret = drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
11599 	HDBC_UNLOCK((SQLHDBC) input);
11600 	return ret;
11601     }
11602     return SQL_ERROR;
11603 }
11604 
11605 /**
11606  * Free a HENV, HDBC, or HSTMT handle.
11607  * @param type handle type
11608  * @param h handle (HENV, HDBC, or HSTMT)
11609  * @result ODBC error code
11610  */
11611 
11612 SQLRETURN SQL_API
SQLFreeHandle(SQLSMALLINT type,SQLHANDLE h)11613 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
11614 {
11615     switch (type) {
11616     case SQL_HANDLE_ENV:
11617 	return drvfreeenv((SQLHENV) h);
11618     case SQL_HANDLE_DBC:
11619 	return drvfreeconnect((SQLHDBC) h);
11620     case SQL_HANDLE_STMT:
11621 	return drvfreestmt((SQLHSTMT) h, SQL_DROP);
11622     }
11623     return SQL_ERROR;
11624 }
11625 
11626 /**
11627  * Free dynamically allocated column descriptions of STMT.
11628  * @param s statement pointer
11629  */
11630 
11631 static void
freedyncols(STMT * s)11632 freedyncols(STMT *s)
11633 {
11634     if (s->dyncols) {
11635 	int i;
11636 
11637 	for (i = 0; i < s->dcols; i++) {
11638 	    freep(&s->dyncols[i].typename);
11639 	}
11640 	if (s->cols == s->dyncols) {
11641 	    s->cols = NULL;
11642 	    s->ncols = 0;
11643 	}
11644 	freep(&s->dyncols);
11645     }
11646     s->dcols = 0;
11647 }
11648 
11649 /**
11650  * Free statement's result.
11651  * @param s statement pointer
11652  * @param clrcols flag to clear column information
11653  *
11654  * The result rows are free'd using the rowfree function pointer.
11655  * If clrcols is greater than zero, then column bindings and dynamic column
11656  * descriptions are free'd.
11657  * If clrcols is less than zero, then dynamic column descriptions are free'd.
11658  */
11659 
11660 static void
freeresult(STMT * s,int clrcols)11661 freeresult(STMT *s, int clrcols)
11662 {
11663     freep(&s->bincache);
11664     s->bincell = NULL;
11665     s->binlen = 0;
11666     if (s->rows) {
11667 	if (s->rowfree) {
11668 	    s->rowfree(s->rows);
11669 	    s->rowfree = NULL;
11670 	}
11671 	s->rows = NULL;
11672     }
11673     s->nrows = -1;
11674     if (clrcols > 0) {
11675 	freep(&s->bindcols);
11676 	s->nbindcols = 0;
11677     }
11678     if (clrcols) {
11679 	freedyncols(s);
11680 	s->cols = NULL;
11681 	s->ncols = 0;
11682 	s->nowchar[1] = 0;
11683     }
11684 }
11685 
11686 /**
11687  * Reset bound columns to unbound state.
11688  * @param s statement pointer
11689  */
11690 
11691 static void
unbindcols(STMT * s)11692 unbindcols(STMT *s)
11693 {
11694     int i;
11695 
11696     s->bkmrkcol.type = -1;
11697     s->bkmrkcol.max = 0;
11698     s->bkmrkcol.lenp = NULL;
11699     s->bkmrkcol.valp = NULL;
11700     s->bkmrkcol.index = 0;
11701     s->bkmrkcol.offs = 0;
11702     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
11703 	s->bindcols[i].type = -1;
11704 	s->bindcols[i].max = 0;
11705 	s->bindcols[i].lenp = NULL;
11706 	s->bindcols[i].valp = NULL;
11707 	s->bindcols[i].index = i;
11708 	s->bindcols[i].offs = 0;
11709     }
11710 }
11711 
11712 /**
11713  * Reallocate space for bound columns.
11714  * @param s statement pointer
11715  * @param ncols number of columns
11716  * @result ODBC error code
11717  */
11718 
11719 static SQLRETURN
mkbindcols(STMT * s,int ncols)11720 mkbindcols(STMT *s, int ncols)
11721 {
11722     if (s->bindcols) {
11723 	if (s->nbindcols < ncols) {
11724 	    int i;
11725 	    BINDCOL *bindcols =
11726 		xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
11727 
11728 	    if (!bindcols) {
11729 		return nomem(s);
11730 	    }
11731 	    for (i = s->nbindcols; i < ncols; i++) {
11732 		bindcols[i].type = -1;
11733 		bindcols[i].max = 0;
11734 		bindcols[i].lenp = NULL;
11735 		bindcols[i].valp = NULL;
11736 		bindcols[i].index = i;
11737 		bindcols[i].offs = 0;
11738 	    }
11739 	    s->bindcols = bindcols;
11740 	    s->nbindcols = ncols;
11741 	}
11742     } else if (ncols > 0) {
11743 	s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
11744 	if (!s->bindcols) {
11745 	    return nomem(s);
11746 	}
11747 	s->nbindcols = ncols;
11748 	unbindcols(s);
11749     }
11750     return SQL_SUCCESS;
11751 }
11752 
11753 /**
11754  * Internal function to retrieve row data, used by SQLFetch() and
11755  * friends and SQLGetData().
11756  * @param s statement pointer
11757  * @param col column number, 0 based
11758  * @param otype output data type
11759  * @param val output buffer
11760  * @param len length of output buffer
11761  * @param lenp output length
11762  * @param partial flag for partial data retrieval
11763  * @result ODBC error code
11764  */
11765 
11766 static SQLRETURN
getrowdata(STMT * s,SQLUSMALLINT col,SQLSMALLINT otype,SQLPOINTER val,SQLINTEGER len,SQLLEN * lenp,int partial)11767 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
11768 	   SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp, int partial)
11769 {
11770     char **data, valdummy[16];
11771     SQLLEN dummy;
11772     int valnull = 0;
11773     int type = otype;
11774 
11775     if (!lenp) {
11776 	lenp = &dummy;
11777     }
11778     if (!s->rows) {
11779 	*lenp = SQL_NULL_DATA;
11780 	return SQL_NO_DATA;
11781     }
11782     if (col >= s->ncols) {
11783 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
11784 	return SQL_ERROR;
11785     }
11786     if (s->rowp < 0 || s->rowp >= s->nrows) {
11787 	*lenp = SQL_NULL_DATA;
11788 	return SQL_NO_DATA;
11789     }
11790     if (s->retr_data != SQL_RD_ON) {
11791 	return SQL_SUCCESS;
11792     }
11793     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0,
11794 		      s->nowchar[0]);
11795 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
11796     /* MS Access hack part 3 (map SQL_C_DEFAULT to SQL_C_CHAR) */
11797     if (type == SQL_C_WCHAR && otype == SQL_C_DEFAULT) {
11798 	type = SQL_C_CHAR;
11799     }
11800 #endif
11801     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
11802     if (!val) {
11803 	valnull = 1;
11804 	val = (SQLPOINTER) valdummy;
11805     }
11806     if (*data == NULL) {
11807 	*lenp = SQL_NULL_DATA;
11808 	switch (type) {
11809 	case SQL_C_UTINYINT:
11810 	case SQL_C_TINYINT:
11811 	case SQL_C_STINYINT:
11812 #ifdef SQL_BIT
11813 	case SQL_C_BIT:
11814 #endif
11815 	    *((char *) val) = 0;
11816 	    break;
11817 	case SQL_C_USHORT:
11818 	case SQL_C_SHORT:
11819 	case SQL_C_SSHORT:
11820 	    *((short *) val) = 0;
11821 	    break;
11822 	case SQL_C_ULONG:
11823 	case SQL_C_LONG:
11824 	case SQL_C_SLONG:
11825 	    *((SQLINTEGER *) val) = 0;
11826 	    break;
11827 #ifdef SQL_BIGINT
11828 	case SQL_C_SBIGINT:
11829 	case SQL_C_UBIGINT:
11830 	    *((SQLBIGINT *) val) = 0;
11831 	    break;
11832 #endif
11833 	case SQL_C_FLOAT:
11834 	    *((float *) val) = 0;
11835 	    break;
11836 	case SQL_C_DOUBLE:
11837 	    *((double *) val) = 0;
11838 	    break;
11839 	case SQL_C_BINARY:
11840 	case SQL_C_CHAR:
11841 	    *((char *) val) = '\0';
11842 	    break;
11843 #ifdef WCHARSUPPORT
11844 	case SQL_C_WCHAR:
11845 	    *((SQLWCHAR *) val) = '\0';
11846 	    break;
11847 #endif
11848 #ifdef SQL_C_TYPE_DATE
11849 	case SQL_C_TYPE_DATE:
11850 #endif
11851 	case SQL_C_DATE:
11852 	    memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
11853 	    break;
11854 #ifdef SQL_C_TYPE_TIME
11855 	case SQL_C_TYPE_TIME:
11856 #endif
11857 	case SQL_C_TIME:
11858 	    memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
11859 	    break;
11860 #ifdef SQL_C_TYPE_TIMESTAMP
11861 	case SQL_C_TYPE_TIMESTAMP:
11862 #endif
11863 	case SQL_C_TIMESTAMP:
11864 	    memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
11865 	    break;
11866 	default:
11867 	    return SQL_ERROR;
11868 	}
11869     } else {
11870 	char *endp = NULL;
11871 #if defined(_WIN32) || defined(_WIN64)
11872 #ifdef SQL_BIGINT
11873 	char endc;
11874 #endif
11875 #endif
11876 
11877 	switch (type) {
11878 	case SQL_C_UTINYINT:
11879 	case SQL_C_TINYINT:
11880 	case SQL_C_STINYINT:
11881 	    *((char *) val) = strtol(*data, &endp, 0);
11882 	    if (endp && endp == *data) {
11883 		*lenp = SQL_NULL_DATA;
11884 	    } else {
11885 		*lenp = sizeof (char);
11886 	    }
11887 	    break;
11888 #ifdef SQL_BIT
11889 	case SQL_C_BIT:
11890 	    *((char *) val) = getbool(*data);
11891 	    *lenp = sizeof (char);
11892 	    break;
11893 #endif
11894 	case SQL_C_USHORT:
11895 	case SQL_C_SHORT:
11896 	case SQL_C_SSHORT:
11897 	    *((short *) val) = strtol(*data, &endp, 0);
11898 	    if (endp && endp == *data) {
11899 		*lenp = SQL_NULL_DATA;
11900 	    } else {
11901 		*lenp = sizeof (short);
11902 	    }
11903 	    break;
11904 	case SQL_C_ULONG:
11905 	case SQL_C_LONG:
11906 	case SQL_C_SLONG:
11907 	    *((SQLINTEGER *) val) = strtol(*data, &endp, 0);
11908 	    if (endp && endp == *data) {
11909 		*lenp = SQL_NULL_DATA;
11910 	    } else {
11911 		*lenp = sizeof (SQLINTEGER);
11912 	    }
11913 	    break;
11914 #ifdef SQL_BIGINT
11915 	case SQL_C_UBIGINT:
11916 #if defined(_WIN32) || defined(_WIN64)
11917 	    if (sscanf(*data, "%I64u%c", (SQLUBIGINT *) val, &endc) != 1) {
11918 		*lenp = SQL_NULL_DATA;
11919 	    } else {
11920 		*lenp = sizeof (SQLUBIGINT);
11921 	    }
11922 #else
11923 #ifdef __osf__
11924 	    *((SQLUBIGINT *) val) = strtoul(*data, &endp, 0);
11925 #else
11926 	    *((SQLUBIGINT *) val) = strtoull(*data, &endp, 0);
11927 #endif
11928 	    if (endp && endp == *data) {
11929 		*lenp = SQL_NULL_DATA;
11930 	    } else {
11931 		*lenp = sizeof (SQLUBIGINT);
11932 	    }
11933 #endif
11934 	    break;
11935 	case SQL_C_SBIGINT:
11936 #if defined(_WIN32) || defined(_WIN64)
11937 	    if (sscanf(*data, "%I64d%c", (SQLBIGINT *) val, &endc) != 1) {
11938 		*lenp = SQL_NULL_DATA;
11939 	    } else {
11940 		*lenp = sizeof (SQLBIGINT);
11941 	    }
11942 #else
11943 #ifdef __osf__
11944 	    *((SQLBIGINT *) val) = strtol(*data, &endp, 0);
11945 #else
11946 	    *((SQLBIGINT *) val) = strtoll(*data, &endp, 0);
11947 #endif
11948 	    if (endp && endp == *data) {
11949 		*lenp = SQL_NULL_DATA;
11950 	    } else {
11951 		*lenp = sizeof (int);
11952 	    }
11953 #endif
11954 	    break;
11955 #endif
11956 	case SQL_C_FLOAT:
11957 	    *((float *) val) = ln_strtod(*data, &endp);
11958 	    if (endp && endp == *data) {
11959 		*lenp = SQL_NULL_DATA;
11960 	    } else {
11961 		*lenp = sizeof (float);
11962 	    }
11963 	    break;
11964 	case SQL_C_DOUBLE:
11965 	    *((double *) val) = ln_strtod(*data, &endp);
11966 	    if (endp && endp == *data) {
11967 		*lenp = SQL_NULL_DATA;
11968 	    } else {
11969 		*lenp = sizeof (double);
11970 	    }
11971 	    break;
11972 	case SQL_C_BINARY: {
11973 	    int dlen, offs = 0;
11974 	    char *bin;
11975 
11976 	    if (valnull) {
11977 		freep(&s->bincache);
11978 		s->binlen = 0;
11979 		goto doCHAR;
11980 	    }
11981 	    if (*data == s->bincell) {
11982 		if (s->bincache) {
11983 		    bin = s->bincache;
11984 		    dlen = s->binlen;
11985 		} else {
11986 		    goto doCHAR;
11987 		}
11988 	    } else {
11989 		char *dp;
11990 		int i;
11991 
11992 		freep(&s->bincache);
11993 		dp = *data;
11994 		dlen = strlen(dp);
11995 		s->bincell = dp;
11996 		s->binlen = 0;
11997 		if (!(dp[0] == 'x' || dp[0] == 'X') || dp[1] != '\'' ||
11998 		    dp[dlen - 1] != '\'') {
11999 		    goto doCHAR;
12000 		}
12001 		dlen -= 2;
12002 		dp += 2;
12003 		dlen = dlen / 2;
12004 		s->bincache = bin = xmalloc(dlen);
12005 		if (!bin) {
12006 		    return nomem(s);
12007 		}
12008 		s->binlen = dlen;
12009 		memset(s->bincache, 0, dlen);
12010 		for (i = 0; i < dlen; i++) {
12011 		    char *x;
12012 		    int v;
12013 
12014 		    if (!*dp || !(x = strchr(xdigits, *dp))) {
12015 			goto converr;
12016 		    }
12017 		    v = x - xdigits;
12018 		    bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
12019 		    ++dp;
12020 		    if (!*dp || !(x = strchr(xdigits, *dp))) {
12021 converr:
12022 			freep(&s->bincache);
12023 			s->binlen = 0;
12024 			setstat(s, -1, "conversion error",
12025 				(*s->ov3) ? "HY000" : "S1000");
12026 			return SQL_ERROR;
12027 		    }
12028 		    v = x - xdigits;
12029 		    bin[i] |= (v >= 16) ? (v - 6) : v;
12030 		    ++dp;
12031 		}
12032 		bin = s->bincache;
12033 	    }
12034 	    if (partial && len && s->bindcols) {
12035 		if (s->bindcols[col].offs >= dlen) {
12036 		    *lenp = 0;
12037 		    if (!dlen && s->bindcols[col].offs == dlen) {
12038 			s->bindcols[col].offs = 1;
12039 			return SQL_SUCCESS;
12040 		    }
12041 		    s->bindcols[col].offs = 0;
12042 		    return SQL_NO_DATA;
12043 		}
12044 		offs = s->bindcols[col].offs;
12045 		dlen -= offs;
12046 	    }
12047 	    if (val && len) {
12048 		memcpy(val, bin + offs, min(len, dlen));
12049 	    }
12050 	    if (len < 1) {
12051 		*lenp = dlen;
12052 	    } else {
12053 		*lenp = min(len, dlen);
12054 		if (*lenp == len && *lenp != dlen) {
12055 		    *lenp = SQL_NO_TOTAL;
12056 		}
12057 	    }
12058 	    if (partial && len && s->bindcols) {
12059 		if (*lenp == SQL_NO_TOTAL) {
12060 		    *lenp = dlen;
12061 		    s->bindcols[col].offs += len;
12062 		    setstat(s, -1, "data right truncated", "01004");
12063 		    if (s->bindcols[col].lenp) {
12064 			*s->bindcols[col].lenp = dlen;
12065 		    }
12066 		    return SQL_SUCCESS_WITH_INFO;
12067 		}
12068 		s->bindcols[col].offs += *lenp;
12069 	    }
12070 	    if (*lenp == SQL_NO_TOTAL) {
12071 		*lenp = dlen;
12072 		setstat(s, -1, "data right truncated", "01004");
12073 		return SQL_SUCCESS_WITH_INFO;
12074 	    }
12075 	    break;
12076 	}
12077 	doCHAR:
12078 #ifdef WCHARSUPPORT
12079 	case SQL_C_WCHAR:
12080 #endif
12081 	case SQL_C_CHAR: {
12082 	    int doz, zlen = len - 1;
12083 	    int dlen = strlen(*data);
12084 	    int offs = 0;
12085 #ifdef WCHARSUPPORT
12086 	    SQLWCHAR *ucdata = NULL;
12087 	    SQLCHAR *cdata = (SQLCHAR *) *data;
12088 #endif
12089 
12090 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
12091 	    /* MS Access hack part 2 (reserved error -7748) */
12092 	    if (!valnull &&
12093 		(s->cols == statSpec2P || s->cols == statSpec3P) &&
12094 		type == SQL_C_WCHAR) {
12095 		if (len > 0 && len <= sizeof (SQLWCHAR)) {
12096 		    ((char *) val)[0] = data[0][0];
12097 		    memset((char *) val + 1, 0, len - 1);
12098 		    *lenp = 1;
12099 		    return SQL_SUCCESS;
12100 		}
12101 	    }
12102 #endif
12103 
12104 #ifdef WCHARSUPPORT
12105 	    switch (type) {
12106 	    case SQL_C_CHAR:
12107 		doz = 1;
12108 		break;
12109 	    case SQL_C_WCHAR:
12110 		doz = sizeof (SQLWCHAR);
12111 		break;
12112 	    default:
12113 		doz = 0;
12114 		break;
12115 	    }
12116 	    if (type == SQL_C_WCHAR) {
12117 		ucdata = uc_from_utf(cdata, dlen);
12118 		if (!ucdata) {
12119 		    return nomem(s);
12120 		}
12121 		dlen = uc_strlen(ucdata) * sizeof (SQLWCHAR);
12122 	    }
12123 #if defined(_WIN32) || defined(_WIN64)
12124 	    else if (*s->oemcp && type == SQL_C_CHAR) {
12125 		ucdata = (SQLWCHAR *) utf_to_wmb((char *) cdata, dlen);
12126 		if (!ucdata) {
12127 		    return nomem(s);
12128 		}
12129 		cdata = (SQLCHAR *) ucdata;
12130 		dlen = strlen((char *) cdata);
12131 	    }
12132 #endif
12133 #else
12134 	    doz = (type == SQL_C_CHAR) ? 1 : 0;
12135 #endif
12136 	    if (partial && len && s->bindcols) {
12137 		if (s->bindcols[col].offs >= dlen) {
12138 #ifdef WCHARSUPPORT
12139 		    uc_free(ucdata);
12140 #endif
12141 		    *lenp = 0;
12142 		    if (doz && val) {
12143 #ifdef WCHARSUPPORT
12144 			if (type == SQL_C_WCHAR) {
12145 			    ((SQLWCHAR *) val)[0] = 0;
12146 			} else {
12147 			    ((char *) val)[0] = '\0';
12148 			}
12149 #else
12150 			((char *) val)[0] = '\0';
12151 #endif
12152 		    }
12153 		    if (!dlen && s->bindcols[col].offs == dlen) {
12154 			s->bindcols[col].offs = 1;
12155 			return SQL_SUCCESS;
12156 		    }
12157 		    s->bindcols[col].offs = 0;
12158 		    return SQL_NO_DATA;
12159 		}
12160 		offs = s->bindcols[col].offs;
12161 		dlen -= offs;
12162 	    }
12163 	    if (val && !valnull && len) {
12164 #ifdef WCHARSUPPORT
12165 		if (type == SQL_C_WCHAR) {
12166 		    uc_strncpy(val, ucdata + offs / sizeof (SQLWCHAR),
12167 			       (len - doz) / sizeof (SQLWCHAR));
12168 		} else {
12169 		    strncpy(val, (char *) cdata + offs, len - doz);
12170 		}
12171 #else
12172 		strncpy(val, *data + offs, len - doz);
12173 #endif
12174 	    }
12175 	    if (valnull || len < 1) {
12176 		*lenp = dlen;
12177 	    } else {
12178 		*lenp = min(len - doz, dlen);
12179 		if (*lenp == len - doz && *lenp != dlen) {
12180 		    *lenp = SQL_NO_TOTAL;
12181 		} else if (*lenp < zlen) {
12182 		    zlen = *lenp;
12183 		}
12184 	    }
12185 	    if (len && !valnull && doz) {
12186 #ifdef WCHARSUPPORT
12187 		if (type == SQL_C_WCHAR) {
12188 		    ((SQLWCHAR *) val)[zlen / sizeof (SQLWCHAR)] = 0;
12189 		} else {
12190 		    ((char *) val)[zlen] = '\0';
12191 		}
12192 #else
12193 		((char *) val)[zlen] = '\0';
12194 #endif
12195 	    }
12196 #ifdef WCHARSUPPORT
12197 	    uc_free(ucdata);
12198 #endif
12199 	    if (partial && len && s->bindcols) {
12200 		if (*lenp == SQL_NO_TOTAL) {
12201 		    *lenp = dlen;
12202 		    s->bindcols[col].offs += len - doz;
12203 		    setstat(s, -1, "data right truncated", "01004");
12204 		    if (s->bindcols[col].lenp) {
12205 			*s->bindcols[col].lenp = dlen;
12206 		    }
12207 		    return SQL_SUCCESS_WITH_INFO;
12208 		}
12209 		s->bindcols[col].offs += *lenp;
12210 	    }
12211 	    if (*lenp == SQL_NO_TOTAL) {
12212 		*lenp = dlen;
12213 		setstat(s, -1, "data right truncated", "01004");
12214 		return SQL_SUCCESS_WITH_INFO;
12215 	    }
12216 	    break;
12217 	}
12218 #ifdef SQL_C_TYPE_DATE
12219 	case SQL_C_TYPE_DATE:
12220 #endif
12221 	case SQL_C_DATE:
12222 	    if (str2date(*data, (DATE_STRUCT *) val) < 0) {
12223 		*lenp = SQL_NULL_DATA;
12224 	    } else {
12225 		*lenp = sizeof (DATE_STRUCT);
12226 	    }
12227 	    break;
12228 #ifdef SQL_C_TYPE_TIME
12229 	case SQL_C_TYPE_TIME:
12230 #endif
12231 	case SQL_C_TIME:
12232 	    if (str2time(*data, (TIME_STRUCT *) val) < 0) {
12233 		*lenp = SQL_NULL_DATA;
12234 	    } else {
12235 		*lenp = sizeof (TIME_STRUCT);
12236 	    }
12237 	    break;
12238 #ifdef SQL_C_TYPE_TIMESTAMP
12239 	case SQL_C_TYPE_TIMESTAMP:
12240 #endif
12241 	case SQL_C_TIMESTAMP:
12242 	    if (str2timestamp(*data, (TIMESTAMP_STRUCT *) val) < 0) {
12243 		*lenp = SQL_NULL_DATA;
12244 	    } else {
12245 		*lenp = sizeof (TIMESTAMP_STRUCT);
12246 	    }
12247 	    switch (s->cols[col].prec) {
12248 	    case 0:
12249 		((TIMESTAMP_STRUCT *) val)->fraction = 0;
12250 		break;
12251 	    case 1:
12252 		((TIMESTAMP_STRUCT *) val)->fraction /= 100000000;
12253 		((TIMESTAMP_STRUCT *) val)->fraction *= 100000000;
12254 		break;
12255 	    case 2:
12256 		((TIMESTAMP_STRUCT *) val)->fraction /= 10000000;
12257 		((TIMESTAMP_STRUCT *) val)->fraction *= 10000000;
12258 		break;
12259 	    }
12260 	    break;
12261 	default:
12262 	    return SQL_ERROR;
12263 	}
12264     }
12265     return SQL_SUCCESS;
12266 }
12267 
12268 /**
12269  * Interal bind C variable to column of result set.
12270  * @param stmt statement handle
12271  * @param col column number, starting at 1
12272  * @param type output type
12273  * @param val output buffer
12274  * @param max length of output buffer
12275  * @param lenp output length pointer
12276  * @result ODBC error code
12277  */
12278 
12279 static SQLRETURN
drvbindcol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)12280 drvbindcol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
12281 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
12282 {
12283     STMT *s;
12284     int sz = 0;
12285 
12286     if (stmt == SQL_NULL_HSTMT) {
12287 	return SQL_INVALID_HANDLE;
12288     }
12289     s = (STMT *) stmt;
12290     if (col < 1) {
12291 	if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
12292 	    s->bkmrkcol.type = type;
12293 	    s->bkmrkcol.max = sizeof (SQLINTEGER);
12294 	    s->bkmrkcol.lenp = lenp;
12295 	    s->bkmrkcol.valp = val;
12296 	    s->bkmrkcol.offs = 0;
12297 	    if (lenp) {
12298 		*lenp = 0;
12299 	    }
12300 	    return SQL_SUCCESS;
12301 	}
12302 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
12303 	return SQL_ERROR;
12304     }
12305     if (mkbindcols(s, col) != SQL_SUCCESS) {
12306 	return SQL_ERROR;
12307     }
12308     --col;
12309     if (type == SQL_C_DEFAULT) {
12310 	type = mapdeftype(type, s->cols[col].type, 0,
12311 			  s->nowchar[0] || s->nowchar[1]);
12312     }
12313     switch (type) {
12314     case SQL_C_LONG:
12315     case SQL_C_ULONG:
12316     case SQL_C_SLONG:
12317 	sz = sizeof (SQLINTEGER);
12318 	break;
12319     case SQL_C_TINYINT:
12320     case SQL_C_UTINYINT:
12321     case SQL_C_STINYINT:
12322 	sz = sizeof (SQLCHAR);
12323 	break;
12324     case SQL_C_SHORT:
12325     case SQL_C_USHORT:
12326     case SQL_C_SSHORT:
12327 	sz = sizeof (short);
12328 	break;
12329     case SQL_C_FLOAT:
12330 	sz = sizeof (SQLFLOAT);
12331 	break;
12332     case SQL_C_DOUBLE:
12333 	sz = sizeof (SQLDOUBLE);
12334 	break;
12335     case SQL_C_TIMESTAMP:
12336 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
12337 	break;
12338     case SQL_C_TIME:
12339 	sz = sizeof (SQL_TIME_STRUCT);
12340 	break;
12341     case SQL_C_DATE:
12342 	sz = sizeof (SQL_DATE_STRUCT);
12343 	break;
12344     case SQL_C_CHAR:
12345 	break;
12346 #ifdef WINTERFACE
12347     case SQL_C_WCHAR:
12348 	break;
12349 #endif
12350 #ifdef SQL_C_TYPE_DATE
12351     case SQL_C_TYPE_DATE:
12352 	sz = sizeof (SQL_DATE_STRUCT);
12353 	break;
12354 #endif
12355 #ifdef SQL_C_TYPE_TIME
12356     case SQL_C_TYPE_TIME:
12357 	sz = sizeof (SQL_TIME_STRUCT);
12358 	break;
12359 #endif
12360 #ifdef SQL_C_TYPE_TIMESTAMP
12361     case SQL_C_TYPE_TIMESTAMP:
12362 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
12363 	break;
12364 #endif
12365 #ifdef SQL_BIT
12366     case SQL_C_BIT:
12367 	sz = sizeof (SQLCHAR);
12368 	break;
12369 #endif
12370     case SQL_C_BINARY:
12371 	break;
12372 #ifdef SQL_BIGINT
12373     case SQL_C_SBIGINT:
12374     case SQL_C_UBIGINT:
12375 	sz = sizeof (SQLBIGINT);
12376 	break;
12377 #endif
12378     default:
12379 	if (val == NULL) {
12380 	    /* fall through, unbinding column */
12381 	    break;
12382 	}
12383 	setstat(s, -1, "invalid type %d", "HY003", type);
12384 	return SQL_ERROR;
12385     }
12386     if (val == NULL) {
12387 	/* unbind column */
12388 	s->bindcols[col].type = -1;
12389 	s->bindcols[col].max = 0;
12390 	s->bindcols[col].lenp = NULL;
12391 	s->bindcols[col].valp = NULL;
12392 	s->bindcols[col].offs = 0;
12393     } else {
12394 	if (sz == 0 && max < 0) {
12395 	    setstat(s, -1, "invalid length", "HY090");
12396 	    return SQL_ERROR;
12397 	}
12398 	s->bindcols[col].type = type;
12399 	s->bindcols[col].max = (sz == 0) ? max : sz;
12400 	s->bindcols[col].lenp = lenp;
12401 	s->bindcols[col].valp = val;
12402 	s->bindcols[col].offs = 0;
12403 	if (lenp) {
12404 	    *lenp = 0;
12405 	}
12406     }
12407     return SQL_SUCCESS;
12408 }
12409 
12410 /**
12411  * Bind C variable to column of result set.
12412  * @param stmt statement handle
12413  * @param col column number, starting at 1
12414  * @param type output type
12415  * @param val output buffer
12416  * @param max length of output buffer
12417  * @param lenp output length pointer
12418  * @result ODBC error code
12419  */
12420 
12421 SQLRETURN SQL_API
SQLBindCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)12422 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
12423 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
12424 {
12425     SQLRETURN ret;
12426 
12427     HSTMT_LOCK(stmt);
12428     ret = drvbindcol(stmt, col, type, val, max, lenp);
12429     HSTMT_UNLOCK(stmt);
12430     return ret;
12431 }
12432 
12433 /**
12434  * Columns for result set of SQLTables().
12435  */
12436 
12437 static COL tableSpec2[] = {
12438     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
12439     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
12440     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
12441     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
12442     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
12443 };
12444 
12445 static COL tableSpec3[] = {
12446     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
12447     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
12448     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
12449     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
12450     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
12451 };
12452 
12453 /**
12454  * Retrieve information on tables and/or views.
12455  * @param stmt statement handle
12456  * @param cat catalog name/pattern or NULL
12457  * @param catLen length of catalog name/pattern or SQL_NTS
12458  * @param schema schema name/pattern or NULL
12459  * @param schemaLen length of schema name/pattern or SQL_NTS
12460  * @param table table name/pattern or NULL
12461  * @param tableLen length of table name/pattern or SQL_NTS
12462  * @param type types of tables string or NULL
12463  * @param typeLen length of types of tables string or SQL_NTS
12464  * @result ODBC error code
12465  */
12466 
12467 static SQLRETURN
drvtables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)12468 drvtables(SQLHSTMT stmt,
12469 	  SQLCHAR *cat, SQLSMALLINT catLen,
12470 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
12471 	  SQLCHAR *table, SQLSMALLINT tableLen,
12472 	  SQLCHAR *type, SQLSMALLINT typeLen)
12473 {
12474     SQLRETURN ret;
12475     STMT *s;
12476     DBC *d;
12477     int ncols, asize, rc, size, npatt;
12478     char *errp = NULL, *sql, tname[512];
12479     char *where = "(type = 'table' or type = 'view')";
12480 
12481     ret = mkresultset(stmt, tableSpec2, array_size(tableSpec2),
12482 		      tableSpec3, array_size(tableSpec3), &asize);
12483     if (ret != SQL_SUCCESS) {
12484 	return ret;
12485     }
12486     s = (STMT *) stmt;
12487     d = (DBC *) s->dbc;
12488     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
12489 	int size = 3 * asize;
12490 
12491 	s->rows = xmalloc(size * sizeof (char *));
12492 	if (!s->rows) {
12493 	    s->nrows = 0;
12494 	    return nomem(s);
12495 	}
12496 	memset(s->rows, 0, sizeof (char *) * size);
12497 	s->ncols = asize;
12498 	s->rows[s->ncols + 0] = "";
12499 	s->rows[s->ncols + 1] = "";
12500 	s->rows[s->ncols + 2] = "";
12501 	s->rows[s->ncols + 3] = "TABLE";
12502 	s->rows[s->ncols + 5] = "";
12503 	s->rows[s->ncols + 6] = "";
12504 	s->rows[s->ncols + 7] = "";
12505 	s->rows[s->ncols + 8] = "VIEW";
12506 #ifdef MEMORY_DEBUG
12507 	s->rowfree = xfree__;
12508 #else
12509 	s->rowfree = sqlite3_free;
12510 #endif
12511 	s->nrows = 2;
12512 	s->rowp = -1;
12513 	return SQL_SUCCESS;
12514     }
12515     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
12516 	table = NULL;
12517 	goto doit;
12518     }
12519     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
12520 	schema[0] == '%') {
12521 	if ((!cat || catLen == 0 || !cat[0]) &&
12522 	    (!table || tableLen == 0 || !table[0])) {
12523 	    table = NULL;
12524 	    goto doit;
12525 	}
12526     }
12527     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] != '\0') {
12528 	char tmp[256], *t;
12529 	int with_view = 0, with_table = 0;
12530 
12531 	if (typeLen == SQL_NTS) {
12532 	    strncpy(tmp, (char *) type, sizeof (tmp));
12533 	    tmp[sizeof (tmp) - 1] = '\0';
12534 	} else {
12535 	    int len = min(sizeof (tmp) - 1, typeLen);
12536 
12537 	    strncpy(tmp, (char *) type, len);
12538 	    tmp[len] = '\0';
12539 	}
12540 	t = tmp;
12541 	while (*t) {
12542 	    *t = TOLOWER(*t);
12543 	    t++;
12544 	}
12545 	t = tmp;
12546 	unescpat(t);
12547 	while (t) {
12548 	    if (t[0] == '\'') {
12549 		++t;
12550 	    }
12551 	    if (strncmp(t, "table", 5) == 0) {
12552 		with_table++;
12553 	    } else if (strncmp(t, "view", 4) == 0) {
12554 		with_view++;
12555 	    }
12556 	    t = strchr(t, ',');
12557 	    if (t) {
12558 		++t;
12559 	    }
12560 	}
12561 	if (with_view && with_table) {
12562 	    /* where is already preset */
12563 	} else if (with_view && !with_table) {
12564 	    where = "type = 'view'";
12565 	} else if (!with_view && with_table) {
12566 	    where = "type = 'table'";
12567 	} else {
12568 	    return SQL_SUCCESS;
12569 	}
12570     }
12571 doit:
12572     if (!table) {
12573 	size = 1;
12574 	tname[0] = '%';
12575     } else {
12576 	if (tableLen == SQL_NTS) {
12577 	    size = sizeof (tname) - 1;
12578 	} else {
12579 	    size = min(sizeof (tname) - 1, tableLen);
12580 	}
12581 	strncpy(tname, (char *) table, size);
12582     }
12583     tname[size] = '\0';
12584     npatt = unescpat(tname);
12585 #if defined(_WIN32) || defined(_WIN64)
12586     sql = sqlite3_mprintf("select %s as 'TABLE_QUALIFIER', "
12587 			  "%s as 'TABLE_OWNER', "
12588 			  "tbl_name as 'TABLE_NAME', "
12589 			  "upper(type) as 'TABLE_TYPE', "
12590 			  "NULL as 'REMARKS' "
12591 			  "from sqlite_master where %s "
12592 			  "and tbl_name %s %Q",
12593 			  d->xcelqrx ? "''" : "NULL",
12594 			  d->xcelqrx ? "'main'" : "NULL",
12595 			  where,
12596 			  npatt ? "like" : "=", tname);
12597 #else
12598     sql = sqlite3_mprintf("select NULL as 'TABLE_QUALIFIER', "
12599 			  "NULL as 'TABLE_OWNER', "
12600 			  "tbl_name as 'TABLE_NAME', "
12601 			  "upper(type) as 'TABLE_TYPE', "
12602 			  "NULL as 'REMARKS' "
12603 			  "from sqlite_master where %s "
12604 			  "and tbl_name %s %Q", where,
12605 			  npatt ? "like" : "=", tname);
12606 #endif
12607     if (!sql) {
12608 	return nomem(s);
12609     }
12610     ret = starttran(s);
12611     if (ret != SQL_SUCCESS) {
12612 	sqlite3_free(sql);
12613 	return ret;
12614     }
12615     dbtraceapi(d, "sqlite3_get_table", sql);
12616     rc = sqlite3_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
12617     sqlite3_free(sql);
12618     if (rc == SQLITE_OK) {
12619 	if (ncols != s->ncols) {
12620 	    freeresult(s, 0);
12621 	    s->nrows = 0;
12622 	} else {
12623 	    s->rowfree = sqlite3_free_table;
12624 	}
12625     } else {
12626 	s->nrows = 0;
12627 	s->rows = NULL;
12628 	s->rowfree = NULL;
12629     }
12630     if (errp) {
12631 	sqlite3_free(errp);
12632 	errp = NULL;
12633     }
12634     s->rowp = -1;
12635     return SQL_SUCCESS;
12636 }
12637 
12638 #ifndef WINTERFACE
12639 /**
12640  * Retrieve information on tables and/or views.
12641  * @param stmt statement handle
12642  * @param cat catalog name/pattern or NULL
12643  * @param catLen length of catalog name/pattern or SQL_NTS
12644  * @param schema schema name/pattern or NULL
12645  * @param schemaLen length of schema name/pattern or SQL_NTS
12646  * @param table table name/pattern or NULL
12647  * @param tableLen length of table name/pattern or SQL_NTS
12648  * @param type types of tables string or NULL
12649  * @param typeLen length of types of tables string or SQL_NTS
12650  * @result ODBC error code
12651  */
12652 
12653 SQLRETURN SQL_API
SQLTables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)12654 SQLTables(SQLHSTMT stmt,
12655 	  SQLCHAR *cat, SQLSMALLINT catLen,
12656 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
12657 	  SQLCHAR *table, SQLSMALLINT tableLen,
12658 	  SQLCHAR *type, SQLSMALLINT typeLen)
12659 {
12660 #if defined(_WIN32) || defined(_WIN64)
12661     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
12662 #endif
12663     SQLRETURN ret;
12664 
12665     HSTMT_LOCK(stmt);
12666 #if defined(_WIN32) || defined(_WIN64)
12667     if (!((STMT *) stmt)->oemcp[0]) {
12668 	ret = drvtables(stmt, cat, catLen, schema, schemaLen,
12669 			table, tableLen, type, typeLen);
12670 	goto done2;
12671     }
12672     if (cat) {
12673 	c = wmb_to_utf_c((char *) cat, catLen);
12674 	if (!c) {
12675 	    ret = nomem((STMT *) stmt);
12676 	    goto done;
12677 	}
12678     }
12679     if (schema) {
12680 	s = wmb_to_utf_c((char *) schema, schemaLen);
12681 	if (!s) {
12682 	    ret = nomem((STMT *) stmt);
12683 	    goto done;
12684 	}
12685     }
12686     if (table) {
12687 	t = wmb_to_utf_c((char *) table, tableLen);
12688 	if (!t) {
12689 	    ret = nomem((STMT *) stmt);
12690 	    goto done;
12691 	}
12692     }
12693     if (type) {
12694 	y = wmb_to_utf_c((char *) type, typeLen);
12695 	if (!y) {
12696 	    ret = nomem((STMT *) stmt);
12697 	    goto done;
12698 	}
12699     }
12700     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
12701 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
12702 #else
12703     ret = drvtables(stmt, cat, catLen, schema, schemaLen,
12704 		    table, tableLen, type, typeLen);
12705 #endif
12706 #if defined(_WIN32) || defined(_WIN64)
12707 done:
12708     uc_free(y);
12709     uc_free(t);
12710     uc_free(s);
12711     uc_free(c);
12712 done2:
12713     ;
12714 #endif
12715     HSTMT_UNLOCK(stmt);
12716     return ret;
12717 }
12718 #endif
12719 
12720 #ifdef WINTERFACE
12721 /**
12722  * Retrieve information on tables and/or views.
12723  * @param stmt statement handle
12724  * @param cat catalog name/pattern or NULL
12725  * @param catLen length of catalog name/pattern or SQL_NTS
12726  * @param schema schema name/pattern or NULL
12727  * @param schemaLen length of schema name/pattern or SQL_NTS
12728  * @param table table name/pattern or NULL
12729  * @param tableLen length of table name/pattern or SQL_NTS
12730  * @param type types of tables string or NULL
12731  * @param typeLen length of types of tables string or SQL_NTS
12732  * @result ODBC error code
12733  */
12734 
12735 SQLRETURN SQL_API
SQLTablesW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * type,SQLSMALLINT typeLen)12736 SQLTablesW(SQLHSTMT stmt,
12737 	   SQLWCHAR *cat, SQLSMALLINT catLen,
12738 	   SQLWCHAR *schema, SQLSMALLINT schemaLen,
12739 	   SQLWCHAR *table, SQLSMALLINT tableLen,
12740 	   SQLWCHAR *type, SQLSMALLINT typeLen)
12741 {
12742     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
12743     SQLRETURN ret;
12744 
12745     HSTMT_LOCK(stmt);
12746     if (cat) {
12747 	c = uc_to_utf_c(cat, catLen);
12748 	if (!c) {
12749 	    ret = nomem((STMT *) stmt);
12750 	    goto done;
12751 	}
12752     }
12753     if (schema) {
12754 	s = uc_to_utf_c(schema, schemaLen);
12755 	if (!s) {
12756 	    ret = nomem((STMT *) stmt);
12757 	    goto done;
12758 	}
12759     }
12760     if (table) {
12761 	t = uc_to_utf_c(table, tableLen);
12762 	if (!t) {
12763 	    ret = nomem((STMT *) stmt);
12764 	    goto done;
12765 	}
12766     }
12767     if (type) {
12768 	y = uc_to_utf_c(type, typeLen);
12769 	if (!y) {
12770 	    ret = nomem((STMT *) stmt);
12771 	    goto done;
12772 	}
12773     }
12774     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
12775 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
12776 done:
12777     uc_free(y);
12778     uc_free(t);
12779     uc_free(s);
12780     uc_free(c);
12781     HSTMT_UNLOCK(stmt);
12782     return ret;
12783 }
12784 #endif
12785 
12786 /**
12787  * Columns for result set of SQLColumns().
12788  */
12789 
12790 static COL colSpec2[] = {
12791     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
12792     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
12793     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
12794     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
12795     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
12796     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
12797     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
12798     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
12799     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
12800     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
12801     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
12802     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
12803     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
12804     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
12805     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
12806     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
12807     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
12808     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
12809 };
12810 
12811 static COL colSpec3[] = {
12812     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
12813     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
12814     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
12815     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
12816     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
12817     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
12818     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
12819     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
12820     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_SMALLINT, 50 },
12821     { "SYSTEM", "COLUMN", "NUM_PREC_RADIX", SQL_SMALLINT, 50 },
12822     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
12823     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
12824     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
12825     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
12826     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
12827     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
12828     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
12829     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
12830 };
12831 
12832 /**
12833  * Internal retrieve column information on table.
12834  * @param stmt statement handle
12835  * @param cat catalog name/pattern or NULL
12836  * @param catLen length of catalog name/pattern or SQL_NTS
12837  * @param schema schema name/pattern or NULL
12838  * @param schemaLen length of schema name/pattern or SQL_NTS
12839  * @param table table name/pattern or NULL
12840  * @param tableLen length of table name/pattern or SQL_NTS
12841  * @param col column name/pattern or NULL
12842  * @param colLen length of column name/pattern or SQL_NTS
12843  * @result ODBC error code
12844  */
12845 
12846 static SQLRETURN
drvcolumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)12847 drvcolumns(SQLHSTMT stmt,
12848 	   SQLCHAR *cat, SQLSMALLINT catLen,
12849 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
12850 	   SQLCHAR *table, SQLSMALLINT tableLen,
12851 	   SQLCHAR *col, SQLSMALLINT colLen)
12852 {
12853     SQLRETURN sret;
12854     STMT *s;
12855     DBC *d;
12856     int ret, nrows, ncols, asize, i, k, roffs, namec;
12857     int tnrows, tncols, npatt;
12858     PTRDIFF_T size;
12859     char *errp = NULL, *sql, tname[512], cname[512], **rowp, **trows;
12860 
12861     sret = mkresultset(stmt, colSpec2, array_size(colSpec2),
12862 		       colSpec3, array_size(colSpec3), &asize);
12863     if (sret != SQL_SUCCESS) {
12864 	return sret;
12865     }
12866     s = (STMT *) stmt;
12867     d = (DBC *) s->dbc;
12868     if (!table) {
12869 	size = 1;
12870 	tname[0] = '%';
12871     } else {
12872 	if (tableLen == SQL_NTS) {
12873 	    size = sizeof (tname) - 1;
12874 	} else {
12875 	    size = min(sizeof (tname) - 1, tableLen);
12876 	}
12877 	strncpy(tname, (char *) table, size);
12878     }
12879     tname[size] = '\0';
12880     npatt = unescpat(tname);
12881     size = 0;
12882     if (col) {
12883 	if (colLen == SQL_NTS) {
12884 	    size = sizeof (cname) - 1;
12885 	} else {
12886 	    size = min(sizeof (cname) - 1, colLen);
12887 	}
12888 	strncpy(cname, (char *) col, size);
12889     }
12890     cname[size] = '\0';
12891     if (!strcmp(cname, "%")) {
12892 	cname[0] = '\0';
12893     }
12894     sql = sqlite3_mprintf("select tbl_name from sqlite_master where "
12895 			  "(type = 'table' or type = 'view') "
12896 			  "and tbl_name %s %Q", npatt ? "like" : "=", tname);
12897     if (!sql) {
12898 	return nomem(s);
12899     }
12900     sret = starttran(s);
12901     if (sret != SQL_SUCCESS) {
12902 	sqlite3_free(sql);
12903 	return sret;
12904     }
12905     dbtraceapi(d, "sqlite3_get_table", sql);
12906     ret = sqlite3_get_table(d->sqlite, sql, &trows, &tnrows, &tncols, &errp);
12907     sqlite3_free(sql);
12908     if (ret != SQLITE_OK) {
12909 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
12910 		errp ? errp : "unknown error", ret);
12911 	if (errp) {
12912 	    sqlite3_free(errp);
12913 	    errp = NULL;
12914 	}
12915 	return SQL_ERROR;
12916     }
12917     if (errp) {
12918 	sqlite3_free(errp);
12919 	errp = NULL;
12920     }
12921     /* pass 1: compute number of rows of result set */
12922     if (tncols * tnrows <= 0) {
12923 	sqlite3_free_table(trows);
12924 	return SQL_SUCCESS;
12925     }
12926     size = 0;
12927     for (i = 1; i <= tnrows; i++) {
12928 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", trows[i]);
12929 	if (!sql) {
12930 	    sqlite3_free_table(trows);
12931 	    return nomem(s);
12932 	}
12933 	dbtraceapi(d, "sqlite3_get_table", sql);
12934 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
12935 	sqlite3_free(sql);
12936 	if (ret != SQLITE_OK) {
12937 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
12938 		    errp ? errp : "unknown error", ret);
12939 	    if (errp) {
12940 		sqlite3_free(errp);
12941 		errp = NULL;
12942 	    }
12943 	    sqlite3_free_table(trows);
12944 	    return SQL_ERROR;
12945 	}
12946 	if (errp) {
12947 	    sqlite3_free(errp);
12948 	    errp = NULL;
12949 	}
12950 	if (ncols * nrows > 0) {
12951 	    namec = -1;
12952 	    for (k = 0; k < ncols; k++) {
12953 		if (strcmp(rowp[k], "name") == 0) {
12954 		    namec = k;
12955 		    break;
12956 		}
12957 	    }
12958 	    if (cname[0]) {
12959 		if (namec >= 0) {
12960 		    for (k = 1; k <= nrows; k++) {
12961 			if (namematch(rowp[k * ncols + namec], cname, 1)) {
12962 			    size++;
12963 			}
12964 		    }
12965 		}
12966 	    } else {
12967 		size += nrows;
12968 	    }
12969 	}
12970 	sqlite3_free_table(rowp);
12971     }
12972     /* pass 2: fill result set */
12973     if (size <= 0) {
12974 	sqlite3_free_table(trows);
12975 	return SQL_SUCCESS;
12976     }
12977     s->nrows = size;
12978     size = (size + 1) * asize;
12979     s->rows = xmalloc((size + 1) * sizeof (char *));
12980     if (!s->rows) {
12981 	s->nrows = 0;
12982 	sqlite3_free_table(trows);
12983 	return nomem(s);
12984     }
12985     s->rows[0] = (char *) size;
12986     s->rows += 1;
12987     memset(s->rows, 0, sizeof (char *) * size);
12988     s->rowfree = freerows;
12989     roffs = 1;
12990     for (i = 1; i <= tnrows; i++) {
12991 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", trows[i]);
12992 	if (!sql) {
12993 	    sqlite3_free_table(trows);
12994 	    return nomem(s);
12995 	}
12996 	dbtraceapi(d, "sqlite3_get_table", sql);
12997 	ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
12998 	sqlite3_free(sql);
12999 	if (ret != SQLITE_OK) {
13000 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
13001 		    errp ? errp : "unknown error", ret);
13002 	    if (errp) {
13003 		sqlite3_free(errp);
13004 		errp = NULL;
13005 	    }
13006 	    sqlite3_free_table(trows);
13007 	    return SQL_ERROR;
13008 	}
13009 	if (errp) {
13010 	    sqlite3_free(errp);
13011 	    errp = NULL;
13012 	}
13013 	if (ncols * nrows > 0) {
13014 	    int m, mr, nr = nrows;
13015 
13016 	    namec = -1;
13017 	    for (k = 0; k < ncols; k++) {
13018 		if (strcmp(rowp[k], "name") == 0) {
13019 		    namec = k;
13020 		    break;
13021 		}
13022 	    }
13023 	    if (cname[0]) {
13024 		nr = 0;
13025 		if (namec >= 0) {
13026 		    for (k = 1; k <= nrows; k++) {
13027 			if (namematch(rowp[k * ncols + namec], cname, 1)) {
13028 			    nr++;
13029 			}
13030 		    }
13031 		}
13032 	    }
13033 	    for (k = 0; k < nr; k++) {
13034 		m = asize * (roffs + k);
13035 		s->rows[m + 0] = xstrdup("");
13036 #if defined(_WIN32) || defined(_WIN64)
13037 		s->rows[m + 1] = xstrdup(d->xcelqrx ? "main" : "");
13038 #else
13039 		s->rows[m + 1] = xstrdup("");
13040 #endif
13041 		s->rows[m + 2] = xstrdup(trows[i]);
13042 		s->rows[m + 8] = xstrdup("10");
13043 		s->rows[m + 9] = xstrdup("0");
13044 		s->rows[m + 15] = xstrdup("16384");
13045 	    }
13046 	    for (k = 0; nr && k < ncols; k++) {
13047 		if (strcmp(rowp[k], "cid") == 0) {
13048 		    for (mr = 0, m = 1; m <= nrows; m++) {
13049 			char buf[256];
13050 			int ir, coln = k;
13051 
13052 			if (cname[0] &&
13053 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
13054 			    continue;
13055 			}
13056 			ir = asize * (roffs + mr);
13057 			sscanf(rowp[m * ncols + k], "%d", &coln);
13058 			sprintf(buf, "%d", coln + 1);
13059 			s->rows[ir + 16] = xstrdup(buf);
13060 			++mr;
13061 		    }
13062 		} else if (k == namec) {
13063 		    for (mr = 0, m = 1; m <= nrows; m++) {
13064 			int ir;
13065 
13066 			if (cname[0] &&
13067 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
13068 			    continue;
13069 			}
13070 			ir = asize * (roffs + mr);
13071 			s->rows[ir + 3] = xstrdup(rowp[m * ncols + k]);
13072 			++mr;
13073 		    }
13074 		} else if (strcmp(rowp[k], "notnull") == 0) {
13075 		    for (mr = 0, m = 1; m <= nrows; m++) {
13076 			int ir;
13077 
13078 			if (cname[0] &&
13079 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
13080 			    continue;
13081 			}
13082 			ir = asize * (roffs + mr);
13083 			if (*rowp[m * ncols + k] != '0') {
13084 			    s->rows[ir + 10] = xstrdup(stringify(SQL_FALSE));
13085 			} else {
13086 			    s->rows[ir + 10] = xstrdup(stringify(SQL_TRUE));
13087 			}
13088 			s->rows[ir + 17] =
13089 			    xstrdup((*rowp[m * ncols + k] != '0') ?
13090 				    "NO" : "YES");
13091 			++mr;
13092 		    }
13093 		} else if (strcmp(rowp[k], "dflt_value") == 0) {
13094 		    for (mr = 0, m = 1; m <= nrows; m++) {
13095 			char *dflt = unquote(rowp[m * ncols + k]);
13096 			int ir;
13097 
13098 			if (cname[0] &&
13099 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
13100 			    continue;
13101 			}
13102 			ir = asize * (roffs + mr);
13103 			s->rows[ir + 12] = xstrdup(dflt ? dflt : "NULL");
13104 			++mr;
13105 		    }
13106 		} else if (strcmp(rowp[k], "type") == 0) {
13107 		    for (mr = 0, m = 1; m <= nrows; m++) {
13108 			char *typename = rowp[m * ncols + k];
13109 			int sqltype, mm, dd, ir;
13110 			char buf[256];
13111 
13112 			if (cname[0] &&
13113 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
13114 			    continue;
13115 			}
13116 			ir = asize * (roffs + mr);
13117 			s->rows[ir + 5] = xstrdup(typename);
13118 			sqltype = mapsqltype(typename, NULL, *s->ov3,
13119 					     s->nowchar[0], s->dobigint);
13120 			getmd(typename, sqltype, &mm, &dd);
13121 #ifdef SQL_LONGVARCHAR
13122 			if (sqltype == SQL_VARCHAR && mm > 255) {
13123 			    sqltype = SQL_LONGVARCHAR;
13124 			}
13125 #endif
13126 #ifdef WINTERFACE
13127 #ifdef SQL_WLONGVARCHAR
13128 			if (sqltype == SQL_WVARCHAR && mm > 255) {
13129 			    sqltype = SQL_WLONGVARCHAR;
13130 			}
13131 #endif
13132 #endif
13133 			if (sqltype == SQL_VARBINARY && mm > 255) {
13134 			    sqltype = SQL_LONGVARBINARY;
13135 			}
13136 			sprintf(buf, "%d", sqltype);
13137 			s->rows[ir + 4] = xstrdup(buf);
13138 			s->rows[ir + 13] = xstrdup(buf);
13139 			sprintf(buf, "%d", mm);
13140 			s->rows[ir + 7] = xstrdup(buf);
13141 			sprintf(buf, "%d", dd);
13142 			s->rows[ir + 6] = xstrdup(buf);
13143 			++mr;
13144 		    }
13145 		}
13146 	    }
13147 	    roffs += nr;
13148 	}
13149 	sqlite3_free_table(rowp);
13150     }
13151     sqlite3_free_table(trows);
13152     return SQL_SUCCESS;
13153 }
13154 
13155 #ifndef WINTERFACE
13156 /**
13157  * Retrieve column information on table.
13158  * @param stmt statement handle
13159  * @param cat catalog name/pattern or NULL
13160  * @param catLen length of catalog name/pattern or SQL_NTS
13161  * @param schema schema name/pattern or NULL
13162  * @param schemaLen length of schema name/pattern or SQL_NTS
13163  * @param table table name/pattern or NULL
13164  * @param tableLen length of table name/pattern or SQL_NTS
13165  * @param col column name/pattern or NULL
13166  * @param colLen length of column name/pattern or SQL_NTS
13167  * @result ODBC error code
13168  */
13169 
13170 SQLRETURN SQL_API
SQLColumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)13171 SQLColumns(SQLHSTMT stmt,
13172 	   SQLCHAR *cat, SQLSMALLINT catLen,
13173 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
13174 	   SQLCHAR *table, SQLSMALLINT tableLen,
13175 	   SQLCHAR *col, SQLSMALLINT colLen)
13176 {
13177 #if defined(_WIN32) || defined(_WIN64)
13178     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
13179 #endif
13180     SQLRETURN ret;
13181 
13182     HSTMT_LOCK(stmt);
13183 #if defined(_WIN32) || defined(_WIN64)
13184     if (!((STMT *) stmt)->oemcp[0]) {
13185 	ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
13186 			 table, tableLen, col, colLen);
13187 	goto done2;
13188     }
13189     if (cat) {
13190 	c = wmb_to_utf_c((char *) cat, catLen);
13191 	if (!c) {
13192 	    ret = nomem((STMT *) stmt);
13193 	    goto done;
13194 	}
13195     }
13196     if (schema) {
13197 	s = wmb_to_utf_c((char *) schema, schemaLen);
13198 	if (!s) {
13199 	    ret = nomem((STMT *) stmt);
13200 	    goto done;
13201 	}
13202     }
13203     if (table) {
13204 	t = wmb_to_utf_c((char *) table, tableLen);
13205 	if (!t) {
13206 	    ret = nomem((STMT *) stmt);
13207 	    goto done;
13208 	}
13209     }
13210     if (col) {
13211 	k = wmb_to_utf_c((char *) col, colLen);
13212 	if (!k) {
13213 	    ret = nomem((STMT *) stmt);
13214 	    goto done;
13215 	}
13216     }
13217     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
13218 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
13219 #else
13220     ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
13221 		     table, tableLen, col, colLen);
13222 #endif
13223 #if defined(_WIN32) || defined(_WIN64)
13224 done:
13225     uc_free(k);
13226     uc_free(t);
13227     uc_free(s);
13228     uc_free(c);
13229 done2:
13230     ;
13231 #endif
13232     HSTMT_UNLOCK(stmt);
13233     return ret;
13234 }
13235 #endif
13236 
13237 #ifdef WINTERFACE
13238 /**
13239  * Retrieve column information on table (UNICODE version).
13240  * @param stmt statement handle
13241  * @param cat catalog name/pattern or NULL
13242  * @param catLen length of catalog name/pattern or SQL_NTS
13243  * @param schema schema name/pattern or NULL
13244  * @param schemaLen length of schema name/pattern or SQL_NTS
13245  * @param table table name/pattern or NULL
13246  * @param tableLen length of table name/pattern or SQL_NTS
13247  * @param col column name/pattern or NULL
13248  * @param colLen length of column name/pattern or SQL_NTS
13249  * @result ODBC error code
13250  */
13251 
13252 SQLRETURN SQL_API
SQLColumnsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * col,SQLSMALLINT colLen)13253 SQLColumnsW(SQLHSTMT stmt,
13254 	    SQLWCHAR *cat, SQLSMALLINT catLen,
13255 	    SQLWCHAR *schema, SQLSMALLINT schemaLen,
13256 	    SQLWCHAR *table, SQLSMALLINT tableLen,
13257 	    SQLWCHAR *col, SQLSMALLINT colLen)
13258 {
13259     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
13260     SQLRETURN ret;
13261 
13262     HSTMT_LOCK(stmt);
13263     if (cat) {
13264 	c = uc_to_utf_c(cat, catLen);
13265 	if (!c) {
13266 	    ret = nomem((STMT *) stmt);
13267 	    goto done;
13268 	}
13269     }
13270     if (schema) {
13271 	s = uc_to_utf_c(schema, schemaLen);
13272 	if (!s) {
13273 	    ret = nomem((STMT *) stmt);
13274 	    goto done;
13275 	}
13276     }
13277     if (table) {
13278 	t = uc_to_utf_c(table, tableLen);
13279 	if (!t) {
13280 	    ret = nomem((STMT *) stmt);
13281 	    goto done;
13282 	}
13283     }
13284     if (col) {
13285 	k = uc_to_utf_c(col, colLen);
13286 	if (!k) {
13287 	    ret = nomem((STMT *) stmt);
13288 	    goto done;
13289 	}
13290     }
13291     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
13292 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
13293 done:
13294     uc_free(k);
13295     uc_free(t);
13296     uc_free(s);
13297     uc_free(c);
13298     HSTMT_UNLOCK(stmt);
13299     return ret;
13300 
13301 }
13302 #endif
13303 
13304 /**
13305  * Columns for result set of SQLGetTypeInfo().
13306  */
13307 
13308 static COL typeSpec2[] = {
13309     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
13310     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
13311     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 9 },
13312     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
13313     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
13314     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
13315     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
13316     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
13317     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
13318     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
13319     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
13320     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
13321     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
13322     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
13323     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
13324 };
13325 
13326 static COL typeSpec3[] = {
13327     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
13328     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
13329     { "SYSTEM", "TYPE", "COLUMN_SIZE", SQL_INTEGER, 9 },
13330     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
13331     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
13332     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
13333     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
13334     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
13335     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
13336     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
13337     { "SYSTEM", "TYPE", "FIXED_PREC_SCALE", SQL_SMALLINT, 2 },
13338     { "SYSTEM", "TYPE", "AUTO_UNIQUE_VALUE", SQL_SMALLINT, 2 },
13339     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
13340     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
13341     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 },
13342     { "SYSTEM", "TYPE", "SQL_DATA_TYPE", SQL_SMALLINT, 2 },
13343     { "SYSTEM", "TYPE", "SQL_DATETIME_SUB", SQL_SMALLINT, 2 },
13344     { "SYSTEM", "TYPE", "NUM_PREC_RADIX", SQL_INTEGER, 4 },
13345     { "SYSTEM", "TYPE", "INTERVAL_PRECISION", SQL_SMALLINT, 2 }
13346 };
13347 
13348 /**
13349  * Internal function to build up data type information as row in result set.
13350  * @param s statement pointer
13351  * @param row row number
13352  * @param asize number of items in a row
13353  * @param typename name of type
13354  * @param type integer SQL type
13355  * @param tind type index
13356  */
13357 
13358 static void
mktypeinfo(STMT * s,int row,int asize,char * typename,int type,int tind)13359 mktypeinfo(STMT *s, int row, int asize, char *typename, int type, int tind)
13360 {
13361     int offs = row * asize;
13362     char *tcode, *crpar = NULL, *quote = NULL, *sign = stringify(SQL_FALSE);
13363     static char tcodes[32 * 32];
13364 
13365     if (tind <= 0) {
13366 	tind = row;
13367     }
13368     tcode = tcodes + tind * 32;
13369     sprintf(tcode, "%d", type);
13370     s->rows[offs + 0] = typename;
13371     s->rows[offs + 1] = tcode;
13372     if (asize >= 17) {
13373 	s->rows[offs + 15] = tcode;
13374 	s->rows[offs + 16] = "0";
13375     }
13376     switch (type) {
13377     default:
13378 #ifdef SQL_LONGVARCHAR
13379     case SQL_LONGVARCHAR:
13380 #ifdef WINTERFACE
13381     case SQL_WLONGVARCHAR:
13382 #endif
13383 	crpar = "length";
13384 	quote = "'";
13385 	sign = NULL;
13386 	s->rows[offs + 2] = "65536";
13387 	break;
13388 #endif
13389 #ifdef SQL_BIT
13390     case SQL_BIT:
13391 	sign = NULL;
13392 	s->rows[offs + 2] = "1";
13393 	break;
13394 #endif
13395     case SQL_CHAR:
13396     case SQL_VARCHAR:
13397 #ifdef WINTERFACE
13398     case SQL_WCHAR:
13399     case SQL_WVARCHAR:
13400 #endif
13401 	s->rows[offs + 2] = "255";
13402 	crpar = "length";
13403 	quote = "'";
13404 	sign = NULL;
13405 	break;
13406     case SQL_TINYINT:
13407 	s->rows[offs + 2] = "3";
13408 	break;
13409     case SQL_SMALLINT:
13410 	s->rows[offs + 2] = "5";
13411 	break;
13412     case SQL_INTEGER:
13413 	s->rows[offs + 2] = "9";
13414 	break;
13415 #ifdef SQL_BIGINT
13416     case SQL_BIGINT:
13417 	s->rows[offs + 2] = "19";
13418 	break;
13419 #endif
13420     case SQL_FLOAT:
13421 	s->rows[offs + 2] = "7";
13422 	break;
13423     case SQL_DOUBLE:
13424 	s->rows[offs + 2] = "15";
13425 	break;
13426 #ifdef SQL_TYPE_DATE
13427     case SQL_TYPE_DATE:
13428 #endif
13429     case SQL_DATE:
13430 	s->rows[offs + 2] = "10";
13431 	quote = "'";
13432 	sign = NULL;
13433 	break;
13434 #ifdef SQL_TYPE_TIME
13435     case SQL_TYPE_TIME:
13436 #endif
13437     case SQL_TIME:
13438 	s->rows[offs + 2] = "8";
13439 	quote = "'";
13440 	sign = NULL;
13441 	break;
13442 #ifdef SQL_TYPE_TIMESTAMP
13443     case SQL_TYPE_TIMESTAMP:
13444 #endif
13445     case SQL_TIMESTAMP:
13446 	s->rows[offs + 2] = "32";
13447 	quote = "'";
13448 	sign = NULL;
13449 	break;
13450     case SQL_VARBINARY:
13451 	sign = NULL;
13452 	s->rows[offs + 2] = "255";
13453 	break;
13454     case SQL_LONGVARBINARY:
13455 	sign = NULL;
13456 	s->rows[offs + 2] = "65536";
13457 	break;
13458     }
13459     s->rows[offs + 3] = s->rows[offs + 4] = quote;
13460     s->rows[offs + 5] = crpar;
13461     s->rows[offs + 6] = stringify(SQL_NULLABLE);
13462     s->rows[offs + 7] = stringify(SQL_FALSE);
13463     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
13464     s->rows[offs + 9] = sign;
13465     s->rows[offs + 10] = stringify(SQL_FALSE);
13466     s->rows[offs + 11] = stringify(SQL_FALSE);
13467     s->rows[offs + 12] = typename;
13468     switch (type) {
13469     case SQL_DATE:
13470     case SQL_TIME:
13471 	s->rows[offs + 13] = "0";
13472 	s->rows[offs + 14] = "0";
13473 	break;
13474 #ifdef SQL_TYPE_TIMESTAMP
13475     case SQL_TYPE_TIMESTAMP:
13476 #endif
13477     case SQL_TIMESTAMP:
13478 	s->rows[offs + 13] = "0";
13479 	s->rows[offs + 14] = "3";
13480 	break;
13481     default:
13482 	s->rows[offs + 13] = NULL;
13483 	s->rows[offs + 14] = NULL;
13484 	break;
13485     }
13486 }
13487 
13488 /**
13489  * Helper function to sort type information.
13490  * Callback for qsort().
13491  * @param a first item to compare
13492  * @param b second item to compare
13493  * @result ==0, <0, >0 according to data type number
13494  */
13495 
13496 static int
typeinfosort(const void * a,const void * b)13497 typeinfosort(const void *a, const void *b)
13498 {
13499     char **pa = (char **) a;
13500     char **pb = (char **) b;
13501     int na, nb;
13502 
13503     na = strtol(pa[1], NULL, 0);
13504     nb = strtol(pb[1], NULL, 0);
13505     return na - nb;
13506 }
13507 
13508 /**
13509  * Internal return data type information.
13510  * @param stmt statement handle
13511  * @param sqltype which type to retrieve
13512  * @result ODBC error code
13513  */
13514 
13515 static SQLRETURN
drvgettypeinfo(SQLHSTMT stmt,SQLSMALLINT sqltype)13516 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
13517 {
13518     SQLRETURN ret;
13519     STMT *s;
13520     DBC *d;
13521     int asize;
13522 
13523     ret = mkresultset(stmt, typeSpec2, array_size(typeSpec2),
13524 		      typeSpec3, array_size(typeSpec3), &asize);
13525     if (ret != SQL_SUCCESS) {
13526 	return ret;
13527     }
13528     s = (STMT *) stmt;
13529     d = (DBC *) s->dbc;
13530 #ifdef SQL_LONGVARCHAR
13531     s->nrows = (sqltype == SQL_ALL_TYPES) ? 13 : 1;
13532 #else
13533     s->nrows = (sqltype == SQL_ALL_TYPES) ? 12 : 1;
13534 #endif
13535     if (sqltype == SQL_ALL_TYPES) {
13536 #ifdef WINTERFACE
13537 	s->nrows += 2;
13538 #ifdef SQL_WLONGVARCHAR
13539 	s->nrows += 2;
13540 #endif
13541 #endif
13542     }
13543     if (sqltype == SQL_ALL_TYPES) {
13544 	s->nrows += 2;
13545 #ifdef SQL_BIT
13546 	s->nrows += 1;
13547 #endif
13548 #ifdef SQL_BIGINT
13549 	s->nrows += 1;
13550 #endif
13551     }
13552     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1) * asize);
13553     if (!s->rows) {
13554 	s->nrows = 0;
13555 	return nomem(s);
13556     }
13557 #ifdef MEMORY_DEBUG
13558     s->rowfree = xfree__;
13559 #else
13560     s->rowfree = sqlite3_free;
13561 #endif
13562     memset(s->rows, 0, sizeof (char *) * (s->nrows + 1) * asize);
13563     if (sqltype == SQL_ALL_TYPES) {
13564 	int cc = 1;
13565 
13566 	mktypeinfo(s, cc++, asize, "varchar", SQL_VARCHAR, 0);
13567 	mktypeinfo(s, cc++, asize, "tinyint", SQL_TINYINT, 0);
13568 	mktypeinfo(s, cc++, asize, "smallint", SQL_SMALLINT, 0);
13569 	mktypeinfo(s, cc++, asize, "integer", SQL_INTEGER, 0);
13570 	mktypeinfo(s, cc++, asize, "float", SQL_FLOAT, 0);
13571 	mktypeinfo(s, cc++, asize, "double", SQL_DOUBLE, 0);
13572 #ifdef SQL_TYPE_DATE
13573 	mktypeinfo(s, cc++, asize, "date",
13574 		   (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
13575 #else
13576 	mktypeinfo(s, cc++, asize, "date", SQL_DATE, 0);
13577 #endif
13578 #ifdef SQL_TYPE_TIME
13579 	mktypeinfo(s, cc++, asize, "time",
13580 		   (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
13581 #else
13582 	mktypeinfo(s, cc++, asize, "time", SQL_TIME, 0);
13583 #endif
13584 #ifdef SQL_TYPE_TIMESTAMP
13585 	mktypeinfo(s, cc++, asize, "timestamp",
13586 		   (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
13587 #else
13588 	mktypeinfo(s, cc++, asize, "timestamp", SQL_TIMESTAMP, 0);
13589 #endif
13590 	mktypeinfo(s, cc++, asize, "char", SQL_CHAR, 0);
13591 	mktypeinfo(s, cc++, asize, "numeric", SQL_DOUBLE, 0);
13592 #ifdef SQL_LONGVARCHAR
13593 	mktypeinfo(s, cc++, asize, "text", SQL_LONGVARCHAR, 0);
13594 	mktypeinfo(s, cc++, asize, "longvarchar", SQL_LONGVARCHAR, 0);
13595 #else
13596 	mktypeinfo(s, cc++, asize, "text", SQL_VARCHAR, 0);
13597 #endif
13598 	mktypeinfo(s, cc++, asize, "varbinary", SQL_VARBINARY, 0);
13599 	mktypeinfo(s, cc++, asize, "longvarbinary", SQL_LONGVARBINARY, 0);
13600 #ifdef SQL_BIT
13601 	mktypeinfo(s, cc++, asize, "bit", SQL_BIT, 0);
13602 #endif
13603 #ifdef SQL_BIGINT
13604 	mktypeinfo(s, cc++, asize, "bigint", SQL_BIGINT, 0);
13605 #endif
13606 #ifdef WINTERFACE
13607 	mktypeinfo(s, cc++, asize, "wvarchar", SQL_WVARCHAR, 0);
13608 	mktypeinfo(s, cc++, asize, "wchar", SQL_WCHAR, 0);
13609 #ifdef SQL_WLONGVARCHAR
13610 	mktypeinfo(s, cc++, asize, "wtext", SQL_WLONGVARCHAR, 0);
13611 	mktypeinfo(s, cc++, asize, "longwvarchar", SQL_WLONGVARCHAR, 0);
13612 #endif
13613 #endif
13614 	qsort(s->rows + asize, s->nrows, sizeof (char *) * asize,
13615 	      typeinfosort);
13616     } else {
13617 	switch (sqltype) {
13618 	case SQL_CHAR:
13619 	    mktypeinfo(s, 1, asize, "char", SQL_CHAR, 10);
13620 	    break;
13621 	case SQL_VARCHAR:
13622 	    mktypeinfo(s, 1, asize, "varchar", SQL_VARCHAR, 1);
13623 	    break;
13624 	case SQL_TINYINT:
13625 	    mktypeinfo(s, 1, asize, "tinyint", SQL_TINYINT, 2);
13626 	    break;
13627 	case SQL_SMALLINT:
13628 	    mktypeinfo(s, 1, asize, "smallint", SQL_SMALLINT, 3);
13629 	    break;
13630 	case SQL_INTEGER:
13631 	    mktypeinfo(s, 1, asize, "integer", SQL_INTEGER, 4);
13632 	    break;
13633 	case SQL_FLOAT:
13634 	    mktypeinfo(s, 1, asize, "float", SQL_FLOAT, 5);
13635 	    break;
13636 	case SQL_DOUBLE:
13637 	    mktypeinfo(s, 1, asize, "double", SQL_DOUBLE, 6);
13638 	    break;
13639 #ifdef SQL_TYPE_DATE
13640 	case SQL_TYPE_DATE:
13641 	    mktypeinfo(s, 1, asize, "date", SQL_TYPE_DATE, 25);
13642 	    break;
13643 #endif
13644 	case SQL_DATE:
13645 	    mktypeinfo(s, 1, asize, "date", SQL_DATE, 7);
13646 	    break;
13647 #ifdef SQL_TYPE_TIME
13648 	case SQL_TYPE_TIME:
13649 	    mktypeinfo(s, 1, asize, "time", SQL_TYPE_TIME, 26);
13650 	    break;
13651 #endif
13652 	case SQL_TIME:
13653 	    mktypeinfo(s, 1, asize, "time", SQL_TIME, 8);
13654 	    break;
13655 #ifdef SQL_TYPE_TIMESTAMP
13656 	case SQL_TYPE_TIMESTAMP:
13657 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TYPE_TIMESTAMP, 27);
13658 	    break;
13659 #endif
13660 	case SQL_TIMESTAMP:
13661 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TIMESTAMP, 9);
13662 	    break;
13663 #ifdef SQL_LONGVARCHAR
13664 	case SQL_LONGVARCHAR:
13665 	    mktypeinfo(s, 1, asize, "longvarchar", SQL_LONGVARCHAR, 12);
13666 	    break;
13667 #endif
13668 	case SQL_VARBINARY:
13669 	    mktypeinfo(s, 1, asize, "varbinary", SQL_VARBINARY, 30);
13670 	    break;
13671 	case SQL_LONGVARBINARY:
13672 	    mktypeinfo(s, 1, asize, "longvarbinary", SQL_LONGVARBINARY, 31);
13673 	    break;
13674 #ifdef SQL_BIT
13675 	case SQL_BIT:
13676 	    mktypeinfo(s, 1, asize, "bit", SQL_BIT, 29);
13677 	    break;
13678 #endif
13679 #ifdef SQL_BIGINT
13680 	case SQL_BIGINT:
13681 	    mktypeinfo(s, 1, asize, "bigint", SQL_BIGINT, 28);
13682 	    break;
13683 #endif
13684 #ifdef WINTERFACE
13685 #ifdef SQL_WCHAR
13686 	case SQL_WCHAR:
13687 	    mktypeinfo(s, 1, asize, "wchar", SQL_WCHAR, 18);
13688 	    break;
13689 #endif
13690 #ifdef SQL_WVARCHAR
13691 	case SQL_WVARCHAR:
13692 	    mktypeinfo(s, 1, asize, "wvarchar", SQL_WVARCHAR, 19);
13693 	    break;
13694 #endif
13695 #ifdef SQL_WLONGVARCHAR
13696 	case SQL_WLONGVARCHAR:
13697 	    mktypeinfo(s, 1, asize, "longwvarchar", SQL_WLONGVARCHAR, 20);
13698 	    break;
13699 #endif
13700 #endif
13701 	default:
13702 	    s->nrows = 0;
13703 	}
13704     }
13705     return SQL_SUCCESS;
13706 }
13707 
13708 #ifndef WINTERFACE
13709 /**
13710  * Return data type information.
13711  * @param stmt statement handle
13712  * @param sqltype which type to retrieve
13713  * @result ODBC error code
13714  */
13715 
13716 SQLRETURN SQL_API
SQLGetTypeInfo(SQLHSTMT stmt,SQLSMALLINT sqltype)13717 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
13718 {
13719     SQLRETURN ret;
13720 
13721     HSTMT_LOCK(stmt);
13722     ret = drvgettypeinfo(stmt, sqltype);
13723     HSTMT_UNLOCK(stmt);
13724     return ret;
13725 }
13726 #endif
13727 
13728 #ifdef WINTERFACE
13729 /**
13730  * Return data type information (UNICODE version).
13731  * @param stmt statement handle
13732  * @param sqltype which type to retrieve
13733  * @result ODBC error code
13734  */
13735 
13736 SQLRETURN SQL_API
SQLGetTypeInfoW(SQLHSTMT stmt,SQLSMALLINT sqltype)13737 SQLGetTypeInfoW(SQLHSTMT stmt, SQLSMALLINT sqltype)
13738 {
13739     SQLRETURN ret;
13740 
13741     HSTMT_LOCK(stmt);
13742     ret = drvgettypeinfo(stmt, sqltype);
13743     HSTMT_UNLOCK(stmt);
13744     return ret;
13745 }
13746 #endif
13747 
13748 /**
13749  * Columns for result set of SQLStatistics().
13750  */
13751 
13752 static COL statSpec2[] = {
13753     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
13754     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
13755     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
13756     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
13757     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
13758     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
13759     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
13760     { "SYSTEM", "STATISTICS", "SEQ_IN_INDEX", SQL_SMALLINT, 50 },
13761     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
13762     { "SYSTEM", "STATISTICS", "COLLATION", SCOL_CHAR, 1 },
13763     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
13764     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
13765     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
13766 };
13767 
13768 static COL statSpec3[] = {
13769     { "SYSTEM", "STATISTICS", "TABLE_CAT", SCOL_VARCHAR, 50 },
13770     { "SYSTEM", "STATISTICS", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
13771     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
13772     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
13773     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
13774     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
13775     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
13776     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
13777     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
13778     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
13779     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
13780     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
13781     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
13782 };
13783 
13784 /**
13785  * Internal return statistic information on table indices.
13786  * @param stmt statement handle
13787  * @param cat catalog name/pattern or NULL
13788  * @param catLen length of catalog name/pattern or SQL_NTS
13789  * @param schema schema name/pattern or NULL
13790  * @param schemaLen length of schema name/pattern or SQL_NTS
13791  * @param table table name/pattern or NULL
13792  * @param tableLen length of table name/pattern or SQL_NTS
13793  * @param itype type of index information
13794  * @param resv reserved
13795  * @result ODBC error code
13796  */
13797 
13798 static SQLRETURN
drvstatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)13799 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
13800 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
13801 	      SQLCHAR *table, SQLSMALLINT tableLen,
13802 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
13803 {
13804     SQLRETURN sret;
13805     STMT *s;
13806     DBC *d;
13807     int i, asize, ret, nrows, ncols, offs, namec, uniquec, addipk = 0;
13808     PTRDIFF_T size;
13809     char **rowp, *errp = NULL, *sql, tname[512];
13810 
13811     sret = mkresultset(stmt, statSpec2, array_size(statSpec2),
13812 		       statSpec3, array_size(statSpec3), &asize);
13813     if (sret != SQL_SUCCESS) {
13814 	return sret;
13815     }
13816     s = (STMT *) stmt;
13817     d = (DBC *) s->dbc;
13818     if (!table || table[0] == '\0' || table[0] == '%') {
13819 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
13820 	return SQL_ERROR;
13821     }
13822     if (tableLen == SQL_NTS) {
13823 	size = sizeof (tname) - 1;
13824     } else {
13825 	size = min(sizeof (tname) - 1, tableLen);
13826     }
13827     strncpy(tname, (char *) table, size);
13828     tname[size] = '\0';
13829     unescpat(tname);
13830     sret = starttran(s);
13831     if (sret != SQL_SUCCESS) {
13832 	return sret;
13833     }
13834     /*
13835      * Try integer primary key (autoincrement) first
13836      */
13837     if (itype == SQL_INDEX_UNIQUE || itype == SQL_INDEX_ALL) {
13838 	rowp = 0;
13839 	ret = SQLITE_ERROR;
13840 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
13841 	if (sql) {
13842 	    dbtraceapi(d, "sqlite3_get_table", sql);
13843 	    ret = sqlite3_get_table(d->sqlite, sql, &rowp,
13844 				    &nrows, &ncols, NULL);
13845 	    sqlite3_free(sql);
13846 	}
13847 	if (ret == SQLITE_OK) {
13848 	    int colid, typec, npk = 0;
13849 
13850 	    namec = findcol(rowp, ncols, "name");
13851 	    uniquec = findcol(rowp, ncols, "pk");
13852 	    typec = findcol(rowp, ncols, "type");
13853 	    colid = findcol(rowp, ncols, "cid");
13854 	    if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
13855 		goto noipk;
13856 	    }
13857 	    for (i = 1; i <= nrows; i++) {
13858 		if (*rowp[i * ncols + uniquec] != '0' &&
13859 		    strlen(rowp[i * ncols + typec]) == 7 &&
13860 		    strncasecmp(rowp[i * ncols + typec], "integer", 7)
13861 		    == 0) {
13862 		    npk++;
13863 		}
13864 	    }
13865 	    if (npk == 1) {
13866 		addipk = 1;
13867 	    }
13868 	}
13869 noipk:
13870 	sqlite3_free_table(rowp);
13871     }
13872     sql = sqlite3_mprintf("PRAGMA index_list(%Q)", tname);
13873     if (!sql) {
13874 	return nomem(s);
13875     }
13876     dbtraceapi(d, "sqlite3_get_table", sql);
13877     ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
13878     sqlite3_free(sql);
13879     if (ret != SQLITE_OK) {
13880 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
13881 		errp ? errp : "unknown error", ret);
13882 	if (errp) {
13883 	    sqlite3_free(errp);
13884 	    errp = NULL;
13885 	}
13886 	return SQL_ERROR;
13887     }
13888     if (errp) {
13889 	sqlite3_free(errp);
13890 	errp = NULL;
13891     }
13892     size = 0;
13893     namec = findcol(rowp, ncols, "name");
13894     uniquec = findcol(rowp, ncols, "unique");
13895     if (namec < 0 || uniquec < 0) {
13896 	goto nodata;
13897     }
13898     for (i = 1; i <= nrows; i++) {
13899 	int nnrows, nncols;
13900 	char **rowpp;
13901 	int isuniq;
13902 
13903 	isuniq = *rowp[i * ncols + uniquec] != '0';
13904 	if (isuniq || itype == SQL_INDEX_ALL) {
13905 	    ret = SQLITE_ERROR;
13906 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
13907 				  rowp[i * ncols + namec]);
13908 	    if (sql) {
13909 		dbtraceapi(d, "sqlite3_get_table", sql);
13910 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
13911 					&nnrows, &nncols, NULL);
13912 		sqlite3_free(sql);
13913 	    }
13914 	    if (ret == SQLITE_OK) {
13915 		size += nnrows;
13916 		sqlite3_free_table(rowpp);
13917 	    }
13918 	}
13919     }
13920 nodata:
13921     if (addipk) {
13922 	size++;
13923     }
13924     if (size == 0) {
13925 	sqlite3_free_table(rowp);
13926 	return SQL_SUCCESS;
13927     }
13928     s->nrows = size;
13929     size = (size + 1) * asize;
13930     s->rows = xmalloc((size + 1) * sizeof (char *));
13931     if (!s->rows) {
13932 	s->nrows = 0;
13933 	return nomem(s);
13934     }
13935     s->rows[0] = (char *) size;
13936     s->rows += 1;
13937     memset(s->rows, 0, sizeof (char *) * size);
13938     s->rowfree = freerows;
13939     offs = 0;
13940     if (addipk) {
13941 	char **rowpp = 0;
13942 	int nrows2, ncols2;
13943 
13944 	sql = sqlite3_mprintf("PRAGMA table_info(%Q)", tname);
13945 	if (sql) {
13946 	    dbtraceapi(d, "sqlite3_get_table", sql);
13947 	    ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
13948 				    &nrows2, &ncols2, NULL);
13949 	    sqlite3_free(sql);
13950 	}
13951 	if (ret == SQLITE_OK) {
13952 	    int colid, typec, roffs, namecc, uniquecc;
13953 
13954 	    namecc = findcol(rowpp, ncols2, "name");
13955 	    uniquecc = findcol(rowpp, ncols2, "pk");
13956 	    typec = findcol(rowpp, ncols2, "type");
13957 	    colid = findcol(rowpp, ncols2, "cid");
13958 	    if (namecc < 0 || uniquecc < 0 || typec < 0 || colid < 0) {
13959 		addipk = 0;
13960 		s->nrows--;
13961 		goto nodata2;
13962 	    }
13963 	    for (i = 1; i <= nrows2; i++) {
13964 		if (*rowpp[i * ncols2 + uniquecc] != '0' &&
13965 		    strlen(rowpp[i * ncols2 + typec]) == 7 &&
13966 		    strncasecmp(rowpp[i * ncols2 + typec], "integer", 7)
13967 		    == 0) {
13968 		    break;
13969 		}
13970 	    }
13971 	    if (i > nrows2) {
13972 		addipk = 0;
13973 		s->nrows--;
13974 		goto nodata2;
13975 	    }
13976 	    roffs = s->ncols;
13977 	    s->rows[roffs + 0] = xstrdup("");
13978 #if defined(_WIN32) || defined(_WIN64)
13979 	    s->rows[roffs + 1] = xstrdup(d->xcelqrx ? "main" : "");
13980 #else
13981 	    s->rows[roffs + 1] = xstrdup("");
13982 #endif
13983 	    s->rows[roffs + 2] = xstrdup(tname);
13984 	    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
13985 	    s->rows[roffs + 5] = xstrdup("sqlite_autoindex_0");
13986 	    s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
13987 	    s->rows[roffs + 7] = xstrdup("1");
13988 	    s->rows[roffs + 8] = xstrdup(rowpp[i * ncols2 + namecc]);
13989 	    s->rows[roffs + 9] = xstrdup("A");
13990 	}
13991 nodata2:
13992 	sqlite3_free_table(rowpp);
13993     }
13994     for (i = 1; i <= nrows; i++) {
13995 	int nnrows, nncols;
13996 	char **rowpp = 0;
13997 
13998 	if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
13999 	    int k;
14000 
14001 	    ret = SQLITE_ERROR;
14002 	    sql = sqlite3_mprintf("PRAGMA index_info(%Q)",
14003 				  rowp[i * ncols + namec]);
14004 	    if (sql) {
14005 		dbtraceapi(d, "sqlite3_get_table", sql);
14006 		ret = sqlite3_get_table(d->sqlite, sql, &rowpp,
14007 					&nnrows, &nncols, NULL);
14008 		sqlite3_free(sql);
14009 	    }
14010 	    if (ret != SQLITE_OK) {
14011 		continue;
14012 	    }
14013 	    for (k = 0; nnrows && k < nncols; k++) {
14014 		if (strcmp(rowpp[k], "name") == 0) {
14015 		    int m;
14016 
14017 		    for (m = 1; m <= nnrows; m++) {
14018 			int roffs = (offs + addipk + m) * s->ncols;
14019 			int isuniq;
14020 
14021 			isuniq = *rowp[i * ncols + uniquec] != '0';
14022 			s->rows[roffs + 0] = xstrdup("");
14023 			s->rows[roffs + 1] = xstrdup("");
14024 			s->rows[roffs + 2] = xstrdup(tname);
14025 			if (isuniq) {
14026 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
14027 			} else {
14028 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
14029 			}
14030 			s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
14031 			s->rows[roffs + 6] =
14032 			    xstrdup(stringify(SQL_INDEX_OTHER));
14033 			s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
14034 			s->rows[roffs + 9] = xstrdup("A");
14035 		    }
14036 		} else if (strcmp(rowpp[k], "seqno") == 0) {
14037 		    int m;
14038 
14039 		    for (m = 1; m <= nnrows; m++) {
14040 			int roffs = (offs + addipk + m) * s->ncols;
14041 			int pos = m - 1;
14042 			char buf[32];
14043 
14044 			sscanf(rowpp[m * nncols + k], "%d", &pos);
14045 			sprintf(buf, "%d", pos + 1);
14046 			s->rows[roffs + 7] = xstrdup(buf);
14047 		    }
14048 		}
14049 	    }
14050 	    offs += nnrows;
14051 	    sqlite3_free_table(rowpp);
14052 	}
14053     }
14054     sqlite3_free_table(rowp);
14055     return SQL_SUCCESS;
14056 }
14057 
14058 #ifndef WINTERFACE
14059 /**
14060  * Return statistic information on table indices.
14061  * @param stmt statement handle
14062  * @param cat catalog name/pattern or NULL
14063  * @param catLen length of catalog name/pattern or SQL_NTS
14064  * @param schema schema name/pattern or NULL
14065  * @param schemaLen length of schema name/pattern or SQL_NTS
14066  * @param table table name/pattern or NULL
14067  * @param tableLen length of table name/pattern or SQL_NTS
14068  * @param itype type of index information
14069  * @param resv reserved
14070  * @result ODBC error code
14071  */
14072 
14073 SQLRETURN SQL_API
SQLStatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)14074 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
14075 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
14076 	      SQLCHAR *table, SQLSMALLINT tableLen,
14077 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
14078 {
14079 #if defined(_WIN32) || defined(_WIN64)
14080     char *c = NULL, *s = NULL, *t = NULL;
14081 #endif
14082     SQLRETURN ret;
14083 
14084     HSTMT_LOCK(stmt);
14085 #if defined(_WIN32) || defined(_WIN64)
14086     if (!((STMT *) stmt)->oemcp[0]) {
14087 	ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
14088 			    table, tableLen, itype, resv);
14089 	goto done2;
14090     }
14091     if (cat) {
14092 	c = wmb_to_utf_c((char *) cat, catLen);
14093 	if (!c) {
14094 	    ret = nomem((STMT *) stmt);
14095 	    goto done;
14096 	}
14097     }
14098     if (schema) {
14099 	s = wmb_to_utf_c((char *) schema, schemaLen);
14100 	if (!s) {
14101 	    ret = nomem((STMT *) stmt);
14102 	    goto done;
14103 	}
14104     }
14105     if (table) {
14106 	t = wmb_to_utf_c((char *) table, tableLen);
14107 	if (!t) {
14108 	    ret = nomem((STMT *) stmt);
14109 	    goto done;
14110 	}
14111     }
14112     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14113 			(SQLCHAR *) t, SQL_NTS, itype, resv);
14114 #else
14115     ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
14116 			table, tableLen, itype, resv);
14117 #endif
14118 #if defined(_WIN32) || defined(_WIN64)
14119 done:
14120     uc_free(t);
14121     uc_free(s);
14122     uc_free(c);
14123 done2:
14124     ;
14125 #endif
14126     HSTMT_UNLOCK(stmt);
14127     return ret;
14128 }
14129 #endif
14130 
14131 #ifdef WINTERFACE
14132 /**
14133  * Return statistic information on table indices (UNICODE version).
14134  * @param stmt statement handle
14135  * @param cat catalog name/pattern or NULL
14136  * @param catLen length of catalog name/pattern or SQL_NTS
14137  * @param schema schema name/pattern or NULL
14138  * @param schemaLen length of schema name/pattern or SQL_NTS
14139  * @param table table name/pattern or NULL
14140  * @param tableLen length of table name/pattern or SQL_NTS
14141  * @param itype type of index information
14142  * @param resv reserved
14143  * @result ODBC error code
14144  */
14145 
14146 SQLRETURN SQL_API
SQLStatisticsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)14147 SQLStatisticsW(SQLHSTMT stmt, SQLWCHAR *cat, SQLSMALLINT catLen,
14148 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
14149 	       SQLWCHAR *table, SQLSMALLINT tableLen,
14150 	       SQLUSMALLINT itype, SQLUSMALLINT resv)
14151 {
14152     char *c = NULL, *s = NULL, *t = NULL;
14153     SQLRETURN ret;
14154 
14155     HSTMT_LOCK(stmt);
14156     if (cat) {
14157 	c = uc_to_utf_c(cat, catLen);
14158 	if (!c) {
14159 	    ret = nomem((STMT *) stmt);
14160 	    goto done;
14161 	}
14162     }
14163     if (schema) {
14164 	s = uc_to_utf_c(schema, schemaLen);
14165 	if (!s) {
14166 	    ret = nomem((STMT *) stmt);
14167 	    goto done;
14168 	}
14169     }
14170     if (table) {
14171 	t = uc_to_utf_c(table, tableLen);
14172 	if (!t) {
14173 	    ret = nomem((STMT *) stmt);
14174 	    goto done;
14175 	}
14176     }
14177     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14178 			(SQLCHAR *) t, SQL_NTS, itype, resv);
14179 done:
14180     uc_free(t);
14181     uc_free(s);
14182     uc_free(c);
14183     HSTMT_UNLOCK(stmt);
14184     return ret;
14185 }
14186 #endif
14187 
14188 /**
14189  * Retrieve row data after fetch.
14190  * @param stmt statement handle
14191  * @param col column number, starting at 1
14192  * @param type output type
14193  * @param val output buffer
14194  * @param len length of output buffer
14195  * @param lenp output length
14196  * @result ODBC error code
14197  */
14198 
14199 SQLRETURN SQL_API
SQLGetData(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN len,SQLLEN * lenp)14200 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
14201 	   SQLPOINTER val, SQLLEN len, SQLLEN *lenp)
14202 {
14203     STMT *s;
14204     SQLRETURN ret = SQL_ERROR;
14205 
14206     HSTMT_LOCK(stmt);
14207     if (stmt == SQL_NULL_HSTMT) {
14208 	return SQL_INVALID_HANDLE;
14209     }
14210     s = (STMT *) stmt;
14211     if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
14212 	*((long *) val) = s->rowp;
14213 	if (lenp) {
14214 	    *lenp = sizeof (long);
14215 	}
14216 	ret = SQL_SUCCESS;
14217 	goto done;
14218     }
14219     if (col < 1 || col > s->ncols) {
14220 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
14221 	goto done;
14222     }
14223     --col;
14224     ret = getrowdata(s, col, type, val, len, lenp, 1);
14225 done:
14226     HSTMT_UNLOCK(stmt);
14227     return ret;
14228 }
14229 
14230 /**
14231  * Internal: fetch and bind from statement's current row
14232  * @param s statement pointer
14233  * @param rsi rowset index
14234  * @result ODBC error code
14235  */
14236 
14237 static SQLRETURN
dofetchbind(STMT * s,int rsi)14238 dofetchbind(STMT *s, int rsi)
14239 {
14240     int ret, i, withinfo = 0;
14241 
14242     s->row_status0[rsi] = SQL_ROW_SUCCESS;
14243     if (s->bkmrk && s->bkmrkcol.valp) {
14244 	long *val;
14245 
14246 	if (s->bind_type != SQL_BIND_BY_COLUMN) {
14247 	    val = (long *) ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
14248 	} else {
14249 	    val = (long *) s->bkmrkcol.valp + rsi;
14250 	}
14251 	if (s->bind_offs) {
14252 	    val = (long *) ((char *) val + *s->bind_offs);
14253 	}
14254 	*val = s->rowp;
14255 	if (s->bkmrkcol.lenp) {
14256 	    SQLLEN *ival;
14257 
14258 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
14259 		ival = (SQLLEN *)
14260 		    ((char *) s->bkmrkcol.lenp + s->bind_type * rsi);
14261 	    } else {
14262 		ival = &s->bkmrkcol.lenp[rsi];
14263 	    }
14264 	    if (s->bind_offs) {
14265 		ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
14266 	    }
14267 	    *ival = sizeof (long);
14268 	}
14269     }
14270     ret = SQL_SUCCESS;
14271     for (i = 0; s->bindcols && i < s->ncols; i++) {
14272 	BINDCOL *b = &s->bindcols[i];
14273 	SQLPOINTER dp = 0;
14274 	SQLLEN *lp = 0;
14275 
14276 	b->offs = 0;
14277 	if (b->valp) {
14278 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
14279 		dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
14280 	    } else {
14281 		dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
14282 	    }
14283 	    if (s->bind_offs) {
14284 		dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
14285 	    }
14286 	}
14287 	if (b->lenp) {
14288 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
14289 		lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
14290 	    } else {
14291 		lp = b->lenp + rsi;
14292 	    }
14293 	    if (s->bind_offs) {
14294 		lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
14295 	    }
14296 	}
14297 	if (dp || lp) {
14298 	    ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
14299 	    if (!SQL_SUCCEEDED(ret)) {
14300 		s->row_status0[rsi] = SQL_ROW_ERROR;
14301 		break;
14302 	    }
14303 	    if (ret != SQL_SUCCESS) {
14304 		withinfo = 1;
14305 #ifdef SQL_ROW_SUCCESS_WITH_INFO
14306 		s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
14307 #endif
14308 	    }
14309 	}
14310     }
14311     if (SQL_SUCCEEDED(ret)) {
14312 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
14313     }
14314     return ret;
14315 }
14316 
14317 /**
14318  * Internal fetch function for SQLFetchScroll() and SQLExtendedFetch().
14319  * @param stmt statement handle
14320  * @param orient fetch direction
14321  * @param offset offset for fetch direction
14322  * @result ODBC error code
14323  */
14324 
14325 static SQLRETURN
drvfetchscroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLINTEGER offset)14326 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
14327 {
14328     STMT *s;
14329     int i, withinfo = 0;
14330     SQLRETURN ret;
14331 
14332     if (stmt == SQL_NULL_HSTMT) {
14333 	return SQL_INVALID_HANDLE;
14334     }
14335     s = (STMT *) stmt;
14336     for (i = 0; i < s->rowset_size; i++) {
14337 	s->row_status0[i] = SQL_ROW_NOROW;
14338     }
14339     if (s->row_status) {
14340 	memcpy(s->row_status, s->row_status0,
14341 	       sizeof (SQLUSMALLINT) * s->rowset_size);
14342     }
14343     s->row_count0 = 0;
14344     if (s->row_count) {
14345 	*s->row_count = s->row_count0;
14346     }
14347     if (!s->bindcols) {
14348 	for (i = 0; i < s->rowset_size; i++) {
14349 	    s->row_status0[i] = SQL_ROW_ERROR;
14350 	}
14351 	ret = SQL_ERROR;
14352 	i = 0;
14353 	goto done2;
14354     }
14355     if (!s->isselect) {
14356 	setstat(s, -1, "no result set available", "24000");
14357 	ret = SQL_ERROR;
14358 	i = s->nrows;
14359 	goto done2;
14360     }
14361     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
14362 	setstat(s, -1, "wrong fetch direction", "01000");
14363 	ret = SQL_ERROR;
14364 	i = 0;
14365 	goto done2;
14366     }
14367     ret = SQL_SUCCESS;
14368     i = 0;
14369     if (((DBC *) (s->dbc))->cur_s3stmt == s && s->s3stmt) {
14370 	s->rowp = 0;
14371 	for (; i < s->rowset_size; i++) {
14372 	    if (s->max_rows && s->s3stmt_rownum + 1 >= s->max_rows) {
14373 		ret = (i == 0) ? SQL_NO_DATA : SQL_SUCCESS;
14374 		break;
14375 	    }
14376 	    ret = s3stmt_step(s);
14377 	    if (ret != SQL_SUCCESS) {
14378 		s->row_status0[i] = SQL_ROW_ERROR;
14379 		break;
14380 	    }
14381 	    if (s->nrows < 1) {
14382 		break;
14383 	    }
14384 	    ret = dofetchbind(s, i);
14385 	    if (!SQL_SUCCEEDED(ret)) {
14386 		break;
14387 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
14388 		withinfo = 1;
14389 	    }
14390 	}
14391     } else if (s->rows) {
14392 	switch (orient) {
14393 	case SQL_FETCH_NEXT:
14394 	    if (s->nrows < 1) {
14395 		return SQL_NO_DATA;
14396 	    }
14397 	    if (s->rowp < 0) {
14398 		s->rowp = -1;
14399 	    }
14400 	    if (s->rowp >= s->nrows) {
14401 		s->rowp = s->nrows;
14402 		return SQL_NO_DATA;
14403 	    }
14404 	    break;
14405 	case SQL_FETCH_PRIOR:
14406 	    if (s->nrows < 1) {
14407 		s->rowp = -1;
14408 		return SQL_NO_DATA;
14409 	    }
14410 	    s->rowp -= s->rowset_size + 1;
14411 	    if (s->rowp < -1) {
14412 		s->rowp = -1;
14413 		return SQL_NO_DATA;
14414 	    }
14415 	    break;
14416 	case SQL_FETCH_FIRST:
14417 	    if (s->nrows < 1) {
14418 		return SQL_NO_DATA;
14419 	    }
14420 	    s->rowp = -1;
14421 	    break;
14422 	case SQL_FETCH_LAST:
14423 	    if (s->nrows < 1) {
14424 		return SQL_NO_DATA;
14425 	    }
14426 	    s->rowp = s->nrows - s->rowset_size;
14427 	    if (--s->rowp < -1) {
14428 		s->rowp = -1;
14429 	    }
14430 	    break;
14431 	case SQL_FETCH_ABSOLUTE:
14432 	    if (offset == 0) {
14433 		s->rowp = -1;
14434 		return SQL_NO_DATA;
14435 	    } else if (offset < 0) {
14436 		if (0 - offset <= s->nrows) {
14437 		    s->rowp = s->nrows + offset - 1;
14438 		    break;
14439 		}
14440 		s->rowp = -1;
14441 		return SQL_NO_DATA;
14442 	    } else if (offset > s->nrows) {
14443 		s->rowp = s->nrows;
14444 		return SQL_NO_DATA;
14445 	    }
14446 	    s->rowp = offset - 1 - 1;
14447 	    break;
14448 	case SQL_FETCH_RELATIVE:
14449 	    if (offset >= 0) {
14450 		s->rowp += offset * s->rowset_size - 1;
14451 		if (s->rowp >= s->nrows) {
14452 		    s->rowp = s->nrows;
14453 		    return SQL_NO_DATA;
14454 		}
14455 	    } else {
14456 		s->rowp += offset * s->rowset_size - 1;
14457 		if (s->rowp < -1) {
14458 		    s->rowp = -1;
14459 		    return SQL_NO_DATA;
14460 		}
14461 	    }
14462 	    break;
14463 	case SQL_FETCH_BOOKMARK:
14464 	    if (s->bkmrk) {
14465 		if (offset < 0 || offset >= s->nrows) {
14466 		    return SQL_NO_DATA;
14467 		}
14468 		s->rowp = offset - 1;
14469 		break;
14470 	    }
14471 	    /* fall through */
14472 	default:
14473 	    s->row_status0[0] = SQL_ROW_ERROR;
14474 	    ret = SQL_ERROR;
14475 	    goto done;
14476 	}
14477 	for (; i < s->rowset_size; i++) {
14478 	    ++s->rowp;
14479 	    if (s->rowp < 0 || s->rowp >= s->nrows) {
14480 		break;
14481 	    }
14482 	    ret = dofetchbind(s, i);
14483 	    if (!SQL_SUCCEEDED(ret)) {
14484 		break;
14485 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
14486 		withinfo = 1;
14487 	    }
14488 	}
14489     }
14490 done:
14491     if (i == 0) {
14492 	if (SQL_SUCCEEDED(ret)) {
14493 	    return SQL_NO_DATA;
14494 	}
14495 	return ret;
14496     }
14497     if (SQL_SUCCEEDED(ret)) {
14498 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
14499     }
14500 done2:
14501     if (s->row_status) {
14502 	memcpy(s->row_status, s->row_status0,
14503 	       sizeof (SQLUSMALLINT) * s->rowset_size);
14504     }
14505     s->row_count0 = i;
14506     if (s->row_count) {
14507 	*s->row_count = s->row_count0;
14508     }
14509     return ret;
14510 }
14511 
14512 /**
14513  * Fetch next result row.
14514  * @param stmt statement handle
14515  * @result ODBC error code
14516  */
14517 
14518 SQLRETURN SQL_API
SQLFetch(SQLHSTMT stmt)14519 SQLFetch(SQLHSTMT stmt)
14520 {
14521     SQLRETURN ret;
14522 
14523     HSTMT_LOCK(stmt);
14524     ret = drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
14525     HSTMT_UNLOCK(stmt);
14526     return ret;
14527 }
14528 
14529 /**
14530  * Fetch result row with scrolling.
14531  * @param stmt statement handle
14532  * @param orient fetch direction
14533  * @param offset offset for fetch direction
14534  * @result ODBC error code
14535  */
14536 
14537 SQLRETURN SQL_API
SQLFetchScroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLLEN offset)14538 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLLEN offset)
14539 {
14540     SQLRETURN ret;
14541 
14542     HSTMT_LOCK(stmt);
14543     ret = drvfetchscroll(stmt, orient, offset);
14544     HSTMT_UNLOCK(stmt);
14545     return ret;
14546 }
14547 
14548 /**
14549  * Fetch result row with scrolling and row status.
14550  * @param stmt statement handle
14551  * @param orient fetch direction
14552  * @param offset offset for fetch direction
14553  * @param rowcount output number of fetched rows
14554  * @param rowstatus array for row stati
14555  * @result ODBC error code
14556  */
14557 
14558 SQLRETURN SQL_API
SQLExtendedFetch(SQLHSTMT stmt,SQLUSMALLINT orient,SQLROWOFFSET offset,SQLROWSETSIZE * rowcount,SQLUSMALLINT * rowstatus)14559 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLROWOFFSET offset,
14560 		 SQLROWSETSIZE *rowcount, SQLUSMALLINT *rowstatus)
14561 {
14562     STMT *s;
14563     SQLRETURN ret;
14564     SQLUSMALLINT *rst;
14565 
14566     HSTMT_LOCK(stmt);
14567     if (stmt == SQL_NULL_HSTMT) {
14568 	return SQL_INVALID_HANDLE;
14569     }
14570     s = (STMT *) stmt;
14571     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
14572     rst = s->row_status;
14573     s->row_status = 0;
14574     ret = drvfetchscroll(stmt, orient, offset);
14575     s->row_status = rst;
14576     if (rowstatus) {
14577 	memcpy(rowstatus, s->row_status0,
14578 	       sizeof (SQLUSMALLINT) * s->rowset_size);
14579     }
14580     if (rowcount) {
14581 	*rowcount = s->row_count0;
14582     }
14583     HSTMT_UNLOCK(stmt);
14584     return ret;
14585 }
14586 
14587 /**
14588  * Return number of affected rows of HSTMT.
14589  * @param stmt statement handle
14590  * @param nrows output number of rows
14591  * @result ODBC error code
14592  */
14593 
14594 SQLRETURN SQL_API
SQLRowCount(SQLHSTMT stmt,SQLLEN * nrows)14595 SQLRowCount(SQLHSTMT stmt, SQLLEN *nrows)
14596 {
14597     STMT *s;
14598 
14599     HSTMT_LOCK(stmt);
14600     if (stmt == SQL_NULL_HSTMT) {
14601 	return SQL_INVALID_HANDLE;
14602     }
14603     s = (STMT *) stmt;
14604     if (nrows) {
14605 	*nrows = s->nrows;
14606     }
14607     HSTMT_UNLOCK(stmt);
14608     return SQL_SUCCESS;
14609 }
14610 
14611 /**
14612  * Return number of columns of result set given HSTMT.
14613  * @param stmt statement handle
14614  * @param ncols output number of columns
14615  * @result ODBC error code
14616  */
14617 
14618 SQLRETURN SQL_API
SQLNumResultCols(SQLHSTMT stmt,SQLSMALLINT * ncols)14619 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
14620 {
14621     STMT *s;
14622 
14623     HSTMT_LOCK(stmt);
14624     if (stmt == SQL_NULL_HSTMT) {
14625 	return SQL_INVALID_HANDLE;
14626     }
14627     s = (STMT *) stmt;
14628     if (ncols) {
14629 	*ncols = s->ncols;
14630     }
14631     HSTMT_UNLOCK(stmt);
14632     return SQL_SUCCESS;
14633 }
14634 
14635 /**
14636  * Internal describe column information.
14637  * @param stmt statement handle
14638  * @param col column number, starting at 1
14639  * @param name buffer for column name
14640  * @param nameMax length of name buffer
14641  * @param nameLen output length of column name
14642  * @param type output SQL type
14643  * @param size output column size
14644  * @param digits output number of digits
14645  * @param nullable output NULL allowed indicator
14646  * @result ODBC error code
14647  */
14648 
14649 static SQLRETURN
drvdescribecol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)14650 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
14651 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
14652 	       SQLSMALLINT *type, SQLULEN *size,
14653 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
14654 {
14655     STMT *s;
14656     COL *c;
14657     int didname = 0;
14658 
14659     if (stmt == SQL_NULL_HSTMT) {
14660 	return SQL_INVALID_HANDLE;
14661     }
14662     s = (STMT *) stmt;
14663     if (!s->cols) {
14664 	setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
14665 	return SQL_ERROR;
14666     }
14667     if (col < 1 || col > s->ncols) {
14668 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
14669 	return SQL_ERROR;
14670     }
14671     c = s->cols + col - 1;
14672     if (name && nameMax > 0) {
14673 	strncpy((char *) name, c->column, nameMax);
14674 	name[nameMax - 1] = '\0';
14675 	didname = 1;
14676     }
14677     if (nameLen) {
14678 	if (didname) {
14679 	    *nameLen = strlen((char *) name);
14680 	} else {
14681 	    *nameLen = strlen(c->column);
14682 	}
14683     }
14684     if (type) {
14685 	*type = c->type;
14686 #ifdef WINTERFACE
14687 	if (s->nowchar[0] || s->nowchar[1]) {
14688 	    switch (c->type) {
14689 	    case SQL_WCHAR:
14690 		*type = SQL_CHAR;
14691 		break;
14692 	    case SQL_WVARCHAR:
14693 		*type = SQL_VARCHAR;
14694 		break;
14695 #ifdef SQL_LONGVARCHAR
14696 	    case SQL_WLONGVARCHAR:
14697 		*type = SQL_LONGVARCHAR;
14698 		break;
14699 #endif
14700 	    }
14701 	}
14702 #endif
14703     }
14704     if (size) {
14705 	*size = c->size;
14706     }
14707     if (digits) {
14708 	*digits = 0;
14709     }
14710     if (nullable) {
14711 	*nullable = 1;
14712     }
14713     return SQL_SUCCESS;
14714 }
14715 
14716 #ifndef WINTERFACE
14717 /**
14718  * Describe column information.
14719  * @param stmt statement handle
14720  * @param col column number, starting at 1
14721  * @param name buffer for column name
14722  * @param nameMax length of name buffer
14723  * @param nameLen output length of column name
14724  * @param type output SQL type
14725  * @param size output column size
14726  * @param digits output number of digits
14727  * @param nullable output NULL allowed indicator
14728  * @result ODBC error code
14729  */
14730 
14731 SQLRETURN SQL_API
SQLDescribeCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)14732 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
14733 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
14734 	       SQLSMALLINT *type, SQLULEN *size,
14735 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
14736 {
14737 #if defined(_WIN32) || defined(_WIN64)
14738     SQLSMALLINT len = 0;
14739 #endif
14740     SQLRETURN ret;
14741 
14742     HSTMT_LOCK(stmt);
14743 #if defined(_WIN32) || defined(_WIN64)
14744     if (!((STMT *) stmt)->oemcp[0]) {
14745 	ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
14746 			     type, size, digits, nullable);
14747 	goto done;
14748     }
14749     ret = drvdescribecol(stmt, col, name, nameMax,
14750 			 &len, type, size, digits, nullable);
14751     if (ret == SQL_SUCCESS) {
14752 	if (name) {
14753 	    if (len > 0) {
14754 		SQLCHAR *n = NULL;
14755 
14756 		n = (SQLCHAR *) utf_to_wmb((char *) name, len);
14757 		if (n) {
14758 		    strncpy((char *) name, (char *) n, nameMax);
14759 		    n[len] = 0;
14760 		    len = min(nameMax, strlen((char *) n));
14761 		    uc_free(n);
14762 		} else {
14763 		    len = 0;
14764 		}
14765 	    }
14766 	    if (len <= 0) {
14767 		len = 0;
14768 		if (nameMax > 0) {
14769 		    name[0] = 0;
14770 		}
14771 	    }
14772 	} else {
14773 	    STMT *s = (STMT *) stmt;
14774 	    COL *c = s->cols + col - 1;
14775 
14776 	    len = 0;
14777 	    if (c->column) {
14778 		len = strlen(c->column);
14779 	    }
14780 	}
14781 	if (nameLen) {
14782 	    *nameLen = len;
14783 	}
14784     }
14785 done:
14786     ;
14787 #else
14788     ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
14789 			 type, size, digits, nullable);
14790 #endif
14791     HSTMT_UNLOCK(stmt);
14792     return ret;
14793 }
14794 #endif
14795 
14796 #ifdef WINTERFACE
14797 /**
14798  * Describe column information (UNICODE version).
14799  * @param stmt statement handle
14800  * @param col column number, starting at 1
14801  * @param name buffer for column name
14802  * @param nameMax length of name buffer
14803  * @param nameLen output length of column name
14804  * @param type output SQL type
14805  * @param size output column size
14806  * @param digits output number of digits
14807  * @param nullable output NULL allowed indicator
14808  * @result ODBC error code
14809  */
14810 
14811 SQLRETURN SQL_API
SQLDescribeColW(SQLHSTMT stmt,SQLUSMALLINT col,SQLWCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)14812 SQLDescribeColW(SQLHSTMT stmt, SQLUSMALLINT col, SQLWCHAR *name,
14813 		SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
14814 		SQLSMALLINT *type, SQLULEN *size,
14815 		SQLSMALLINT *digits, SQLSMALLINT *nullable)
14816 {
14817     SQLRETURN ret;
14818     SQLSMALLINT len = 0;
14819 
14820     HSTMT_LOCK(stmt);
14821     ret = drvdescribecol(stmt, col, (SQLCHAR *) name,
14822 			 (SQLSMALLINT) (nameMax * sizeof (SQLWCHAR)),
14823 			 &len, type, size, digits, nullable);
14824     if (ret == SQL_SUCCESS) {
14825 	if (name) {
14826 	    if (len > 0) {
14827 		SQLWCHAR *n = NULL;
14828 
14829 		n = uc_from_utf((SQLCHAR *) name, len);
14830 		if (n) {
14831 		    uc_strncpy(name, n, nameMax);
14832 		    n[len] = 0;
14833 		    len = min(nameMax, uc_strlen(n));
14834 		    uc_free(n);
14835 		} else {
14836 		    len = 0;
14837 		}
14838 	    }
14839 	    if (len <= 0) {
14840 		len = 0;
14841 		if (nameMax > 0) {
14842 		    name[0] = 0;
14843 		}
14844 	    }
14845 	} else {
14846 	    STMT *s = (STMT *) stmt;
14847 	    COL *c = s->cols + col - 1;
14848 
14849 	    len = 0;
14850 	    if (c->column) {
14851 		len = strlen(c->column);
14852 	    }
14853 	}
14854 	if (nameLen) {
14855 	    *nameLen = len;
14856 	}
14857     }
14858     HSTMT_UNLOCK(stmt);
14859     return ret;
14860 }
14861 #endif
14862 
14863 /**
14864  * Internal retrieve column attributes.
14865  * @param stmt statement handle
14866  * @param col column number, starting at 1
14867  * @param id attribute id
14868  * @param val output buffer
14869  * @param valMax length of output buffer
14870  * @param valLen output length
14871  * @param val2 integer output buffer
14872  * @result ODBC error code
14873  */
14874 
14875 static SQLRETURN
drvcolattributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)14876 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
14877 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
14878 		 SQLLEN *val2)
14879 {
14880     STMT *s;
14881     COL *c;
14882     SQLSMALLINT dummy;
14883     char *valc = (char *) val;
14884 
14885     if (stmt == SQL_NULL_HSTMT) {
14886 	return SQL_INVALID_HANDLE;
14887     }
14888     s = (STMT *) stmt;
14889     if (!s->cols) {
14890 	return SQL_ERROR;
14891     }
14892     if (!valLen) {
14893 	valLen = &dummy;
14894     }
14895     if (id == SQL_COLUMN_COUNT) {
14896 	if (val2) {
14897 	    *val2 = s->ncols;
14898 	}
14899 	*valLen = sizeof (int);
14900 	return SQL_SUCCESS;
14901     }
14902     if (id == SQL_COLUMN_TYPE && col == 0) {
14903 	if (val2) {
14904 	    *val2 = SQL_INTEGER;
14905 	}
14906 	*valLen = sizeof (int);
14907 	return SQL_SUCCESS;
14908     }
14909 #ifdef SQL_DESC_OCTET_LENGTH
14910     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
14911 	if (val2) {
14912 	    *val2 = 4;
14913 	}
14914 	*valLen = sizeof (int);
14915 	return SQL_SUCCESS;
14916     }
14917 #endif
14918     if (col < 1 || col > s->ncols) {
14919 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
14920 	return SQL_ERROR;
14921     }
14922     c = s->cols + col - 1;
14923 
14924     switch (id) {
14925     case SQL_COLUMN_LABEL:
14926 	if (c->label) {
14927 	    if (valc && valMax > 0) {
14928 		strncpy(valc, c->label, valMax);
14929 		valc[valMax - 1] = '\0';
14930 	    }
14931 	    *valLen = strlen(c->label);
14932 	    goto checkLen;
14933 	}
14934 	/* fall through */
14935     case SQL_COLUMN_NAME:
14936     case SQL_DESC_NAME:
14937 	if (valc && valMax > 0) {
14938 	    strncpy(valc, c->column, valMax);
14939 	    valc[valMax - 1] = '\0';
14940 	}
14941 	*valLen = strlen(c->column);
14942 checkLen:
14943 	if (*valLen >= valMax) {
14944 	    setstat(s, -1, "data right truncated", "01004");
14945 	    return SQL_SUCCESS_WITH_INFO;
14946 	}
14947 	return SQL_SUCCESS;
14948 #ifdef SQL_DESC_BASE_COLUMN_NAME
14949 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
14950 	    valc[0] = '\0';
14951 	    *valLen = 0;
14952 	} else if (valc && valMax > 0) {
14953 	    strncpy(valc, c->column, valMax);
14954 	    valc[valMax - 1] = '\0';
14955 	    *valLen = strlen(c->column);
14956 	}
14957 	goto checkLen;
14958 #endif
14959     case SQL_COLUMN_TYPE:
14960     case SQL_DESC_TYPE:
14961 #ifdef WINTERFACE
14962 	{
14963 	    int type = c->type;
14964 
14965 	    if (s->nowchar[0] || s->nowchar[1]) {
14966 		switch (type) {
14967 		case SQL_WCHAR:
14968 		    type = SQL_CHAR;
14969 		    break;
14970 		case SQL_WVARCHAR:
14971 		    type = SQL_VARCHAR;
14972 		    break;
14973 #ifdef SQL_LONGVARCHAR
14974 		case SQL_WLONGVARCHAR:
14975 		    type = SQL_LONGVARCHAR;
14976 		    break;
14977 		}
14978 	    }
14979 	    if (val2) {
14980 		*val2 = type;
14981 	    }
14982 #endif
14983 	}
14984 #else
14985 	if (val2) {
14986 	    *val2 = c->type;
14987 	}
14988 #endif
14989 	*valLen = sizeof (int);
14990 	return SQL_SUCCESS;
14991     case SQL_COLUMN_DISPLAY_SIZE:
14992 	if (val2) {
14993 	    *val2 = c->size;
14994 	}
14995 	*valLen = sizeof (int);
14996 	return SQL_SUCCESS;
14997     case SQL_COLUMN_UNSIGNED:
14998 	if (val2) {
14999 	    *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
15000 	}
15001 	*valLen = sizeof (int);
15002 	return SQL_SUCCESS;
15003     case SQL_COLUMN_SCALE:
15004     case SQL_DESC_SCALE:
15005 	if (val2) {
15006 	    *val2 = c->scale;
15007 	}
15008 	*valLen = sizeof (int);
15009 	return SQL_SUCCESS;
15010     case SQL_COLUMN_PRECISION:
15011     case SQL_DESC_PRECISION:
15012 	if (val2) {
15013 	    switch (c->type) {
15014 	    case SQL_SMALLINT:
15015 		*val2 = 5;
15016 		break;
15017 	    case SQL_INTEGER:
15018 		*val2 = 10;
15019 		break;
15020 	    case SQL_FLOAT:
15021 	    case SQL_REAL:
15022 	    case SQL_DOUBLE:
15023 		*val2 = 15;
15024 		break;
15025 	    case SQL_DATE:
15026 		*val2 = 0;
15027 		break;
15028 	    case SQL_TIME:
15029 		*val2 = 0;
15030 		break;
15031 #ifdef SQL_TYPE_TIMESTAMP
15032 	    case SQL_TYPE_TIMESTAMP:
15033 #endif
15034 	    case SQL_TIMESTAMP:
15035 		*val2 = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
15036 		break;
15037 	    default:
15038 		*val2 = c->prec;
15039 		break;
15040 	    }
15041 	}
15042 	*valLen = sizeof (int);
15043 	return SQL_SUCCESS;
15044     case SQL_COLUMN_MONEY:
15045 	if (val2) {
15046 	    *val2 = SQL_FALSE;
15047 	}
15048 	*valLen = sizeof (int);
15049 	return SQL_SUCCESS;
15050     case SQL_COLUMN_AUTO_INCREMENT:
15051 	if (val2) {
15052 	    *val2 = c->autoinc;
15053 	}
15054 	*valLen = sizeof (int);
15055 	return SQL_SUCCESS;
15056     case SQL_COLUMN_LENGTH:
15057     case SQL_DESC_LENGTH:
15058 	if (val2) {
15059 	    *val2 = c->size;
15060 	}
15061 	*valLen = sizeof (int);
15062 	return SQL_SUCCESS;
15063     case SQL_COLUMN_NULLABLE:
15064     case SQL_DESC_NULLABLE:
15065 	if (val2) {
15066 	    *val2 = c->notnull;
15067 	}
15068 	*valLen = sizeof (int);
15069 	return SQL_SUCCESS;
15070     case SQL_COLUMN_SEARCHABLE:
15071 	if (val2) {
15072 	    *val2 = SQL_SEARCHABLE;
15073 	}
15074 	*valLen = sizeof (int);
15075 	return SQL_SUCCESS;
15076     case SQL_COLUMN_CASE_SENSITIVE:
15077 	if (val2) {
15078 	    *val2 = SQL_TRUE;
15079 	}
15080 	*valLen = sizeof (int);
15081 	return SQL_SUCCESS;
15082     case SQL_COLUMN_UPDATABLE:
15083 	if (val2) {
15084 	    *val2 = SQL_TRUE;
15085 	}
15086 	*valLen = sizeof (int);
15087 	return SQL_SUCCESS;
15088     case SQL_DESC_COUNT:
15089 	if (val2) {
15090 	    *val2 = s->ncols;
15091 	}
15092 	*valLen = sizeof (int);
15093 	return SQL_SUCCESS;
15094     case SQL_COLUMN_TYPE_NAME: {
15095 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
15096 
15097 #ifdef WINTERFACE
15098 	if (c->type == SQL_WCHAR ||
15099 	    c->type == SQL_WVARCHAR ||
15100 	    c->type == SQL_WLONGVARCHAR) {
15101 	    if (!(s->nowchar[0] || s->nowchar[1])) {
15102 		if (strcasecmp(tn, "varchar") == 0) {
15103 		    tn = "wvarchar";
15104 		}
15105 	    }
15106 	}
15107 #endif
15108 	if (valc && valMax > 0) {
15109 	    strncpy(valc, tn, valMax);
15110 	    valc[valMax - 1] = '\0';
15111 	    p = strchr(valc, '(');
15112 	    if (p) {
15113 		*p = '\0';
15114 		while (p > valc && ISSPACE(p[-1])) {
15115 		    --p;
15116 		    *p = '\0';
15117 		}
15118 	    }
15119 	    *valLen = strlen(valc);
15120 	} else {
15121 	    *valLen = strlen(tn);
15122 	    p = strchr(tn, '(');
15123 	    if (p) {
15124 		*valLen = p - tn;
15125 		while (p > tn && ISSPACE(p[-1])) {
15126 		    --p;
15127 		    *valLen -= 1;
15128 		}
15129 	    }
15130 	}
15131 	goto checkLen;
15132     }
15133     case SQL_COLUMN_OWNER_NAME:
15134     case SQL_COLUMN_QUALIFIER_NAME: {
15135 	char *z = "";
15136 
15137 	if (valc && valMax > 0) {
15138 	    strncpy(valc, z, valMax);
15139 	    valc[valMax - 1] = '\0';
15140 	}
15141 	*valLen = strlen(z);
15142 	goto checkLen;
15143     }
15144     case SQL_COLUMN_TABLE_NAME:
15145 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
15146     case SQL_DESC_TABLE_NAME:
15147 #endif
15148 #ifdef SQL_DESC_BASE_TABLE_NAME
15149     case SQL_DESC_BASE_TABLE_NAME:
15150 #endif
15151 	if (valc && valMax > 0) {
15152 	    strncpy(valc, c->table, valMax);
15153 	    valc[valMax - 1] = '\0';
15154 	}
15155 	*valLen = strlen(c->table);
15156 	goto checkLen;
15157 #ifdef SQL_DESC_NUM_PREC_RADIX
15158     case SQL_DESC_NUM_PREC_RADIX:
15159 	if (val2) {
15160 	    switch (c->type) {
15161 #ifdef WINTERFACE
15162 	    case SQL_WCHAR:
15163 	    case SQL_WVARCHAR:
15164 #ifdef SQL_LONGVARCHAR
15165 	    case SQL_WLONGVARCHAR:
15166 #endif
15167 #endif
15168 	    case SQL_CHAR:
15169 	    case SQL_VARCHAR:
15170 #ifdef SQL_LONGVARCHAR
15171 	    case SQL_LONGVARCHAR:
15172 #endif
15173 	    case SQL_BINARY:
15174 	    case SQL_VARBINARY:
15175 	    case SQL_LONGVARBINARY:
15176 		*val2 = 0;
15177 		break;
15178 	    default:
15179 		*val2 = 2;
15180 	    }
15181 	}
15182 	*valLen = sizeof (int);
15183 	return SQL_SUCCESS;
15184 #endif
15185     }
15186     setstat(s, -1, "unsupported column attributes %d", "HY091", id);
15187     return SQL_ERROR;
15188 }
15189 
15190 #ifndef WINTERFACE
15191 /**
15192  * Retrieve column attributes.
15193  * @param stmt statement handle
15194  * @param col column number, starting at 1
15195  * @param id attribute id
15196  * @param val output buffer
15197  * @param valMax length of output buffer
15198  * @param valLen output length
15199  * @param val2 integer output buffer
15200  * @result ODBC error code
15201  */
15202 
15203 SQLRETURN SQL_API
SQLColAttributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)15204 SQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
15205 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
15206 		 SQLLEN *val2)
15207 {
15208 #if defined(_WIN32) || defined(_WIN64)
15209     SQLSMALLINT len = 0;
15210 #endif
15211     SQLRETURN ret;
15212 
15213     HSTMT_LOCK(stmt);
15214 #if defined(_WIN32) || defined(_WIN64)
15215     if (!((STMT *) stmt)->oemcp[0]) {
15216 	ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
15217 	goto done;
15218     }
15219     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
15220     if (SQL_SUCCEEDED(ret)) {
15221 	char *v = NULL;
15222 
15223 	switch (id) {
15224 	case SQL_COLUMN_LABEL:
15225 	case SQL_COLUMN_NAME:
15226 	case SQL_DESC_NAME:
15227 	case SQL_COLUMN_TYPE_NAME:
15228 	case SQL_COLUMN_OWNER_NAME:
15229 	case SQL_COLUMN_QUALIFIER_NAME:
15230 	case SQL_COLUMN_TABLE_NAME:
15231 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
15232 	case SQL_DESC_TABLE_NAME:
15233 #endif
15234 #ifdef SQL_DESC_BASE_COLUMN_NAME
15235 	case SQL_DESC_BASE_COLUMN_NAME:
15236 #endif
15237 #ifdef SQL_DESC_BASE_TABLE_NAME
15238     case SQL_DESC_BASE_TABLE_NAME:
15239 #endif
15240 	    if (val && valMax > 0) {
15241 		int vmax = valMax;
15242 
15243 		v = utf_to_wmb((char *) val, SQL_NTS);
15244 		if (v) {
15245 		    strncpy(val, v, vmax);
15246 		    len = min(vmax, strlen(v));
15247 		    uc_free(v);
15248 		}
15249 		if (vmax > 0) {
15250 		    v = (char *) val;
15251 		    v[vmax - 1] = '\0';
15252 		}
15253 	    }
15254 	    if (len <= 0) {
15255 		len = 0;
15256 	    }
15257 	    break;
15258 	}
15259 	if (valLen) {
15260 	    *valLen = len;
15261 	}
15262     }
15263 done:
15264     ;
15265 #else
15266     ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
15267 #endif
15268     HSTMT_UNLOCK(stmt);
15269     return ret;
15270 }
15271 #endif
15272 
15273 #ifdef WINTERFACE
15274 /**
15275  * Retrieve column attributes (UNICODE version).
15276  * @param stmt statement handle
15277  * @param col column number, starting at 1
15278  * @param id attribute id
15279  * @param val output buffer
15280  * @param valMax length of output buffer
15281  * @param valLen output length
15282  * @param val2 integer output buffer
15283  * @result ODBC error code
15284  */
15285 
15286 SQLRETURN SQL_API
SQLColAttributesW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)15287 SQLColAttributesW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
15288 		  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
15289 		  SQLLEN *val2)
15290 {
15291     SQLRETURN ret;
15292     SQLSMALLINT len = 0;
15293 
15294     HSTMT_LOCK(stmt);
15295     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
15296     if (SQL_SUCCEEDED(ret)) {
15297 	SQLWCHAR *v = NULL;
15298 
15299 	switch (id) {
15300 	case SQL_COLUMN_LABEL:
15301 	case SQL_COLUMN_NAME:
15302 	case SQL_DESC_NAME:
15303 	case SQL_COLUMN_TYPE_NAME:
15304 	case SQL_COLUMN_OWNER_NAME:
15305 	case SQL_COLUMN_QUALIFIER_NAME:
15306 	case SQL_COLUMN_TABLE_NAME:
15307 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
15308 	case SQL_DESC_TABLE_NAME:
15309 #endif
15310 #ifdef SQL_DESC_BASE_COLUMN_NAME
15311 	case SQL_DESC_BASE_COLUMN_NAME:
15312 #endif
15313 #ifdef SQL_DESC_BASE_TABLE_NAME
15314     case SQL_DESC_BASE_TABLE_NAME:
15315 #endif
15316 	    if (val && valMax > 0) {
15317 		int vmax = valMax / sizeof (SQLWCHAR);
15318 
15319 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
15320 		if (v) {
15321 		    uc_strncpy(val, v, vmax);
15322 		    len = min(vmax, uc_strlen(v));
15323 		    uc_free(v);
15324 		    len *= sizeof (SQLWCHAR);
15325 		}
15326 		if (vmax > 0) {
15327 		    v = (SQLWCHAR *) val;
15328 		    v[vmax - 1] = '\0';
15329 		}
15330 	    }
15331 	    if (len <= 0) {
15332 		len = 0;
15333 	    }
15334 	    break;
15335 	}
15336 	if (valLen) {
15337 	    *valLen = len;
15338 	}
15339     }
15340     HSTMT_UNLOCK(stmt);
15341     return ret;
15342 }
15343 #endif
15344 
15345 /**
15346  * Internal retrieve column attributes.
15347  * @param stmt statement handle
15348  * @param col column number, starting at 1
15349  * @param id attribute id
15350  * @param val output buffer
15351  * @param valMax length of output buffer
15352  * @param valLen output length
15353  * @param val2 integer output buffer
15354  * @result ODBC error code
15355  */
15356 
15357 static SQLRETURN
drvcolattribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLPOINTER val2)15358 drvcolattribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
15359 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
15360 		SQLPOINTER val2)
15361 {
15362     STMT *s;
15363     COL *c;
15364     int v = 0;
15365     char *valc = (char *) val;
15366     SQLSMALLINT dummy;
15367 
15368     if (stmt == SQL_NULL_HSTMT) {
15369 	return SQL_INVALID_HANDLE;
15370     }
15371     s = (STMT *) stmt;
15372     if (!s->cols) {
15373 	return SQL_ERROR;
15374     }
15375     if (col < 1 || col > s->ncols) {
15376 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
15377 	return SQL_ERROR;
15378     }
15379     if (!valLen) {
15380 	valLen = &dummy;
15381     }
15382     c = s->cols + col - 1;
15383     switch (id) {
15384     case SQL_DESC_COUNT:
15385 	v = s->ncols;
15386 	break;
15387     case SQL_DESC_CATALOG_NAME:
15388 	if (valc && valMax > 0) {
15389 	    strncpy(valc, c->db, valMax);
15390 	    valc[valMax - 1] = '\0';
15391 	}
15392 	*valLen = strlen(c->db);
15393 checkLen:
15394 	if (*valLen >= valMax) {
15395 	    setstat(s, -1, "data right truncated", "01004");
15396 	    return SQL_SUCCESS_WITH_INFO;
15397 	}
15398 	break;
15399     case SQL_COLUMN_LENGTH:
15400     case SQL_DESC_LENGTH:
15401 	v = c->size;
15402 	break;
15403     case SQL_COLUMN_LABEL:
15404 	if (c->label) {
15405 	    if (valc && valMax > 0) {
15406 		strncpy(valc, c->label, valMax);
15407 		valc[valMax - 1] = '\0';
15408 	    }
15409 	    *valLen = strlen(c->label);
15410 	    goto checkLen;
15411 	}
15412 	/* fall through */
15413     case SQL_COLUMN_NAME:
15414     case SQL_DESC_NAME:
15415 	if (valc && valMax > 0) {
15416 	    strncpy(valc, c->column, valMax);
15417 	    valc[valMax - 1] = '\0';
15418 	}
15419 	*valLen = strlen(c->column);
15420 	goto checkLen;
15421     case SQL_DESC_SCHEMA_NAME: {
15422 	char *z = "";
15423 
15424 	if (valc && valMax > 0) {
15425 	    strncpy(valc, z, valMax);
15426 	    valc[valMax - 1] = '\0';
15427 	}
15428 	*valLen = strlen(z);
15429 	goto checkLen;
15430     }
15431 #ifdef SQL_DESC_BASE_COLUMN_NAME
15432     case SQL_DESC_BASE_COLUMN_NAME:
15433 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
15434 	    valc[0] = '\0';
15435 	    *valLen = 0;
15436 	} else if (valc && valMax > 0) {
15437 	    strncpy(valc, c->column, valMax);
15438 	    valc[valMax - 1] = '\0';
15439 	    *valLen = strlen(c->column);
15440 	}
15441 	goto checkLen;
15442 #endif
15443     case SQL_DESC_TYPE_NAME: {
15444 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
15445 
15446 #ifdef WINTERFACE
15447 	if (c->type == SQL_WCHAR ||
15448 	    c->type == SQL_WVARCHAR ||
15449 	    c->type == SQL_WLONGVARCHAR) {
15450 	    if (!(s->nowchar[0] || s->nowchar[1])) {
15451 		if (strcasecmp(tn, "varchar") == 0) {
15452 		    tn = "wvarchar";
15453 		}
15454 	    }
15455 	}
15456 #endif
15457 	if (valc && valMax > 0) {
15458 	    strncpy(valc, tn, valMax);
15459 	    valc[valMax - 1] = '\0';
15460 	    p = strchr(valc, '(');
15461 	    if (p) {
15462 		*p = '\0';
15463 		while (p > valc && ISSPACE(p[-1])) {
15464 		    --p;
15465 		    *p = '\0';
15466 		}
15467 	    }
15468 	    *valLen = strlen(valc);
15469 	} else {
15470 	    *valLen = strlen(tn);
15471 	    p = strchr(tn, '(');
15472 	    if (p) {
15473 		*valLen = p - tn;
15474 		while (p > tn && ISSPACE(p[-1])) {
15475 		    --p;
15476 		    *valLen -= 1;
15477 		}
15478 	    }
15479 	}
15480 	goto checkLen;
15481     }
15482     case SQL_DESC_OCTET_LENGTH:
15483 	v = c->size;
15484 #ifdef WINTERFACE
15485 	if (c->type == SQL_WCHAR ||
15486 	    c->type == SQL_WVARCHAR ||
15487 	    c->type == SQL_WLONGVARCHAR) {
15488 	    if (!(s->nowchar[0] || s->nowchar[1])) {
15489 		v *= sizeof (SQLWCHAR);
15490 	    }
15491 	}
15492 #endif
15493 	break;
15494 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
15495     case SQL_COLUMN_TABLE_NAME:
15496 #endif
15497 #ifdef SQL_DESC_BASE_TABLE_NAME
15498     case SQL_DESC_BASE_TABLE_NAME:
15499 #endif
15500     case SQL_DESC_TABLE_NAME:
15501 	if (valc && valMax > 0) {
15502 	    strncpy(valc, c->table, valMax);
15503 	    valc[valMax - 1] = '\0';
15504 	}
15505 	*valLen = strlen(c->table);
15506 	goto checkLen;
15507     case SQL_DESC_TYPE:
15508 	v = c->type;
15509 #ifdef WINTERFACE
15510 	if (s->nowchar[0] || s->nowchar[1]) {
15511 	    switch (v) {
15512 	    case SQL_WCHAR:
15513 		v = SQL_CHAR;
15514 		break;
15515 	    case SQL_WVARCHAR:
15516 		v = SQL_VARCHAR;
15517 		break;
15518 #ifdef SQL_LONGVARCHAR
15519 	    case SQL_WLONGVARCHAR:
15520 		v = SQL_LONGVARCHAR;
15521 		break;
15522 #endif
15523 	    }
15524 	}
15525 #endif
15526 	break;
15527     case SQL_DESC_CONCISE_TYPE:
15528 	switch (c->type) {
15529 	case SQL_INTEGER:
15530 	    v = SQL_C_LONG;
15531 	    break;
15532 	case SQL_TINYINT:
15533 	    v = SQL_C_TINYINT;
15534 	    break;
15535 	case SQL_SMALLINT:
15536 	    v = SQL_C_SHORT;
15537 	    break;
15538 	case SQL_FLOAT:
15539 	    v = SQL_C_FLOAT;
15540 	    break;
15541 	case SQL_DOUBLE:
15542 	    v = SQL_C_DOUBLE;
15543 	    break;
15544 	case SQL_TIMESTAMP:
15545 	    v = SQL_C_TIMESTAMP;
15546 	    break;
15547 	case SQL_TIME:
15548 	    v = SQL_C_TIME;
15549 	    break;
15550 	case SQL_DATE:
15551 	    v = SQL_C_DATE;
15552 	    break;
15553 #ifdef SQL_C_TYPE_TIMESTAMP
15554 	case SQL_TYPE_TIMESTAMP:
15555 	    v = SQL_C_TYPE_TIMESTAMP;
15556 	    break;
15557 #endif
15558 #ifdef SQL_C_TYPE_TIME
15559 	case SQL_TYPE_TIME:
15560 	    v = SQL_C_TYPE_TIME;
15561 	    break;
15562 #endif
15563 #ifdef SQL_C_TYPE_DATE
15564 	case SQL_TYPE_DATE:
15565 	    v = SQL_C_TYPE_DATE;
15566 	    break;
15567 #endif
15568 #ifdef SQL_BIT
15569 	case SQL_BIT:
15570 	    v = SQL_C_BIT;
15571 	    break;
15572 #endif
15573 #ifdef SQL_BIGINT
15574 	case SQL_BIGINT:
15575 	    v = SQL_C_SBIGINT;
15576 	    break;
15577 #endif
15578 	default:
15579 #ifdef WINTERFACE
15580 	    v = (s->nowchar[0] || s->nowchar[1]) ? SQL_C_CHAR : SQL_C_WCHAR;
15581 #else
15582 	    v = SQL_C_CHAR;
15583 #endif
15584 	    break;
15585 	}
15586 	break;
15587     case SQL_DESC_UPDATABLE:
15588 	v = SQL_TRUE;
15589 	break;
15590     case SQL_COLUMN_DISPLAY_SIZE:
15591 	v = c->size;
15592 	break;
15593     case SQL_COLUMN_UNSIGNED:
15594 	v = c->nosign ? SQL_TRUE : SQL_FALSE;
15595 	break;
15596     case SQL_COLUMN_SEARCHABLE:
15597 	v = SQL_SEARCHABLE;
15598 	break;
15599     case SQL_COLUMN_SCALE:
15600     case SQL_DESC_SCALE:
15601 	v = c->scale;
15602 	break;
15603     case SQL_COLUMN_PRECISION:
15604     case SQL_DESC_PRECISION:
15605 	switch (c->type) {
15606 	case SQL_SMALLINT:
15607 	    v = 5;
15608 	    break;
15609 	case SQL_INTEGER:
15610 	    v = 10;
15611 	    break;
15612 	case SQL_FLOAT:
15613 	case SQL_REAL:
15614 	case SQL_DOUBLE:
15615 	    v = 15;
15616 	    break;
15617 	case SQL_DATE:
15618 	    v = 0;
15619 	    break;
15620 	case SQL_TIME:
15621 	    v = 0;
15622 	    break;
15623 #ifdef SQL_TYPE_TIMESTAMP
15624 	case SQL_TYPE_TIMESTAMP:
15625 #endif
15626 	case SQL_TIMESTAMP:
15627 	    v = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
15628 	    break;
15629 	default:
15630 	    v = c->prec;
15631 	    break;
15632 	}
15633 	break;
15634     case SQL_COLUMN_MONEY:
15635 	v = SQL_FALSE;
15636 	break;
15637     case SQL_COLUMN_AUTO_INCREMENT:
15638 	v = c->autoinc;
15639 	break;
15640     case SQL_DESC_NULLABLE:
15641 	v = c->notnull;
15642 	break;
15643 #ifdef SQL_DESC_NUM_PREC_RADIX
15644     case SQL_DESC_NUM_PREC_RADIX:
15645 	switch (c->type) {
15646 #ifdef WINTERFACE
15647 	case SQL_WCHAR:
15648 	case SQL_WVARCHAR:
15649 #ifdef SQL_LONGVARCHAR
15650 	case SQL_WLONGVARCHAR:
15651 #endif
15652 #endif
15653 	case SQL_CHAR:
15654 	case SQL_VARCHAR:
15655 #ifdef SQL_LONGVARCHAR
15656 	case SQL_LONGVARCHAR:
15657 #endif
15658 	case SQL_BINARY:
15659 	case SQL_VARBINARY:
15660 	case SQL_LONGVARBINARY:
15661 	    v = 0;
15662 	    break;
15663 	default:
15664 	    v = 2;
15665 	}
15666 	break;
15667 #endif
15668     default:
15669 	setstat(s, -1, "unsupported column attribute %d", "HY091", id);
15670 	return SQL_ERROR;
15671     }
15672     if (val2) {
15673 	*(SQLLEN *) val2 = v;
15674     }
15675     return SQL_SUCCESS;
15676 }
15677 
15678 #ifndef WINTERFACE
15679 /**
15680  * Retrieve column attributes.
15681  * @param stmt statement handle
15682  * @param col column number, starting at 1
15683  * @param id attribute id
15684  * @param val output buffer
15685  * @param valMax length of output buffer
15686  * @param valLen output length
15687  * @param val2 integer output buffer
15688  * @result ODBC error code
15689  */
15690 
15691 SQLRETURN SQL_API
SQLColAttribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)15692 SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
15693 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
15694 		COLATTRIBUTE_LAST_ARG_TYPE val2)
15695 {
15696 #if defined(_WIN32) || defined(_WIN64)
15697     SQLSMALLINT len = 0;
15698 #endif
15699     SQLRETURN ret;
15700 
15701     HSTMT_LOCK(stmt);
15702 #if defined(_WIN32) || defined(_WIN64)
15703     if (!((STMT *) stmt)->oemcp[0]) {
15704 	ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
15705 			      (SQLPOINTER) val2);
15706 	goto done;
15707     }
15708     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
15709 			  (SQLPOINTER) val2);
15710     if (SQL_SUCCEEDED(ret)) {
15711 	char *v = NULL;
15712 
15713 	switch (id) {
15714 	case SQL_DESC_SCHEMA_NAME:
15715 	case SQL_DESC_CATALOG_NAME:
15716 	case SQL_COLUMN_LABEL:
15717 	case SQL_DESC_NAME:
15718 	case SQL_DESC_TABLE_NAME:
15719 #ifdef SQL_DESC_BASE_TABLE_NAME
15720 	case SQL_DESC_BASE_TABLE_NAME:
15721 #endif
15722 #ifdef SQL_DESC_BASE_COLUMN_NAME
15723 	case SQL_DESC_BASE_COLUMN_NAME:
15724 #endif
15725 	case SQL_DESC_TYPE_NAME:
15726 	    if (val && valMax > 0) {
15727 		int vmax = valMax;
15728 
15729 		v = utf_to_wmb((char *) val, SQL_NTS);
15730 		if (v) {
15731 		    strncpy(val, v, vmax);
15732 		    len = min(vmax, strlen(v));
15733 		    uc_free(v);
15734 		}
15735 		if (vmax > 0) {
15736 		    v = (char *) val;
15737 		    v[vmax - 1] = '\0';
15738 		}
15739 	    }
15740 	    if (len <= 0) {
15741 		len = 0;
15742 	    }
15743 	    break;
15744 	}
15745 	if (valLen) {
15746 	    *valLen = len;
15747 	}
15748     }
15749 done:
15750     ;
15751 #else
15752     ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
15753 			  (SQLPOINTER) val2);
15754 #endif
15755     HSTMT_UNLOCK(stmt);
15756     return ret;
15757 }
15758 #endif
15759 
15760 #ifdef WINTERFACE
15761 /**
15762  * Retrieve column attributes (UNICODE version).
15763  * @param stmt statement handle
15764  * @param col column number, starting at 1
15765  * @param id attribute id
15766  * @param val output buffer
15767  * @param valMax length of output buffer
15768  * @param valLen output length
15769  * @param val2 integer output buffer
15770  * @result ODBC error code
15771  */
15772 
15773 SQLRETURN SQL_API
SQLColAttributeW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)15774 SQLColAttributeW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
15775 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
15776 		 COLATTRIBUTE_LAST_ARG_TYPE val2)
15777 {
15778     SQLRETURN ret;
15779     SQLSMALLINT len = 0;
15780 
15781     HSTMT_LOCK(stmt);
15782     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
15783 			  (SQLPOINTER) val2);
15784     if (SQL_SUCCEEDED(ret)) {
15785 	SQLWCHAR *v = NULL;
15786 
15787 	switch (id) {
15788 	case SQL_DESC_SCHEMA_NAME:
15789 	case SQL_DESC_CATALOG_NAME:
15790 	case SQL_COLUMN_LABEL:
15791 	case SQL_DESC_NAME:
15792 	case SQL_DESC_TABLE_NAME:
15793 #ifdef SQL_DESC_BASE_TABLE_NAME
15794 	case SQL_DESC_BASE_TABLE_NAME:
15795 #endif
15796 #ifdef SQL_DESC_BASE_COLUMN_NAME
15797 	case SQL_DESC_BASE_COLUMN_NAME:
15798 #endif
15799 	case SQL_DESC_TYPE_NAME:
15800 	    if (val && valMax > 0) {
15801 		int vmax = valMax / sizeof (SQLWCHAR);
15802 
15803 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
15804 		if (v) {
15805 		    uc_strncpy(val, v, vmax);
15806 		    len = min(vmax, uc_strlen(v));
15807 		    uc_free(v);
15808 		    len *= sizeof (SQLWCHAR);
15809 		}
15810 		if (vmax > 0) {
15811 		    v = (SQLWCHAR *) val;
15812 		    v[vmax - 1] = '\0';
15813 		}
15814 	    }
15815 	    if (len <= 0) {
15816 		len = 0;
15817 	    }
15818 	    break;
15819 	}
15820 	if (valLen) {
15821 	    *valLen = len;
15822 	}
15823     }
15824     HSTMT_UNLOCK(stmt);
15825     return ret;
15826 }
15827 #endif
15828 
15829 /**
15830  * Internal return last HDBC or HSTMT error message.
15831  * @param env environment handle or NULL
15832  * @param dbc database connection handle or NULL
15833  * @param stmt statement handle or NULL
15834  * @param sqlState output buffer for SQL state
15835  * @param nativeErr output buffer for native error code
15836  * @param errmsg output buffer for error message
15837  * @param errmax length of output buffer for error message
15838  * @param errlen output length of error message
15839  * @result ODBC error code
15840  */
15841 
15842 static SQLRETURN
drverror(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)15843 drverror(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
15844 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
15845 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
15846 {
15847     SQLCHAR dummy0[6];
15848     SQLINTEGER dummy1;
15849     SQLSMALLINT dummy2;
15850 
15851     if (env == SQL_NULL_HENV &&
15852 	dbc == SQL_NULL_HDBC &&
15853 	stmt == SQL_NULL_HSTMT) {
15854 	return SQL_INVALID_HANDLE;
15855     }
15856     if (sqlState) {
15857 	sqlState[0] = '\0';
15858     } else {
15859 	sqlState = dummy0;
15860     }
15861     if (!nativeErr) {
15862 	nativeErr = &dummy1;
15863     }
15864     *nativeErr = 0;
15865     if (!errlen) {
15866 	errlen = &dummy2;
15867     }
15868     *errlen = 0;
15869     if (errmsg) {
15870 	if (errmax > 0) {
15871 	    errmsg[0] = '\0';
15872 	}
15873     } else {
15874 	errmsg = dummy0;
15875 	errmax = 0;
15876     }
15877     if (stmt) {
15878 	STMT *s = (STMT *) stmt;
15879 
15880 	HSTMT_LOCK(stmt);
15881 	if (s->logmsg[0] == '\0') {
15882 	    HSTMT_UNLOCK(stmt);
15883 	    goto noerr;
15884 	}
15885 	*nativeErr = s->naterr;
15886 	strcpy((char *) sqlState, s->sqlstate);
15887 	if (errmax == SQL_NTS) {
15888 	    strcpy((char *) errmsg, "[SQLite]");
15889 	    strcat((char *) errmsg, (char *) s->logmsg);
15890 	    *errlen = strlen((char *) errmsg);
15891 	} else {
15892 	    strncpy((char *) errmsg, "[SQLite]", errmax);
15893 	    if (errmax - 8 > 0) {
15894 		strncpy((char *) errmsg + 8, (char *) s->logmsg, errmax - 8);
15895 	    }
15896 	    *errlen = min(strlen((char *) s->logmsg) + 8, errmax);
15897 	}
15898 	s->logmsg[0] = '\0';
15899 	HSTMT_UNLOCK(stmt);
15900 	return SQL_SUCCESS;
15901     }
15902     if (dbc) {
15903 	DBC *d = (DBC *) dbc;
15904 
15905 	HDBC_LOCK(dbc);
15906 	if (d->magic != DBC_MAGIC || d->logmsg[0] == '\0') {
15907 	    HDBC_UNLOCK(dbc);
15908 	    goto noerr;
15909 	}
15910 	*nativeErr = d->naterr;
15911 	strcpy((char *) sqlState, d->sqlstate);
15912 	if (errmax == SQL_NTS) {
15913 	    strcpy((char *) errmsg, "[SQLite]");
15914 	    strcat((char *) errmsg, (char *) d->logmsg);
15915 	    *errlen = strlen((char *) errmsg);
15916 	} else {
15917 	    strncpy((char *) errmsg, "[SQLite]", errmax);
15918 	    if (errmax - 8 > 0) {
15919 		strncpy((char *) errmsg + 8, (char *) d->logmsg, errmax - 8);
15920 	    }
15921 	    *errlen = min(strlen((char *) d->logmsg) + 8, errmax);
15922 	}
15923 	d->logmsg[0] = '\0';
15924 	HDBC_UNLOCK(dbc);
15925 	return SQL_SUCCESS;
15926     }
15927 noerr:
15928     sqlState[0] = '\0';
15929     errmsg[0] = '\0';
15930     *nativeErr = 0;
15931     *errlen = 0;
15932     return SQL_NO_DATA;
15933 }
15934 
15935 #ifndef WINTERFACE
15936 /**
15937  * Return last HDBC or HSTMT error message.
15938  * @param env environment handle or NULL
15939  * @param dbc database connection handle or NULL
15940  * @param stmt statement handle or NULL
15941  * @param sqlState output buffer for SQL state
15942  * @param nativeErr output buffer for native error code
15943  * @param errmsg output buffer for error message
15944  * @param errmax length of output buffer for error message
15945  * @param errlen output length of error message
15946  * @result ODBC error code
15947  */
15948 
15949 SQLRETURN SQL_API
SQLError(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)15950 SQLError(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
15951 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
15952 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
15953 {
15954     return drverror(env, dbc, stmt, sqlState, nativeErr,
15955 		    errmsg, errmax, errlen);
15956 }
15957 #endif
15958 
15959 #ifdef WINTERFACE
15960 /**
15961  * Return last HDBC or HSTMT error message (UNICODE version).
15962  * @param env environment handle or NULL
15963  * @param dbc database connection handle or NULL
15964  * @param stmt statement handle or NULL
15965  * @param sqlState output buffer for SQL state
15966  * @param nativeErr output buffer for native error code
15967  * @param errmsg output buffer for error message
15968  * @param errmax length of output buffer for error message
15969  * @param errlen output length of error message
15970  * @result ODBC error code
15971  */
15972 
15973 SQLRETURN SQL_API
SQLErrorW(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLWCHAR * sqlState,SQLINTEGER * nativeErr,SQLWCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)15974 SQLErrorW(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
15975 	  SQLWCHAR *sqlState, SQLINTEGER *nativeErr,
15976 	  SQLWCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
15977 {
15978     char state[16];
15979     SQLSMALLINT len = 0;
15980     SQLRETURN ret;
15981 
15982     ret = drverror(env, dbc, stmt, (SQLCHAR *) state, nativeErr,
15983 		   (SQLCHAR *) errmsg, errmax, &len);
15984     if (ret == SQL_SUCCESS) {
15985 	if (sqlState) {
15986 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlState,
15987 			    6 * sizeof (SQLWCHAR));
15988 	}
15989 	if (errmsg) {
15990 	    if (len > 0) {
15991 		SQLWCHAR *e = NULL;
15992 
15993 		e = uc_from_utf((SQLCHAR *) errmsg, len);
15994 		if (e) {
15995 		    if (errmax > 0) {
15996 			uc_strncpy(errmsg, e, errmax);
15997 			e[len] = 0;
15998 			len = min(errmax, uc_strlen(e));
15999 		    } else {
16000 			len = uc_strlen(e);
16001 		    }
16002 		    uc_free(e);
16003 		} else {
16004 		    len = 0;
16005 		}
16006 	    }
16007 	    if (len <= 0) {
16008 		len = 0;
16009 		if (errmax > 0) {
16010 		    errmsg[0] = 0;
16011 		}
16012 	    }
16013 	} else {
16014 	    len = 0;
16015 	}
16016 	if (errlen) {
16017 	    *errlen = len;
16018 	}
16019     } else if (ret == SQL_NO_DATA) {
16020 	if (sqlState) {
16021 	    sqlState[0] = 0;
16022 	}
16023 	if (errmsg) {
16024 	    if (errmax > 0) {
16025 		errmsg[0] = 0;
16026 	    }
16027 	}
16028 	if (errlen) {
16029 	    *errlen = 0;
16030 	}
16031     }
16032     return ret;
16033 }
16034 #endif
16035 
16036 /**
16037  * Return information for more result sets.
16038  * @param stmt statement handle
16039  * @result ODBC error code
16040  */
16041 
16042 SQLRETURN SQL_API
SQLMoreResults(SQLHSTMT stmt)16043 SQLMoreResults(SQLHSTMT stmt)
16044 {
16045     HSTMT_LOCK(stmt);
16046     if (stmt == SQL_NULL_HSTMT) {
16047 	return SQL_INVALID_HANDLE;
16048     }
16049     HSTMT_UNLOCK(stmt);
16050     return SQL_NO_DATA;
16051 }
16052 
16053 /**
16054  * Internal function to setup column name/type information
16055  * @param s statement poiner
16056  * @param s3stmt SQLite3 statement pointer
16057  * @param ncolsp pointer to preinitialized number of colums
16058  * @result ODBC error code
16059  */
16060 
16061 static SQLRETURN
setupdyncols(STMT * s,sqlite3_stmt * s3stmt,int * ncolsp)16062 setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp)
16063 {
16064     int ncols = *ncolsp, guessed_types = 0;
16065     SQLRETURN ret = SQL_SUCCESS;
16066 
16067     if (ncols > 0) {
16068 	int i;
16069 	PTRDIFF_T size;
16070 	char *p;
16071 	COL *dyncols;
16072 	DBC *d = (DBC *) s->dbc;
16073 	const char *colname, *typename;
16074 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
16075 	char *tblname;
16076 #endif
16077 
16078 	for (i = size = 0; i < ncols; i++) {
16079 	    colname = sqlite3_column_name(s3stmt, i);
16080 	    size += 3 + 3 * strlen(colname);
16081 	}
16082 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
16083 	tblname = (char *) size;
16084 	for (i = 0; i < ncols; i++) {
16085 	    p = (char *) sqlite3_column_table_name(s3stmt, i);
16086 	    size += 2 + (p ? strlen(p) : 0);
16087 	}
16088 #endif
16089 	dyncols = xmalloc(ncols * sizeof (COL) + size);
16090 	if (!dyncols) {
16091 	    freedyncols(s);
16092 	    *ncolsp = 0;
16093 	    ret = SQL_ERROR;
16094 	} else {
16095 	    p = (char *) (dyncols + ncols);
16096 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
16097 	    tblname = p + (PTRDIFF_T) tblname;
16098 #endif
16099 	    for (i = 0; i < ncols; i++) {
16100 		char *q;
16101 
16102 		colname = sqlite3_column_name(s3stmt, i);
16103 		if (d->trace) {
16104 		    fprintf(d->trace, "-- column %d name: '%s'\n",
16105 			    i + 1, colname);
16106 		    fflush(d->trace);
16107 		}
16108 #if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
16109 		q = (char *) sqlite3_column_table_name(s3stmt, i);
16110 		strcpy(tblname, q ? q : "");
16111 		if (d->trace) {
16112 		    fprintf(d->trace, "-- table %d name: '%s'\n",
16113 			    i + 1, tblname);
16114 		    fflush(d->trace);
16115 		}
16116 		dyncols[i].table = tblname;
16117 		tblname += strlen(tblname) + 1;
16118 #endif
16119 		typename = s3stmt_coltype(s3stmt, i, d, &guessed_types);
16120 		dyncols[i].db = ((DBC *) (s->dbc))->dbname;
16121 		strcpy(p, colname);
16122 		dyncols[i].label = p;
16123 		p += strlen(p) + 1;
16124 		q = strchr(colname, '.');
16125 		if (q) {
16126 		    char *q2 = strchr(q + 1, '.');
16127 
16128 		    /* SQLite 3.3.4 produces view.table.column sometimes */
16129 		    if (q2) {
16130 			q = q2;
16131 		    }
16132 		}
16133 		if (q) {
16134 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
16135 		    dyncols[i].table = p;
16136 #endif
16137 		    strncpy(p, colname, q - colname);
16138 		    p[q - colname] = '\0';
16139 		    p += strlen(p) + 1;
16140 		    strcpy(p, q + 1);
16141 		    dyncols[i].column = p;
16142 		    p += strlen(p) + 1;
16143 		} else {
16144 #if !defined(HAVE_SQLITE3COLUMNTABLENAME) || !(HAVE_SQLITE3COLUMNTABLENAME)
16145 		    dyncols[i].table = "";
16146 #endif
16147 		    strcpy(p, colname);
16148 		    dyncols[i].column = p;
16149 		    p += strlen(p) + 1;
16150 		}
16151 		if (s->longnames) {
16152 		    dyncols[i].column = dyncols[i].label;
16153 		}
16154 #ifdef SQL_LONGVARCHAR
16155 		dyncols[i].type = SQL_LONGVARCHAR;
16156 		dyncols[i].size = 65535;
16157 #else
16158 		dyncols[i].type = SQL_VARCHAR;
16159 		dyncols[i].size = 255;
16160 #endif
16161 		dyncols[i].index = i;
16162 		dyncols[i].scale = 0;
16163 		dyncols[i].prec = 0;
16164 		dyncols[i].nosign = 1;
16165 #if defined(HAVE_SQLITE3TABLECOLUMNMETADATA) && (HAVE_SQLITE3TABLECOLUMNMETADATA)
16166 		s3stmt_addmeta(s3stmt, i, d, &dyncols[i]);
16167 #else
16168 		dyncols[i].autoinc = SQL_FALSE;
16169 		dyncols[i].notnull = SQL_NULLABLE;
16170 #endif
16171 		dyncols[i].typename = xstrdup(typename);
16172 	    }
16173 	    freedyncols(s);
16174 	    s->dyncols = s->cols = dyncols;
16175 	    s->dcols = ncols;
16176 	    fixupdyncols(s, d);
16177 	    s->guessed_types = guessed_types;
16178 	}
16179     }
16180     return ret;
16181 }
16182 
16183 /**
16184  * Internal query preparation used by SQLPrepare() and SQLExecDirect().
16185  * @param stmt statement handle
16186  * @param query query string
16187  * @param queryLen length of query string or SQL_NTS
16188  * @result ODBC error code
16189  */
16190 
16191 static SQLRETURN
drvprepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)16192 drvprepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
16193 {
16194     STMT *s;
16195     DBC *d;
16196     char *errp = NULL;
16197     SQLRETURN sret;
16198 
16199     if (stmt == SQL_NULL_HSTMT) {
16200 	return SQL_INVALID_HANDLE;
16201     }
16202     s = (STMT *) stmt;
16203     if (s->dbc == SQL_NULL_HDBC) {
16204 noconn:
16205 	return noconn(s);
16206     }
16207     d = s->dbc;
16208     if (!d->sqlite) {
16209 	goto noconn;
16210     }
16211     s3stmt_end(s);
16212     s3stmt_drop(s);
16213     sret = starttran(s);
16214     if (sret != SQL_SUCCESS) {
16215 	return sret;
16216     }
16217     freep(&s->query);
16218     s->query = (SQLCHAR *) fixupsql((char *) query, queryLen,
16219 				    &s->nparams, &s->isselect, &errp);
16220     if (!s->query) {
16221 	if (errp) {
16222 	    setstat(s, -1, "%s", (*s->ov3) ? "HY000" : "S1000", errp);
16223 	    return SQL_ERROR;
16224 	}
16225 	return nomem(s);
16226     }
16227     errp = NULL;
16228     freeresult(s, -1);
16229     if (s->isselect > 0) {
16230 	int ret, ncols, nretry = 0;
16231 	const char *rest;
16232 	sqlite3_stmt *s3stmt = NULL;
16233 
16234 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
16235 	dbtraceapi(d, "sqlite3_prepare_v2", (char *) s->query);
16236 #else
16237 	dbtraceapi(d, "sqlite3_prepare", (char *) s->query);
16238 #endif
16239 	do {
16240 	    s3stmt = NULL;
16241 #if defined(HAVE_SQLITE3PREPAREV2) && (HAVE_SQLITE3PREPAREV2)
16242 	    ret = sqlite3_prepare_v2(d->sqlite, (char *) s->query, -1,
16243 				     &s3stmt, &rest);
16244 #else
16245 	    ret = sqlite3_prepare(d->sqlite, (char *) s->query, -1,
16246 				  &s3stmt, &rest);
16247 #endif
16248 	    if (ret != SQLITE_OK) {
16249 		if (s3stmt) {
16250 		    sqlite3_finalize(s3stmt);
16251 		    s3stmt = NULL;
16252 		}
16253 	    }
16254 	} while (ret == SQLITE_SCHEMA && (++nretry) < 2);
16255 	dbtracerc(d, ret, NULL);
16256 	if (ret != SQLITE_OK) {
16257 	    if (s3stmt) {
16258 		dbtraceapi(d, "sqlite3_finalize", 0);
16259 		sqlite3_finalize(s3stmt);
16260 	    }
16261 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
16262 		    sqlite3_errmsg(d->sqlite), ret);
16263 	    return SQL_ERROR;
16264 	}
16265 	if (sqlite3_bind_parameter_count(s3stmt) != s->nparams) {
16266 	    dbtraceapi(d, "sqlite3_finalize", 0);
16267 	    sqlite3_finalize(s3stmt);
16268 	    setstat(s, SQLITE_ERROR, "parameter marker count incorrect",
16269 		    (*s->ov3) ? "HY000" : "S1000");
16270 	    return SQL_ERROR;
16271 	}
16272 	ncols = sqlite3_column_count(s3stmt);
16273 	s->guessed_types = 0;
16274 	setupdyncols(s, s3stmt, &ncols);
16275 	s->ncols = ncols;
16276 	s->s3stmt = s3stmt;
16277     }
16278     mkbindcols(s, s->ncols);
16279     s->paramset_count = 0;
16280     return SQL_SUCCESS;
16281 }
16282 
16283 /**
16284  * Internal query execution used by SQLExecute() and SQLExecDirect().
16285  * @param stmt statement handle
16286  * @param initial false when called from SQLPutData()
16287  * @result ODBC error code
16288  */
16289 
16290 static SQLRETURN
drvexecute(SQLHSTMT stmt,int initial)16291 drvexecute(SQLHSTMT stmt, int initial)
16292 {
16293     STMT *s;
16294     DBC *d;
16295     char *errp = NULL;
16296     int rc, i, ncols = 0, nrows = 0, busy_count;
16297     SQLRETURN ret;
16298 
16299     if (stmt == SQL_NULL_HSTMT) {
16300 	return SQL_INVALID_HANDLE;
16301     }
16302     s = (STMT *) stmt;
16303     if (s->dbc == SQL_NULL_HDBC) {
16304 noconn:
16305 	return noconn(s);
16306     }
16307     d = (DBC *) s->dbc;
16308     if (!d->sqlite) {
16309 	goto noconn;
16310     }
16311     if (!s->query) {
16312 	setstat(s, -1, "no query prepared", (*s->ov3) ? "HY000" : "S1000");
16313 	return SQL_ERROR;
16314     }
16315     if (s->nbindparms < s->nparams) {
16316 unbound:
16317 	setstat(s, -1, "unbound parameters in query",
16318 		(*s->ov3) ? "HY000" : "S1000");
16319 	return SQL_ERROR;
16320     }
16321     for (i = 0; i < s->nparams; i++) {
16322 	BINDPARM *p = &s->bindparms[i];
16323 
16324 	if (!p->bound) {
16325 	    goto unbound;
16326 	}
16327 	if (initial) {
16328 	    SQLLEN *lenp = p->lenp;
16329 
16330 	    if (lenp && *lenp < 0 && *lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
16331 		*lenp != SQL_NTS && *lenp != SQL_NULL_DATA) {
16332 		setstat(s, -1, "invalid length reference", "HY009");
16333 		return SQL_ERROR;
16334 	    }
16335 	    if (lenp && *lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
16336 		p->need = 1;
16337 		p->offs = 0;
16338 		p->len = 0;
16339 	    }
16340 	}
16341     }
16342     ret = starttran(s);
16343     if (ret != SQL_SUCCESS) {
16344 	goto cleanup;
16345     }
16346     busy_count = 0;
16347 again:
16348     s3stmt_end(s);
16349     if (initial) {
16350 	/* fixup data-at-execution parameters and alloc'ed blobs */
16351 	for (i = 0; i < s->nparams; i++) {
16352 	    BINDPARM *p = &s->bindparms[i];
16353 
16354 	    if (p->param == p->parbuf) {
16355 		p->param = NULL;
16356 	    }
16357 	    freep(&p->parbuf);
16358 	    if (p->need <= 0 &&
16359 		p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
16360 		p->need = 1;
16361 		p->offs = 0;
16362 		p->len = 0;
16363 	    }
16364 	}
16365     }
16366     if (s->nparams) {
16367 	for (i = 0; i < s->nparams; i++) {
16368 	    ret = setupparam(s, (char *) s->query, i);
16369 	    if (ret != SQL_SUCCESS) {
16370 		goto cleanup;
16371 	    }
16372 	}
16373     }
16374     freeresult(s, 0);
16375     if (s->isselect > 0 && !d->intrans &&
16376 	s->curtype == SQL_CURSOR_FORWARD_ONLY &&
16377 	d->step_enable && s->nparams == 0 && d->cur_s3stmt == NULL) {
16378 	s->nrows = -1;
16379 	ret = s3stmt_start(s);
16380 	if (ret == SQL_SUCCESS) {
16381 	    goto done2;
16382 	}
16383     }
16384     rc = drvgettable(s, s->s3stmt ? NULL : (char *) s->query, &s->rows,
16385 		     &s->nrows, &ncols, &errp, s->nparams, s->bindparms);
16386     dbtracerc(d, rc, errp);
16387     if (rc == SQLITE_BUSY) {
16388 	if (busy_handler((void *) d, ++busy_count)) {
16389 	    if (errp) {
16390 		sqlite3_free(errp);
16391 		errp = NULL;
16392 	    }
16393 	    for (i = 0; i < s->nparams; i++) {
16394 		BINDPARM *p = &s->bindparms[i];
16395 
16396 		if (p->param == p->parbuf) {
16397 		    p->param = NULL;
16398 		}
16399 		freep(&p->parbuf);
16400 		if (!p->lenp || *p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET) {
16401 		    p->param = p->param0;
16402 		}
16403 		p->lenp = p->lenp0;
16404 	    }
16405 	    s->nrows = 0;
16406 	    goto again;
16407 	}
16408     }
16409     if (rc != SQLITE_OK) {
16410 	setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
16411 		errp ? errp : "unknown error", rc);
16412 	if (errp) {
16413 	    sqlite3_free(errp);
16414 	    errp = NULL;
16415 	}
16416 	ret = SQL_ERROR;
16417 	goto cleanup;
16418     }
16419     if (errp) {
16420 	sqlite3_free(errp);
16421 	errp = NULL;
16422     }
16423     s->rowfree = freerows;
16424     if (!s->isselect) {
16425 	/*
16426 	 * INSERT/UPDATE/DELETE results are immediately released.
16427 	 */
16428 	freeresult(s, -1);
16429 	nrows += sqlite3_changes(d->sqlite);
16430 	s->nrows = nrows;
16431 	goto done;
16432     }
16433     if (s->ncols != ncols) {
16434 	/*
16435 	 * Weird result.
16436 	 */
16437 	setstat(s, -1, "broken result set %d/%d",
16438 		(*s->ov3) ? "HY000" : "S1000", s->ncols, ncols);
16439 	ret = SQL_ERROR;
16440 	goto cleanup;
16441     }
16442 done:
16443     mkbindcols(s, s->ncols);
16444 done2:
16445     ret = SQL_SUCCESS;
16446     s->rowp = -1;
16447     s->paramset_count++;
16448     s->paramset_nrows = s->nrows;
16449     if (s->paramset_count < s->paramset_size) {
16450 	for (i = 0; i < s->nparams; i++) {
16451 	    BINDPARM *p = &s->bindparms[i];
16452 
16453 	    if (p->param == p->parbuf) {
16454 		p->param = NULL;
16455 	    }
16456 	    freep(&p->parbuf);
16457 	    if (p->lenp0 &&
16458 		s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
16459 		p->lenp = (SQLLEN *) ((char *) p->lenp0 +
16460 				      s->paramset_count * s->parm_bind_type);
16461 	    } else if (p->lenp0 && p->inc > 0) {
16462 		p->lenp = p->lenp0 + s->paramset_count;
16463 	    }
16464 	    if (!p->lenp || *p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET) {
16465 		if (p->param0 &&
16466 		    s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
16467 		    p->param = (char *) p->param0 +
16468 			s->paramset_count * s->parm_bind_type;
16469 		} else if (p->param0 && p->inc > 0) {
16470 		    p->param = (char *) p->param0 +
16471 			s->paramset_count * p->inc;
16472 		}
16473 	    } else if (p->lenp && *p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
16474 		p->need = 1;
16475 		p->offs = 0;
16476 		p->len = 0;
16477 	    }
16478 	}
16479 	goto again;
16480     }
16481 cleanup:
16482     if (ret != SQL_NEED_DATA) {
16483 	for (i = 0; i < s->nparams; i++) {
16484 	    BINDPARM *p = &s->bindparms[i];
16485 
16486 	    if (p->param == p->parbuf) {
16487 		p->param = NULL;
16488 	    }
16489 	    freep(&p->parbuf);
16490 	    if (!p->lenp || *p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET) {
16491 		p->param = p->param0;
16492 	    }
16493 	    p->lenp = p->lenp0;
16494 	}
16495 	s->nrows = s->paramset_nrows;
16496 	if (s->parm_proc) {
16497 	    *s->parm_proc = s->paramset_count;
16498 	}
16499 	s->paramset_count = 0;
16500 	s->paramset_nrows = 0;
16501     }
16502     if (*s->ov3 && !s->isselect && ret == SQL_SUCCESS && nrows == 0) {
16503 	ret = SQL_NO_DATA;
16504     }
16505     return ret;
16506 }
16507 
16508 #ifndef WINTERFACE
16509 /**
16510  * Prepare HSTMT.
16511  * @param stmt statement handle
16512  * @param query query string
16513  * @param queryLen length of query string or SQL_NTS
16514  * @result ODBC error code
16515  */
16516 
16517 SQLRETURN SQL_API
SQLPrepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)16518 SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
16519 {
16520     SQLRETURN ret;
16521 #if defined(_WIN32) || defined(_WIN64)
16522     char *q;
16523 #endif
16524 
16525     HSTMT_LOCK(stmt);
16526 #if defined(_WIN32) || defined(_WIN64)
16527     if (!((STMT *) stmt)->oemcp[0]) {
16528 	ret = drvprepare(stmt, query, queryLen);
16529 	goto done;
16530     }
16531     q = wmb_to_utf_c((char *) query, queryLen);
16532     if (!q) {
16533 	ret = nomem((STMT *) stmt);
16534 	goto done;
16535     }
16536     query = (SQLCHAR *) q;
16537     queryLen = SQL_NTS;
16538 #endif
16539     ret = drvprepare(stmt, query, queryLen);
16540 #if defined(_WIN32) || defined(_WIN64)
16541     uc_free(q);
16542 done:
16543     ;
16544 #endif
16545     HSTMT_UNLOCK(stmt);
16546     return ret;
16547 }
16548 #endif
16549 
16550 #ifdef WINTERFACE
16551 /**
16552  * Prepare HSTMT (UNICODE version).
16553  * @param stmt statement handle
16554  * @param query query string
16555  * @param queryLen length of query string or SQL_NTS
16556  * @result ODBC error code
16557  */
16558 
16559 SQLRETURN SQL_API
SQLPrepareW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)16560 SQLPrepareW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
16561 {
16562     SQLRETURN ret;
16563     char *q = uc_to_utf_c(query, queryLen);
16564 
16565     HSTMT_LOCK(stmt);
16566     if (!q) {
16567 	ret = nomem((STMT *) stmt);
16568 	goto done;
16569     }
16570     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
16571     uc_free(q);
16572 done:
16573     HSTMT_UNLOCK(stmt);
16574     return ret;
16575 }
16576 #endif
16577 
16578 /**
16579  * Execute query.
16580  * @param stmt statement handle
16581  * @result ODBC error code
16582  */
16583 
16584 SQLRETURN SQL_API
SQLExecute(SQLHSTMT stmt)16585 SQLExecute(SQLHSTMT stmt)
16586 {
16587     SQLRETURN ret;
16588 
16589     HSTMT_LOCK(stmt);
16590     ret = drvexecute(stmt, 1);
16591     HSTMT_UNLOCK(stmt);
16592     return ret;
16593 }
16594 
16595 #ifndef WINTERFACE
16596 /**
16597  * Execute query directly.
16598  * @param stmt statement handle
16599  * @param query query string
16600  * @param queryLen length of query string or SQL_NTS
16601  * @result ODBC error code
16602  */
16603 
16604 SQLRETURN SQL_API
SQLExecDirect(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)16605 SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
16606 {
16607     SQLRETURN ret;
16608 #if defined(_WIN32) || defined(_WIN64)
16609     char *q;
16610 #endif
16611 
16612     HSTMT_LOCK(stmt);
16613 #if defined(_WIN32) || defined(_WIN64)
16614     if (!((STMT *) stmt)->oemcp[0]) {
16615 	ret = drvprepare(stmt, query, queryLen);
16616 	if (ret == SQL_SUCCESS) {
16617 	    ret = drvexecute(stmt, 1);
16618 	}
16619 	goto done;
16620     }
16621     q = wmb_to_utf_c((char *) query, queryLen);
16622     if (!q) {
16623 	ret = nomem((STMT *) stmt);
16624 	goto done;
16625     }
16626     query = (SQLCHAR *) q;
16627     queryLen = SQL_NTS;
16628 #endif
16629     ret = drvprepare(stmt, query, queryLen);
16630     if (ret == SQL_SUCCESS) {
16631 	ret = drvexecute(stmt, 1);
16632     }
16633 #if defined(_WIN32) || defined(_WIN64)
16634     uc_free(q);
16635 done:
16636     ;
16637 #endif
16638     HSTMT_UNLOCK(stmt);
16639     return ret;
16640 }
16641 #endif
16642 
16643 #ifdef WINTERFACE
16644 /**
16645  * Execute query directly (UNICODE version).
16646  * @param stmt statement handle
16647  * @param query query string
16648  * @param queryLen length of query string or SQL_NTS
16649  * @result ODBC error code
16650  */
16651 
16652 SQLRETURN SQL_API
SQLExecDirectW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)16653 SQLExecDirectW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
16654 {
16655     SQLRETURN ret;
16656     char *q = uc_to_utf_c(query, queryLen);
16657 
16658     HSTMT_LOCK(stmt);
16659     if (!q) {
16660 	ret = nomem((STMT *) stmt);
16661 	goto done;
16662     }
16663     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
16664     uc_free(q);
16665     if (ret == SQL_SUCCESS) {
16666 	ret = drvexecute(stmt, 1);
16667     }
16668 done:
16669     HSTMT_UNLOCK(stmt);
16670     return ret;
16671 }
16672 #endif
16673 
16674 
16675 #if defined(_WIN32) || defined(_WIN64)
16676 #ifndef WITHOUT_DRIVERMGR
16677 
16678 /*
16679  * Windows configuration dialog stuff.
16680  */
16681 
16682 #include <windowsx.h>
16683 #include <winuser.h>
16684 
16685 #define MAXPATHLEN      (255+1)           /* Max path length */
16686 #define MAXKEYLEN       (15+1)            /* Max keyword length */
16687 #define MAXDESC         (255+1)           /* Max description length */
16688 #define MAXDSNAME       (32+1)            /* Max data source name length */
16689 #define MAXTONAME       (32+1)            /* Max timeout length */
16690 #define MAXDBNAME	(255+1)
16691 
16692 /* Attribute key indexes into an array of Attr structs, see below */
16693 
16694 #define KEY_DSN 		0
16695 #define KEY_DESC		1
16696 #define KEY_DBNAME		2
16697 #define KEY_BUSY		3
16698 #define KEY_DRIVER		4
16699 #define KEY_STEPAPI		5
16700 #define KEY_SYNCP		6
16701 #define KEY_NOTXN		7
16702 #define KEY_SHORTNAM		8
16703 #define KEY_LONGNAM		9
16704 #define KEY_NOCREAT	       10
16705 #define KEY_NOWCHAR	       11
16706 #define KEY_LOADEXT	       12
16707 #define KEY_JMODE              13
16708 #define KEY_FKSUPPORT          14
16709 #define KEY_OEMCP              15
16710 #define KEY_BIGINT             16
16711 #define KEY_PASSWD             17
16712 #define NUMOFKEYS	       18
16713 
16714 typedef struct {
16715     BOOL supplied;
16716     char attr[MAXPATHLEN*4];
16717 } ATTR;
16718 
16719 typedef struct {
16720     SQLHWND parent;
16721     LPCSTR  driver;
16722     ATTR    attr[NUMOFKEYS];
16723     char    DSN[MAXDSNAME];
16724     BOOL    newDSN;
16725     BOOL    defDSN;
16726 } SETUPDLG;
16727 
16728 static struct {
16729     char *key;
16730     int ikey;
16731 } attrLookup[] = {
16732     { "DSN", KEY_DSN },
16733     { "DESC", KEY_DESC },
16734     { "Description", KEY_DESC},
16735     { "Database", KEY_DBNAME },
16736     { "Timeout", KEY_BUSY },
16737     { "Driver", KEY_DRIVER },
16738     { "StepAPI", KEY_STEPAPI },
16739     { "SyncPragma", KEY_SYNCP },
16740     { "NoTXN", KEY_NOTXN },
16741     { "ShortNames", KEY_SHORTNAM },
16742     { "LongNames", KEY_LONGNAM },
16743     { "NoCreat", KEY_NOCREAT },
16744     { "NoWCHAR", KEY_NOWCHAR },
16745     { "LoadExt", KEY_LOADEXT },
16746     { "JournalMode", KEY_JMODE },
16747     { "FKSupport", KEY_FKSUPPORT },
16748     { "OEMCP", KEY_OEMCP },
16749     { "BigInt", KEY_BIGINT },
16750     { "PWD", KEY_PASSWD },
16751     { NULL, 0 }
16752 };
16753 
16754 /**
16755  * Setup dialog data from datasource attributes.
16756  * @param attribs attribute string
16757  * @param setupdlg pointer to dialog data
16758  */
16759 
16760 static void
ParseAttributes(LPCSTR attribs,SETUPDLG * setupdlg)16761 ParseAttributes(LPCSTR attribs, SETUPDLG *setupdlg)
16762 {
16763     char *str = (char *) attribs, *start, key[MAXKEYLEN];
16764     int elem, nkey;
16765 
16766     while (*str) {
16767 	start = str;
16768 	if ((str = strchr(str, '=')) == NULL) {
16769 	    return;
16770 	}
16771 	elem = -1;
16772 	nkey = str - start;
16773 	if (nkey < sizeof (key)) {
16774 	    int i;
16775 
16776 	    memcpy(key, start, nkey);
16777 	    key[nkey] = '\0';
16778 	    for (i = 0; attrLookup[i].key; i++) {
16779 		if (strcasecmp(attrLookup[i].key, key) == 0) {
16780 		    elem = attrLookup[i].ikey;
16781 		    break;
16782 		}
16783 	    }
16784 	}
16785 	start = ++str;
16786 	while (*str && *str != ';') {
16787 	    ++str;
16788 	}
16789 	if (elem >= 0) {
16790 	    int end = min(str - start, sizeof (setupdlg->attr[elem].attr) - 1);
16791 
16792 	    setupdlg->attr[elem].supplied = TRUE;
16793 	    memcpy(setupdlg->attr[elem].attr, start, end);
16794 	    setupdlg->attr[elem].attr[end] = '\0';
16795 	}
16796 	++str;
16797     }
16798 }
16799 
16800 /**
16801  * Set datasource attributes in registry.
16802  * @param parent handle of parent window
16803  * @param setupdlg pointer to dialog data
16804  * @result true or false
16805  */
16806 
16807 static BOOL
SetDSNAttributes(HWND parent,SETUPDLG * setupdlg)16808 SetDSNAttributes(HWND parent, SETUPDLG *setupdlg)
16809 {
16810     char *dsn = setupdlg->attr[KEY_DSN].attr;
16811 
16812     if (setupdlg->newDSN && strlen(dsn) == 0) {
16813 	return FALSE;
16814     }
16815     if (!SQLWriteDSNToIni(dsn, setupdlg->driver)) {
16816 	if (parent) {
16817 	    char buf[MAXPATHLEN], msg[MAXPATHLEN];
16818 
16819 	    LoadString(hModule, IDS_BADDSN, buf, sizeof (buf));
16820 	    wsprintf(msg, buf, dsn);
16821 	    LoadString(hModule, IDS_MSGTITLE, buf, sizeof (buf));
16822 	    MessageBox(parent, msg, buf,
16823 		       MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
16824 		       MB_SETFOREGROUND);
16825 	}
16826 	return FALSE;
16827     }
16828     if (parent || setupdlg->attr[KEY_DESC].supplied) {
16829 	SQLWritePrivateProfileString(dsn, "Description",
16830 				     setupdlg->attr[KEY_DESC].attr,
16831 				     ODBC_INI);
16832     }
16833     if (parent || setupdlg->attr[KEY_DBNAME].supplied) {
16834 	SQLWritePrivateProfileString(dsn, "Database",
16835 				     setupdlg->attr[KEY_DBNAME].attr,
16836 				     ODBC_INI);
16837     }
16838     if (parent || setupdlg->attr[KEY_BUSY].supplied) {
16839 	SQLWritePrivateProfileString(dsn, "Timeout",
16840 				     setupdlg->attr[KEY_BUSY].attr,
16841 				     ODBC_INI);
16842     }
16843     if (parent || setupdlg->attr[KEY_STEPAPI].supplied) {
16844 	SQLWritePrivateProfileString(dsn, "StepAPI",
16845 				     setupdlg->attr[KEY_STEPAPI].attr,
16846 				     ODBC_INI);
16847     }
16848     if (parent || setupdlg->attr[KEY_SYNCP].supplied) {
16849 	SQLWritePrivateProfileString(dsn, "SyncPragma",
16850 				     setupdlg->attr[KEY_SYNCP].attr,
16851 				     ODBC_INI);
16852     }
16853     if (parent || setupdlg->attr[KEY_NOTXN].supplied) {
16854 	SQLWritePrivateProfileString(dsn, "NoTXN",
16855 				     setupdlg->attr[KEY_NOTXN].attr,
16856 				     ODBC_INI);
16857     }
16858     if (parent || setupdlg->attr[KEY_SHORTNAM].supplied) {
16859 	SQLWritePrivateProfileString(dsn, "ShortNames",
16860 				     setupdlg->attr[KEY_SHORTNAM].attr,
16861 				     ODBC_INI);
16862     }
16863     if (parent || setupdlg->attr[KEY_LONGNAM].supplied) {
16864 	SQLWritePrivateProfileString(dsn, "LongNames",
16865 				     setupdlg->attr[KEY_LONGNAM].attr,
16866 				     ODBC_INI);
16867     }
16868     if (parent || setupdlg->attr[KEY_NOCREAT].supplied) {
16869 	SQLWritePrivateProfileString(dsn, "NoCreat",
16870 				     setupdlg->attr[KEY_NOCREAT].attr,
16871 				     ODBC_INI);
16872     }
16873     if (parent || setupdlg->attr[KEY_NOWCHAR].supplied) {
16874 	SQLWritePrivateProfileString(dsn, "NoWCHAR",
16875 				     setupdlg->attr[KEY_NOWCHAR].attr,
16876 				     ODBC_INI);
16877     }
16878     if (parent || setupdlg->attr[KEY_FKSUPPORT].supplied) {
16879 	SQLWritePrivateProfileString(dsn, "FKSupport",
16880 				     setupdlg->attr[KEY_FKSUPPORT].attr,
16881 				     ODBC_INI);
16882     }
16883     if (parent || setupdlg->attr[KEY_OEMCP].supplied) {
16884 	SQLWritePrivateProfileString(dsn, "OEMCP",
16885 				     setupdlg->attr[KEY_OEMCP].attr,
16886 				     ODBC_INI);
16887     }
16888     if (parent || setupdlg->attr[KEY_LOADEXT].supplied) {
16889 	SQLWritePrivateProfileString(dsn, "LoadExt",
16890 				     setupdlg->attr[KEY_LOADEXT].attr,
16891 				     ODBC_INI);
16892     }
16893     if (parent || setupdlg->attr[KEY_BIGINT].supplied) {
16894 	SQLWritePrivateProfileString(dsn, "BigInt",
16895 				     setupdlg->attr[KEY_BIGINT].attr,
16896 				     ODBC_INI);
16897     }
16898     if (parent || setupdlg->attr[KEY_PASSWD].supplied) {
16899 	SQLWritePrivateProfileString(dsn, "PWD",
16900 				     setupdlg->attr[KEY_PASSWD].attr,
16901 				     ODBC_INI);
16902     }
16903     if (setupdlg->attr[KEY_DSN].supplied &&
16904 	strcasecmp(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr)) {
16905 	SQLRemoveDSNFromIni(setupdlg->DSN);
16906     }
16907     return TRUE;
16908 }
16909 
16910 /**
16911  * Get datasource attributes from registry.
16912  * @param setupdlg pointer to dialog data
16913  */
16914 
16915 static void
GetAttributes(SETUPDLG * setupdlg)16916 GetAttributes(SETUPDLG *setupdlg)
16917 {
16918     char *dsn = setupdlg->attr[KEY_DSN].attr;
16919 
16920     if (!setupdlg->attr[KEY_DESC].supplied) {
16921 	SQLGetPrivateProfileString(dsn, "Description", "",
16922 				   setupdlg->attr[KEY_DESC].attr,
16923 				   sizeof (setupdlg->attr[KEY_DESC].attr),
16924 				   ODBC_INI);
16925     }
16926     if (!setupdlg->attr[KEY_DBNAME].supplied) {
16927 	SQLGetPrivateProfileString(dsn, "Database", "",
16928 				   setupdlg->attr[KEY_DBNAME].attr,
16929 				   sizeof (setupdlg->attr[KEY_DBNAME].attr),
16930 				   ODBC_INI);
16931     }
16932     if (!setupdlg->attr[KEY_BUSY].supplied) {
16933 	SQLGetPrivateProfileString(dsn, "Timeout", "100000",
16934 				   setupdlg->attr[KEY_BUSY].attr,
16935 				   sizeof (setupdlg->attr[KEY_BUSY].attr),
16936 				   ODBC_INI);
16937     }
16938     if (!setupdlg->attr[KEY_STEPAPI].supplied) {
16939 	SQLGetPrivateProfileString(dsn, "StepAPI", "0",
16940 				   setupdlg->attr[KEY_STEPAPI].attr,
16941 				   sizeof (setupdlg->attr[KEY_STEPAPI].attr),
16942 				   ODBC_INI);
16943     }
16944     if (!setupdlg->attr[KEY_SYNCP].supplied) {
16945 	SQLGetPrivateProfileString(dsn, "SyncPragma", "NORMAL",
16946 				   setupdlg->attr[KEY_SYNCP].attr,
16947 				   sizeof (setupdlg->attr[KEY_SYNCP].attr),
16948 				   ODBC_INI);
16949     }
16950     if (!setupdlg->attr[KEY_NOTXN].supplied) {
16951 	SQLGetPrivateProfileString(dsn, "NoTXN", "",
16952 				   setupdlg->attr[KEY_NOTXN].attr,
16953 				   sizeof (setupdlg->attr[KEY_NOTXN].attr),
16954 				   ODBC_INI);
16955     }
16956     if (!setupdlg->attr[KEY_SHORTNAM].supplied) {
16957 	SQLGetPrivateProfileString(dsn, "ShortNames", "",
16958 				   setupdlg->attr[KEY_SHORTNAM].attr,
16959 				   sizeof (setupdlg->attr[KEY_SHORTNAM].attr),
16960 				   ODBC_INI);
16961     }
16962     if (!setupdlg->attr[KEY_LONGNAM].supplied) {
16963 	SQLGetPrivateProfileString(dsn, "LongNames", "",
16964 				   setupdlg->attr[KEY_LONGNAM].attr,
16965 				   sizeof (setupdlg->attr[KEY_LONGNAM].attr),
16966 				   ODBC_INI);
16967     }
16968     if (!setupdlg->attr[KEY_NOCREAT].supplied) {
16969 	SQLGetPrivateProfileString(dsn, "NoCreat", "",
16970 				   setupdlg->attr[KEY_NOCREAT].attr,
16971 				   sizeof (setupdlg->attr[KEY_NOCREAT].attr),
16972 				   ODBC_INI);
16973     }
16974     if (!setupdlg->attr[KEY_NOWCHAR].supplied) {
16975 	SQLGetPrivateProfileString(dsn, "NoWCHAR", "",
16976 				   setupdlg->attr[KEY_NOWCHAR].attr,
16977 				   sizeof (setupdlg->attr[KEY_NOWCHAR].attr),
16978 				   ODBC_INI);
16979     }
16980     if (!setupdlg->attr[KEY_FKSUPPORT].supplied) {
16981 	SQLGetPrivateProfileString(dsn, "FKSupport", "",
16982 				   setupdlg->attr[KEY_FKSUPPORT].attr,
16983 				   sizeof (setupdlg->attr[KEY_FKSUPPORT].attr),
16984 				   ODBC_INI);
16985     }
16986     if (!setupdlg->attr[KEY_OEMCP].supplied) {
16987 	SQLGetPrivateProfileString(dsn, "OEMCP", "",
16988 				   setupdlg->attr[KEY_OEMCP].attr,
16989 				   sizeof (setupdlg->attr[KEY_OEMCP].attr),
16990 				   ODBC_INI);
16991     }
16992     if (!setupdlg->attr[KEY_LOADEXT].supplied) {
16993 	SQLGetPrivateProfileString(dsn, "LoadExt", "",
16994 				   setupdlg->attr[KEY_LOADEXT].attr,
16995 				   sizeof (setupdlg->attr[KEY_LOADEXT].attr),
16996 				   ODBC_INI);
16997     }
16998     if (!setupdlg->attr[KEY_JMODE].supplied) {
16999 	SQLGetPrivateProfileString(dsn, "JournalMode", "",
17000 				   setupdlg->attr[KEY_JMODE].attr,
17001 				   sizeof (setupdlg->attr[KEY_JMODE].attr),
17002 				   ODBC_INI);
17003     }
17004     if (!setupdlg->attr[KEY_BIGINT].supplied) {
17005 	SQLGetPrivateProfileString(dsn, "BigInt", "",
17006 				   setupdlg->attr[KEY_BIGINT].attr,
17007 				   sizeof (setupdlg->attr[KEY_BIGINT].attr),
17008 				   ODBC_INI);
17009     }
17010     if (!setupdlg->attr[KEY_PASSWD].supplied) {
17011 	SQLGetPrivateProfileString(dsn, "PWD", "",
17012 				   setupdlg->attr[KEY_PASSWD].attr,
17013 				   sizeof (setupdlg->attr[KEY_PASSWD].attr),
17014 				   ODBC_INI);
17015     }
17016 }
17017 
17018 /**
17019  * Open file dialog for selection of SQLite database file.
17020  * @param hdlg handle of originating dialog window
17021  */
17022 
17023 static void
GetDBFile(HWND hdlg)17024 GetDBFile(HWND hdlg)
17025 {
17026 #ifdef _WIN64
17027     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
17028 #else
17029     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
17030 #endif
17031     OPENFILENAME ofn;
17032 
17033     memset(&ofn, 0, sizeof (ofn));
17034     ofn.lStructSize = sizeof (ofn);
17035     ofn.hwndOwner = hdlg;
17036 #ifdef _WIN64
17037     ofn.hInstance = (HINSTANCE) GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
17038 #else
17039     ofn.hInstance = (HINSTANCE) GetWindowLong(hdlg, GWL_HINSTANCE);
17040 #endif
17041     ofn.lpstrFile = (LPTSTR) setupdlg->attr[KEY_DBNAME].attr;
17042     ofn.nMaxFile = MAXPATHLEN;
17043     ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
17044 		OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_FILEMUSTEXIST;
17045     if (GetOpenFileName(&ofn)) {
17046 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
17047 	setupdlg->attr[KEY_DBNAME].supplied = TRUE;
17048     }
17049 }
17050 
17051 /**
17052  * Dialog procedure for ConfigDSN().
17053  * @param hdlg handle of dialog window
17054  * @param wmsg type of message
17055  * @param wparam wparam of message
17056  * @param lparam lparam of message
17057  * @result true or false
17058  */
17059 
17060 static BOOL CALLBACK
ConfigDlgProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)17061 ConfigDlgProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
17062 {
17063     SETUPDLG *setupdlg = NULL;
17064     WORD index;
17065 
17066     switch (wmsg) {
17067     case WM_INITDIALOG:
17068 #ifdef _WIN64
17069 	SetWindowLong(hdlg, DWLP_USER, lparam);
17070 #else
17071 	SetWindowLong(hdlg, DWL_USER, lparam);
17072 #endif
17073 	setupdlg = (SETUPDLG *) lparam;
17074 	GetAttributes(setupdlg);
17075 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
17076 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
17077 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
17078 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
17079 	SetDlgItemText(hdlg, IDC_LOADEXT, setupdlg->attr[KEY_LOADEXT].attr);
17080 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
17081 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
17082 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
17083 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
17084 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
17085 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
17086 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
17087 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
17088 	SendDlgItemMessage(hdlg, IDC_LOADEXT, EM_LIMITTEXT,
17089 			   (WPARAM) (MAXPATHLEN*4 - 1), (LPARAM) 0);
17090 	CheckDlgButton(hdlg, IDC_STEPAPI,
17091 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
17092 		       BST_CHECKED : BST_UNCHECKED);
17093 	CheckDlgButton(hdlg, IDC_NOTXN,
17094 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
17095 		       BST_CHECKED : BST_UNCHECKED);
17096 	CheckDlgButton(hdlg, IDC_SHORTNAM,
17097 		       getbool(setupdlg->attr[KEY_SHORTNAM].attr) ?
17098 		       BST_CHECKED : BST_UNCHECKED);
17099 	CheckDlgButton(hdlg, IDC_LONGNAM,
17100 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
17101 		       BST_CHECKED : BST_UNCHECKED);
17102 	CheckDlgButton(hdlg, IDC_NOCREAT,
17103 		       getbool(setupdlg->attr[KEY_NOCREAT].attr) ?
17104 		       BST_CHECKED : BST_UNCHECKED);
17105 	CheckDlgButton(hdlg, IDC_NOWCHAR,
17106 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
17107 		       BST_CHECKED : BST_UNCHECKED);
17108 	CheckDlgButton(hdlg, IDC_FKSUPPORT,
17109 		       getbool(setupdlg->attr[KEY_FKSUPPORT].attr) ?
17110 		       BST_CHECKED : BST_UNCHECKED);
17111 	CheckDlgButton(hdlg, IDC_OEMCP,
17112 		       getbool(setupdlg->attr[KEY_OEMCP].attr) ?
17113 		       BST_CHECKED : BST_UNCHECKED);
17114 	CheckDlgButton(hdlg, IDC_BIGINT,
17115 		       getbool(setupdlg->attr[KEY_BIGINT].attr) ?
17116 		       BST_CHECKED : BST_UNCHECKED);
17117 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17118 			   CB_LIMITTEXT, (WPARAM) 10, (LPARAM) 0);
17119 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17120 			   CB_ADDSTRING, 0, (LPARAM) "NORMAL");
17121 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17122 			   CB_ADDSTRING, 0, (LPARAM) "OFF");
17123 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17124 			   CB_ADDSTRING, 0, (LPARAM) "FULL");
17125 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17126 			   CB_SELECTSTRING, (WPARAM) -1,
17127 			   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
17128 	if (setupdlg->defDSN) {
17129 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
17130 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
17131 	}
17132 	return TRUE;
17133     case WM_COMMAND:
17134 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
17135 	case IDC_DSNAME:
17136 	    if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) {
17137 		char item[MAXDSNAME];
17138 
17139 		EnableWindow(GetDlgItem(hdlg, IDOK),
17140 			     GetDlgItemText(hdlg, IDC_DSNAME,
17141 					    item, sizeof (item)));
17142 		return TRUE;
17143 	    }
17144 	    break;
17145 	case IDC_BROWSE:
17146 	    GetDBFile(hdlg);
17147 	    break;
17148 	case IDOK:
17149 #ifdef _WIN64
17150 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
17151 #else
17152 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
17153 #endif
17154 	    if (!setupdlg->defDSN) {
17155 		GetDlgItemText(hdlg, IDC_DSNAME,
17156 			       setupdlg->attr[KEY_DSN].attr,
17157 			       sizeof (setupdlg->attr[KEY_DSN].attr));
17158 	    }
17159 	    GetDlgItemText(hdlg, IDC_DESC,
17160 			   setupdlg->attr[KEY_DESC].attr,
17161 			   sizeof (setupdlg->attr[KEY_DESC].attr));
17162 	    GetDlgItemText(hdlg, IDC_DBNAME,
17163 			   setupdlg->attr[KEY_DBNAME].attr,
17164 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
17165 	    GetDlgItemText(hdlg, IDC_TONAME,
17166 			   setupdlg->attr[KEY_BUSY].attr,
17167 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
17168 	    GetDlgItemText(hdlg, IDC_LOADEXT,
17169 			   setupdlg->attr[KEY_LOADEXT].attr,
17170 			   sizeof (setupdlg->attr[KEY_LOADEXT].attr));
17171 	    index = SendDlgItemMessage(hdlg, IDC_SYNCP,
17172 				       CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
17173 	    if (index != (WORD) CB_ERR) {
17174 		SendDlgItemMessage(hdlg, IDC_SYNCP,
17175 				   CB_GETLBTEXT, index,
17176 				   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
17177 	    }
17178 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
17179 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
17180 		   "1" : "0");
17181 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
17182 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
17183 		   "1" : "0");
17184 	    strcpy(setupdlg->attr[KEY_SHORTNAM].attr,
17185 		   (IsDlgButtonChecked(hdlg, IDC_SHORTNAM) == BST_CHECKED) ?
17186 		   "1" : "0");
17187 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
17188 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
17189 		   "1" : "0");
17190 	    strcpy(setupdlg->attr[KEY_NOCREAT].attr,
17191 		   (IsDlgButtonChecked(hdlg, IDC_NOCREAT) == BST_CHECKED) ?
17192 		   "1" : "0");
17193 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
17194 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
17195 		   "1" : "0");
17196 	    strcpy(setupdlg->attr[KEY_FKSUPPORT].attr,
17197 		   (IsDlgButtonChecked(hdlg, IDC_FKSUPPORT) == BST_CHECKED) ?
17198 		   "1" : "0");
17199 	    strcpy(setupdlg->attr[KEY_OEMCP].attr,
17200 		   (IsDlgButtonChecked(hdlg, IDC_OEMCP) == BST_CHECKED) ?
17201 		   "1" : "0");
17202 	    strcpy(setupdlg->attr[KEY_BIGINT].attr,
17203 		   (IsDlgButtonChecked(hdlg, IDC_BIGINT) == BST_CHECKED) ?
17204 		   "1" : "0");
17205 	    SetDSNAttributes(hdlg, setupdlg);
17206 	    /* FALL THROUGH */
17207 	case IDCANCEL:
17208 	    EndDialog(hdlg, wparam);
17209 	    return TRUE;
17210 	}
17211 	break;
17212     }
17213     return FALSE;
17214 }
17215 
17216 /**
17217  * ODBC INSTAPI procedure for DSN configuration.
17218  * @param hwnd parent window handle
17219  * @param request type of request
17220  * @param driver driver name
17221  * @param attribs attribute string of DSN
17222  * @result true or false
17223  */
17224 
17225 BOOL INSTAPI
ConfigDSN(HWND hwnd,WORD request,LPCSTR driver,LPCSTR attribs)17226 ConfigDSN(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attribs)
17227 {
17228     BOOL success;
17229     SETUPDLG *setupdlg;
17230 
17231     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
17232     if (setupdlg == NULL) {
17233 	return FALSE;
17234     }
17235     memset(setupdlg, 0, sizeof (SETUPDLG));
17236     if (attribs) {
17237 	ParseAttributes(attribs, setupdlg);
17238     }
17239     if (setupdlg->attr[KEY_DSN].supplied) {
17240 	strcpy(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr);
17241     } else {
17242 	setupdlg->DSN[0] = '\0';
17243     }
17244     if (request == ODBC_REMOVE_DSN) {
17245 	if (!setupdlg->attr[KEY_DSN].supplied) {
17246 	    success = FALSE;
17247 	} else {
17248 	    success = SQLRemoveDSNFromIni(setupdlg->attr[KEY_DSN].attr);
17249 	}
17250     } else {
17251 	setupdlg->parent = hwnd;
17252 	setupdlg->driver = driver;
17253 	setupdlg->newDSN = request == ODBC_ADD_DSN;
17254 	setupdlg->defDSN = strcasecmp(setupdlg->attr[KEY_DSN].attr,
17255 				      "Default") == 0;
17256 	if (hwnd) {
17257 	    success = DialogBoxParam(hModule, MAKEINTRESOURCE(CONFIGDSN),
17258 				     hwnd, (DLGPROC) ConfigDlgProc,
17259 				     (LPARAM) setupdlg) == IDOK;
17260 	} else if (setupdlg->attr[KEY_DSN].supplied) {
17261 	    success = SetDSNAttributes(hwnd, setupdlg);
17262 	} else {
17263 	    success = FALSE;
17264 	}
17265     }
17266     xfree(setupdlg);
17267     return success;
17268 }
17269 
17270 /**
17271  * Dialog procedure for SQLDriverConnect().
17272  * @param hdlg handle of dialog window
17273  * @param wmsg type of message
17274  * @param wparam wparam of message
17275  * @param lparam lparam of message
17276  * @result true or false
17277  */
17278 
17279 static BOOL CALLBACK
DriverConnectProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)17280 DriverConnectProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
17281 {
17282     SETUPDLG *setupdlg;
17283     WORD index;
17284 
17285     switch (wmsg) {
17286     case WM_INITDIALOG:
17287 #ifdef _WIN64
17288 	SetWindowLong(hdlg, DWLP_USER, lparam);
17289 #else
17290 	SetWindowLong(hdlg, DWL_USER, lparam);
17291 #endif
17292 	setupdlg = (SETUPDLG *) lparam;
17293 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
17294 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
17295 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
17296 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
17297 	SetDlgItemText(hdlg, IDC_LOADEXT, setupdlg->attr[KEY_LOADEXT].attr);
17298 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
17299 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
17300 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
17301 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
17302 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
17303 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
17304 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
17305 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
17306 	SendDlgItemMessage(hdlg, IDC_LOADEXT, EM_LIMITTEXT,
17307 			   (WPARAM) (MAXPATHLEN*4 - 1), (LPARAM) 0);
17308 	CheckDlgButton(hdlg, IDC_STEPAPI,
17309 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
17310 		       BST_CHECKED : BST_UNCHECKED);
17311 	CheckDlgButton(hdlg, IDC_NOTXN,
17312 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
17313 		       BST_CHECKED : BST_UNCHECKED);
17314 	CheckDlgButton(hdlg, IDC_SHORTNAM,
17315 		       getbool(setupdlg->attr[KEY_SHORTNAM].attr) ?
17316 		       BST_CHECKED : BST_UNCHECKED);
17317 	CheckDlgButton(hdlg, IDC_LONGNAM,
17318 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
17319 		       BST_CHECKED : BST_UNCHECKED);
17320 	CheckDlgButton(hdlg, IDC_NOCREAT,
17321 		       getbool(setupdlg->attr[KEY_NOCREAT].attr) ?
17322 		       BST_CHECKED : BST_UNCHECKED);
17323 	CheckDlgButton(hdlg, IDC_NOWCHAR,
17324 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
17325 		       BST_CHECKED : BST_UNCHECKED);
17326 	CheckDlgButton(hdlg, IDC_FKSUPPORT,
17327 		       getbool(setupdlg->attr[KEY_FKSUPPORT].attr) ?
17328 		       BST_CHECKED : BST_UNCHECKED);
17329 	CheckDlgButton(hdlg, IDC_OEMCP,
17330 		       getbool(setupdlg->attr[KEY_OEMCP].attr) ?
17331 		       BST_CHECKED : BST_UNCHECKED);
17332 	CheckDlgButton(hdlg, IDC_BIGINT,
17333 		       getbool(setupdlg->attr[KEY_BIGINT].attr) ?
17334 		       BST_CHECKED : BST_UNCHECKED);
17335 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17336 			   CB_LIMITTEXT, (WPARAM) 10, (LPARAM) 0);
17337 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17338 			   CB_ADDSTRING, 0, (LPARAM) "NORMAL");
17339 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17340 			   CB_ADDSTRING, 0, (LPARAM) "OFF");
17341 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17342 			   CB_ADDSTRING, 0, (LPARAM) "FULL");
17343 	SendDlgItemMessage(hdlg, IDC_SYNCP,
17344 			   CB_SELECTSTRING, (WORD) -1,
17345 			   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
17346 	if (setupdlg->defDSN) {
17347 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
17348 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
17349 	}
17350 	return TRUE;
17351     case WM_COMMAND:
17352 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
17353 	case IDC_BROWSE:
17354 	    GetDBFile(hdlg);
17355 	    break;
17356 	case IDOK:
17357 #ifdef _WIN64
17358 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
17359 #else
17360 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
17361 #endif
17362 	    GetDlgItemText(hdlg, IDC_DSNAME,
17363 			   setupdlg->attr[KEY_DSN].attr,
17364 			   sizeof (setupdlg->attr[KEY_DSN].attr));
17365 	    GetDlgItemText(hdlg, IDC_DBNAME,
17366 			   setupdlg->attr[KEY_DBNAME].attr,
17367 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
17368 	    GetDlgItemText(hdlg, IDC_TONAME,
17369 			   setupdlg->attr[KEY_BUSY].attr,
17370 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
17371 	    GetDlgItemText(hdlg, IDC_LOADEXT,
17372 			   setupdlg->attr[KEY_LOADEXT].attr,
17373 			   sizeof (setupdlg->attr[KEY_LOADEXT].attr));
17374 	    index = SendDlgItemMessage(hdlg, IDC_SYNCP,
17375 				       CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
17376 	    if (index != (WORD) CB_ERR) {
17377 		SendDlgItemMessage(hdlg, IDC_SYNCP,
17378 				   CB_GETLBTEXT, index,
17379 				   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
17380 	    }
17381 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
17382 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
17383 		   "1" : "0");
17384 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
17385 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
17386 		   "1" : "0");
17387 	    strcpy(setupdlg->attr[KEY_SHORTNAM].attr,
17388 		   (IsDlgButtonChecked(hdlg, IDC_SHORTNAM) == BST_CHECKED) ?
17389 		   "1" : "0");
17390 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
17391 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
17392 		   "1" : "0");
17393 	    strcpy(setupdlg->attr[KEY_NOCREAT].attr,
17394 		   (IsDlgButtonChecked(hdlg, IDC_NOCREAT) == BST_CHECKED) ?
17395 		   "1" : "0");
17396 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
17397 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
17398 		   "1" : "0");
17399 	    strcpy(setupdlg->attr[KEY_FKSUPPORT].attr,
17400 		   (IsDlgButtonChecked(hdlg, IDC_FKSUPPORT) == BST_CHECKED) ?
17401 		   "1" : "0");
17402 	    strcpy(setupdlg->attr[KEY_OEMCP].attr,
17403 		   (IsDlgButtonChecked(hdlg, IDC_OEMCP) == BST_CHECKED) ?
17404 		   "1" : "0");
17405 	    strcpy(setupdlg->attr[KEY_BIGINT].attr,
17406 		   (IsDlgButtonChecked(hdlg, IDC_BIGINT) == BST_CHECKED) ?
17407 		   "1" : "0");
17408 	    /* FALL THROUGH */
17409 	case IDCANCEL:
17410 	    EndDialog(hdlg, GET_WM_COMMAND_ID(wparam, lparam) == IDOK);
17411 	    return TRUE;
17412 	}
17413     }
17414     return FALSE;
17415 }
17416 
17417 /**
17418  * Internal connect using a driver connection string.
17419  * @param dbc database connection handle
17420  * @param hwnd parent window handle
17421  * @param connIn driver connect input string
17422  * @param connInLen length of driver connect input string or SQL_NTS
17423  * @param connOut driver connect output string
17424  * @param connOutMax length of driver connect output string
17425  * @param connOutLen output length of driver connect output string
17426  * @param drvcompl completion type
17427  * @result ODBC error code
17428  */
17429 
17430 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)17431 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
17432 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
17433 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
17434 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
17435 {
17436     BOOL maybeprompt, prompt = FALSE;
17437     DBC *d;
17438     SETUPDLG *setupdlg;
17439     SQLRETURN ret;
17440     char *dsn = NULL, *driver = NULL, *dbname = NULL;
17441 
17442     if (dbc == SQL_NULL_HDBC) {
17443 	return SQL_INVALID_HANDLE;
17444     }
17445     d = (DBC *) dbc;
17446     if (d->sqlite) {
17447 	setstatd(d, -1, "connection already established", "08002");
17448 	return SQL_ERROR;
17449     }
17450     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
17451     if (setupdlg == NULL) {
17452 	return SQL_ERROR;
17453     }
17454     memset(setupdlg, 0, sizeof (SETUPDLG));
17455     maybeprompt = drvcompl == SQL_DRIVER_COMPLETE ||
17456 	drvcompl == SQL_DRIVER_COMPLETE_REQUIRED;
17457     if (connIn == NULL || !connInLen ||
17458 	(connInLen == SQL_NTS && !connIn[0])) {
17459 	prompt = TRUE;
17460     } else {
17461 	ParseAttributes((LPCSTR) connIn, setupdlg);
17462 	if (!setupdlg->attr[KEY_DSN].attr[0] &&
17463 	    drvcompl == SQL_DRIVER_COMPLETE_REQUIRED) {
17464 	    strcpy(setupdlg->attr[KEY_DSN].attr, "DEFAULT");
17465 	}
17466 	GetAttributes(setupdlg);
17467 	if (drvcompl == SQL_DRIVER_PROMPT ||
17468 	    (maybeprompt &&
17469 	     !setupdlg->attr[KEY_DBNAME].attr[0])) {
17470 	    prompt = TRUE;
17471 	}
17472     }
17473 retry:
17474     if (prompt) {
17475 	short dlgret;
17476 
17477 	setupdlg->defDSN = setupdlg->attr[KEY_DRIVER].attr[0] != '\0';
17478 	dlgret = DialogBoxParam(hModule, MAKEINTRESOURCE(DRIVERCONNECT),
17479 				hwnd, (DLGPROC) DriverConnectProc,
17480 				(LPARAM) setupdlg);
17481 
17482 	if (!dlgret || dlgret == -1) {
17483 	    xfree(setupdlg);
17484 	    return SQL_NO_DATA;
17485 	}
17486     }
17487     dsn = setupdlg->attr[KEY_DSN].attr;
17488     driver = setupdlg->attr[KEY_DRIVER].attr;
17489     dbname = setupdlg->attr[KEY_DBNAME].attr;
17490     if (connOut || connOutLen) {
17491 	char buf[2048];
17492 	int len, count;
17493 	char dsn_0 = dsn ? dsn[0] : '\0';
17494 	char drv_0 = driver ? driver[0] : '\0';
17495 
17496 	buf[0] = '\0';
17497 	count = snprintf(buf, sizeof (buf),
17498 			 "%s%s%s%s%s%sDatabase=%s;StepAPI=%s;"
17499 			 "SyncPragma=%s;NoTXN=%s;Timeout=%s;"
17500 			 "ShortNames=%s;LongNames=%s;"
17501 			 "NoCreat=%s;NoWCHAR=%s;"
17502 			 "FKSupport=%s;JournalMode=%s;OEMCP=%s;LoadExt=%s;"
17503 			 "BigInt=%s;PWD=%s",
17504 			 dsn_0 ? "DSN=" : "",
17505 			 dsn_0 ? dsn : "",
17506 			 dsn_0 ? ";" : "",
17507 			 drv_0 ? "Driver=" : "",
17508 			 drv_0 ? driver : "",
17509 			 drv_0 ? ";" : "",
17510 			 dbname ? dbname : "",
17511 			 setupdlg->attr[KEY_STEPAPI].attr,
17512 			 setupdlg->attr[KEY_SYNCP].attr,
17513 			 setupdlg->attr[KEY_NOTXN].attr,
17514 			 setupdlg->attr[KEY_BUSY].attr,
17515 			 setupdlg->attr[KEY_SHORTNAM].attr,
17516 			 setupdlg->attr[KEY_LONGNAM].attr,
17517 			 setupdlg->attr[KEY_NOCREAT].attr,
17518 			 setupdlg->attr[KEY_NOWCHAR].attr,
17519 			 setupdlg->attr[KEY_FKSUPPORT].attr,
17520 			 setupdlg->attr[KEY_JMODE].attr,
17521 			 setupdlg->attr[KEY_OEMCP].attr,
17522 			 setupdlg->attr[KEY_LOADEXT].attr,
17523 			 setupdlg->attr[KEY_BIGINT].attr,
17524 			 setupdlg->attr[KEY_PASSWD].attr);
17525 	if (count < 0) {
17526 	    buf[sizeof (buf) - 1] = '\0';
17527 	}
17528 	len = min(connOutMax - 1, strlen(buf));
17529 	if (connOut) {
17530 	    strncpy((char *) connOut, buf, len);
17531 	    connOut[len] = '\0';
17532 	}
17533 	if (connOutLen) {
17534 	    *connOutLen = len;
17535 	}
17536     }
17537     if (dsn[0]) {
17538 	char tracef[SQL_MAX_MESSAGE_LENGTH];
17539 
17540 	tracef[0] = '\0';
17541 	SQLGetPrivateProfileString(setupdlg->attr[KEY_DSN].attr,
17542 				   "tracefile", "", tracef,
17543 				   sizeof (tracef), ODBC_INI);
17544 	if (tracef[0] != '\0') {
17545 	    d->trace = fopen(tracef, "a");
17546 	}
17547     }
17548     d->nowchar = getbool(setupdlg->attr[KEY_NOWCHAR].attr);
17549     d->shortnames = getbool(setupdlg->attr[KEY_SHORTNAM].attr);
17550     d->longnames = getbool(setupdlg->attr[KEY_LONGNAM].attr);
17551     d->nocreat = getbool(setupdlg->attr[KEY_NOCREAT].attr);
17552     d->fksupport = getbool(setupdlg->attr[KEY_FKSUPPORT].attr);
17553     d->oemcp = getbool(setupdlg->attr[KEY_OEMCP].attr);
17554     d->dobigint = getbool(setupdlg->attr[KEY_BIGINT].attr);
17555     d->pwdLen = strlen(setupdlg->attr[KEY_PASSWD].attr);
17556     d->pwd = (d->pwdLen > 0) ? setupdlg->attr[KEY_PASSWD].attr : NULL;
17557     ret = dbopen(d, dbname ? dbname : "", 0,
17558 		 dsn ? dsn : "",
17559 		 setupdlg->attr[KEY_STEPAPI].attr,
17560 		 setupdlg->attr[KEY_SYNCP].attr,
17561 		 setupdlg->attr[KEY_NOTXN].attr,
17562 		 setupdlg->attr[KEY_JMODE].attr,
17563 		 setupdlg->attr[KEY_BUSY].attr);
17564     if (ret != SQL_SUCCESS) {
17565 	if (maybeprompt && !prompt) {
17566 	    prompt = TRUE;
17567 	    goto retry;
17568 	}
17569     }
17570     memset(setupdlg->attr[KEY_PASSWD].attr, 0,
17571 	   sizeof (setupdlg->attr[KEY_PASSWD].attr));
17572     if (ret == SQL_SUCCESS) {
17573 	dbloadext(d, setupdlg->attr[KEY_LOADEXT].attr);
17574     }
17575     xfree(setupdlg);
17576     return ret;
17577 }
17578 
17579 #endif /* WITHOUT_DRIVERMGR */
17580 #endif /* _WIN32 || _WIN64 */
17581 
17582 #ifndef WINTERFACE
17583 /**
17584  * Connect using a driver connection string.
17585  * @param dbc database connection handle
17586  * @param hwnd parent window handle
17587  * @param connIn driver connect input string
17588  * @param connInLen length of driver connect input string or SQL_NTS
17589  * @param connOut driver connect output string
17590  * @param connOutMax length of driver connect output string
17591  * @param connOutLen output length of driver connect output string
17592  * @param drvcompl completion type
17593  * @result ODBC error code
17594  */
17595 
17596 SQLRETURN SQL_API
SQLDriverConnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)17597 SQLDriverConnect(SQLHDBC dbc, SQLHWND hwnd,
17598 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
17599 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
17600 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
17601 {
17602     SQLRETURN ret;
17603 
17604     HDBC_LOCK(dbc);
17605     ret = drvdriverconnect(dbc, hwnd, connIn, connInLen,
17606 			   connOut, connOutMax, connOutLen, drvcompl);
17607     HDBC_UNLOCK(dbc);
17608     return ret;
17609 }
17610 #endif
17611 
17612 #ifdef WINTERFACE
17613 /**
17614  * Connect using a driver connection string (UNICODE version).
17615  * @param dbc database connection handle
17616  * @param hwnd parent window handle
17617  * @param connIn driver connect input string
17618  * @param connInLen length of driver connect input string or SQL_NTS
17619  * @param connOut driver connect output string
17620  * @param connOutMax length of driver connect output string
17621  * @param connOutLen output length of driver connect output string
17622  * @param drvcompl completion type
17623  * @result ODBC error code
17624  */
17625 
17626 SQLRETURN SQL_API
SQLDriverConnectW(SQLHDBC dbc,SQLHWND hwnd,SQLWCHAR * connIn,SQLSMALLINT connInLen,SQLWCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)17627 SQLDriverConnectW(SQLHDBC dbc, SQLHWND hwnd,
17628 		  SQLWCHAR *connIn, SQLSMALLINT connInLen,
17629 		  SQLWCHAR *connOut, SQLSMALLINT connOutMax,
17630 		  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
17631 {
17632     SQLRETURN ret;
17633     char *ci = NULL;
17634     SQLSMALLINT len = 0;
17635 
17636     HDBC_LOCK(dbc);
17637     if (connIn) {
17638 #if defined(_WIN32) || defined(_WIN64)
17639 	ci = uc_to_wmb(connIn, connInLen);
17640 #else
17641 	ci = uc_to_utf(connIn, connInLen);
17642 #endif
17643 	if (!ci) {
17644 	    DBC *d = (DBC *) dbc;
17645 
17646 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
17647 	    HDBC_UNLOCK(dbc);
17648 	    return SQL_ERROR;
17649 	}
17650     }
17651     ret = drvdriverconnect(dbc, hwnd, (SQLCHAR *) ci, SQL_NTS,
17652 			   (SQLCHAR *) connOut, connOutMax, &len, drvcompl);
17653     HDBC_UNLOCK(dbc);
17654     uc_free(ci);
17655     if (ret == SQL_SUCCESS) {
17656 	SQLWCHAR *co = NULL;
17657 
17658 	if (connOut) {
17659 	    if (len > 0) {
17660 #if defined(_WIN32) || defined(_WIN64)
17661 		co = wmb_to_uc((char *) connOut, len);
17662 #else
17663 		co = uc_from_utf((SQLCHAR *) connOut, len);
17664 #endif
17665 		if (co) {
17666 		    uc_strncpy(connOut, co, connOutMax);
17667 		    co[len] = 0;
17668 		    len = min(connOutMax, uc_strlen(co));
17669 		    uc_free(co);
17670 		} else {
17671 		    len = 0;
17672 		}
17673 	    }
17674 	    if (len <= 0) {
17675 		len = 0;
17676 		connOut[0] = 0;
17677 	    }
17678 	} else {
17679 	    len = 0;
17680 	}
17681 	if (connOutLen) {
17682 	    *connOutLen = len;
17683 	}
17684     }
17685     return ret;
17686 }
17687 #endif
17688 
17689 #if defined(_WIN32) || defined(_WIN64)
17690 
17691 /**
17692  * DLL initializer for WIN32.
17693  * @param hinst instance handle
17694  * @param reason reason code for entry point
17695  * @param reserved
17696  * @result always true
17697  */
17698 
17699 BOOL APIENTRY
LibMain(HANDLE hinst,DWORD reason,LPVOID reserved)17700 LibMain(HANDLE hinst, DWORD reason, LPVOID reserved)
17701 {
17702     static int initialized = 0;
17703 
17704     switch (reason) {
17705     case DLL_PROCESS_ATTACH:
17706 	if (!initialized++) {
17707 	    hModule = hinst;
17708 #ifdef WINTERFACE
17709 	    /* MS Access hack part 1 (reserved error -7748) */
17710 	    statSpec2P = statSpec2;
17711 	    statSpec3P = statSpec3;
17712 #endif
17713 #ifdef SQLITE_DYNLOAD
17714 	    dls_init();
17715 #endif
17716 #ifdef SQLITE_HAS_CODEC
17717 	    sqlite3_activate_see(SQLITE_ACTIVATION_KEY);
17718 #endif
17719 	}
17720 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
17721 	nvfs_init();
17722 #endif
17723 	break;
17724     case DLL_THREAD_ATTACH:
17725 	break;
17726     case DLL_PROCESS_DETACH:
17727 	if (--initialized <= 0) {
17728 #ifdef SQLITE_DYNLOAD
17729 	    dls_fini();
17730 #endif
17731 	}
17732 	break;
17733     case DLL_THREAD_DETACH:
17734 	break;
17735     default:
17736 	break;
17737     }
17738     return TRUE;
17739 }
17740 
17741 /**
17742  * DLL entry point for WIN32.
17743  * @param hinst instance handle
17744  * @param reason reason code for entry point
17745  * @param reserved
17746  * @result always true
17747  */
17748 
17749 int __stdcall
DllMain(HANDLE hinst,DWORD reason,LPVOID reserved)17750 DllMain(HANDLE hinst, DWORD reason, LPVOID reserved)
17751 {
17752     return LibMain(hinst, reason, reserved);
17753 }
17754 
17755 #ifndef WITHOUT_INSTALLER
17756 
17757 /**
17758  * Handler for driver installer/uninstaller error messages.
17759  * @param name name of API function for which to show error messages
17760  * @result true when error message retrieved
17761  */
17762 
17763 static BOOL
InUnError(char * name)17764 InUnError(char *name)
17765 {
17766     WORD err = 1;
17767     DWORD code;
17768     char errmsg[301];
17769     WORD errlen, errmax = sizeof (errmsg) - 1;
17770     int sqlret;
17771     BOOL ret = FALSE;
17772 
17773     do {
17774 	errmsg[0] = '\0';
17775 	sqlret = SQLInstallerError(err, &code, errmsg, errmax, &errlen);
17776 	if (SQL_SUCCEEDED(sqlret)) {
17777 	    MessageBox(NULL, errmsg, name,
17778 		       MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
17779 	    ret = TRUE;
17780 	}
17781 	err++;
17782     } while (sqlret != SQL_NO_DATA);
17783     return ret;
17784 }
17785 
17786 /**
17787  * Built in driver installer/uninstaller.
17788  * @param remove true for uninstall
17789  * @param cmdline command line string of rundll32
17790  */
17791 
17792 static BOOL
InUn(int remove,char * cmdline)17793 InUn(int remove, char *cmdline)
17794 {
17795 #ifdef SQLITE_HAS_CODEC
17796     static char *drivername = "SQLite3 ODBC Driver (SEE)";
17797     static char *dsname = "SQLite3 SEE Datasource";
17798 #else
17799     static char *drivername = "SQLite3 ODBC Driver";
17800     static char *dsname = "SQLite3 Datasource";
17801 #endif
17802     char *dllname, *p;
17803     char dllbuf[301], path[301], driver[300], attr[300], inst[400];
17804     WORD pathmax = sizeof (path) - 1, pathlen;
17805     DWORD usecnt, mincnt;
17806     int quiet = 0;
17807 
17808     dllbuf[0] = '\0';
17809     GetModuleFileName(hModule, dllbuf, sizeof (dllbuf));
17810     p = strrchr(dllbuf, '\\');
17811     dllname = p ? (p + 1) : dllbuf;
17812     quiet = cmdline && strstr(cmdline, "quiet");
17813     if (SQLInstallDriverManager(path, pathmax, &pathlen)) {
17814 	sprintf(driver, "%s;Driver=%s;Setup=%s;",
17815 		drivername, dllname, dllname);
17816 	p = driver;
17817 	while (*p) {
17818 	    if (*p == ';') {
17819 		*p = '\0';
17820 	    }
17821 	    ++p;
17822 	}
17823 	usecnt = 0;
17824 	path[0] = '\0';
17825 	SQLInstallDriverEx(driver, NULL, path, pathmax, NULL,
17826 			   ODBC_INSTALL_INQUIRY, &usecnt);
17827 	pathlen = strlen(path);
17828 	while (pathlen > 0 && path[pathlen - 1] == '\\') {
17829 	    --pathlen;
17830 	    path[pathlen] = '\0';
17831 	}
17832 	sprintf(driver, "%s;Driver=%s\\%s;Setup=%s\\%s;",
17833 		drivername, path, dllname, path, dllname);
17834 	p = driver;
17835 	while (*p) {
17836 	    if (*p == ';') {
17837 		*p = '\0';
17838 	    }
17839 	    ++p;
17840 	}
17841 	sprintf(inst, "%s\\%s", path, dllname);
17842 	if (!remove && usecnt > 0) {
17843 	    /* first install try: copy over driver dll, keeping DSNs */
17844 	    if (GetFileAttributesA(dllbuf) != INVALID_FILE_ATTRIBUTES &&
17845 		CopyFile(dllbuf, inst, 0)) {
17846 		if (!quiet) {
17847 		    char buf[512];
17848 
17849 		    sprintf(buf, "%s replaced.", drivername);
17850 		    MessageBox(NULL, buf, "Info",
17851 			       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
17852 			       MB_SETFOREGROUND);
17853 		}
17854 		return TRUE;
17855 	    }
17856 	}
17857 	mincnt = remove ? 1 : 0;
17858 	while (usecnt != mincnt) {
17859 	    if (!SQLRemoveDriver(driver, TRUE, &usecnt)) {
17860 		break;
17861 	    }
17862 	}
17863 	if (remove) {
17864 	    if (usecnt && !SQLRemoveDriver(driver, TRUE, &usecnt)) {
17865 		InUnError("SQLRemoveDriver");
17866 		return FALSE;
17867 	    }
17868 	    if (!usecnt) {
17869 		char buf[512];
17870 
17871 		DeleteFile(inst);
17872 		if (!quiet) {
17873 		    sprintf(buf, "%s uninstalled.", drivername);
17874 		    MessageBox(NULL, buf, "Info",
17875 			       MB_ICONINFORMATION |MB_OK | MB_TASKMODAL |
17876 			       MB_SETFOREGROUND);
17877 		}
17878 	    }
17879 	    sprintf(attr, "DSN=%s;Database=sqlite.db;", dsname);
17880 	    p = attr;
17881 	    while (*p) {
17882 		if (*p == ';') {
17883 		    *p = '\0';
17884 		}
17885 		++p;
17886 	    }
17887 	    SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
17888 	    return TRUE;
17889 	}
17890 	if (GetFileAttributesA(dllbuf) == INVALID_FILE_ATTRIBUTES) {
17891 	    return FALSE;
17892 	}
17893 	if (strcmp(dllbuf, inst) != 0 && !CopyFile(dllbuf, inst, 0)) {
17894 	    char buf[512];
17895 
17896 	    sprintf(buf, "Copy %s to %s failed.", dllbuf, inst);
17897 	    MessageBox(NULL, buf, "CopyFile",
17898 		       MB_ICONSTOP |MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
17899 	    return FALSE;
17900 	}
17901 	if (!SQLInstallDriverEx(driver, path, path, pathmax, &pathlen,
17902 				ODBC_INSTALL_COMPLETE, &usecnt)) {
17903 	    InUnError("SQLInstallDriverEx");
17904 	    return FALSE;
17905 	}
17906 	sprintf(attr, "DSN=%s;Database=sqlite.db;", dsname);
17907 	p = attr;
17908 	while (*p) {
17909 	    if (*p == ';') {
17910 		*p = '\0';
17911 	    }
17912 	    ++p;
17913 	}
17914 	SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
17915 	if (!SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, drivername, attr)) {
17916 	    InUnError("SQLConfigDataSource");
17917 	    return FALSE;
17918 	}
17919 	if (!quiet) {
17920 	    char buf[512];
17921 
17922 	    sprintf(buf, "%s installed.", drivername);
17923 	    MessageBox(NULL, buf, "Info",
17924 		       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
17925 		       MB_SETFOREGROUND);
17926 	}
17927     } else {
17928 	InUnError("SQLInstallDriverManager");
17929 	return FALSE;
17930     }
17931     return TRUE;
17932 }
17933 
17934 /**
17935  * RunDLL32 entry point for driver installation.
17936  * @param hwnd window handle of caller
17937  * @param hinst of this DLL
17938  * @param lpszCmdLine rundll32 command line tail
17939  * @param nCmdShow ignored
17940  */
17941 
17942 void CALLBACK
install(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)17943 install(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
17944 {
17945     InUn(0, lpszCmdLine);
17946 }
17947 
17948 /**
17949  * RunDLL32 entry point for driver uninstallation.
17950  * @param hwnd window handle of caller
17951  * @param hinst of this DLL
17952  * @param lpszCmdLine rundll32 command line tail
17953  * @param nCmdShow ignored
17954  */
17955 
17956 void CALLBACK
uninstall(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)17957 uninstall(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
17958 {
17959     InUn(1, lpszCmdLine);
17960 }
17961 
17962 #endif /* WITHOUT_INSTALLER */
17963 
17964 #ifndef WITHOUT_SHELL
17965 
17966 /**
17967  * Setup argv vector from string
17968  * @param argcp pointer to argc
17969  * @param argvp pointer to argv
17970  * @param cmdline command line string
17971  * @param argv0 0th element for argv or NULL, must be static
17972  */
17973 
17974 static void
setargv(int * argcp,char *** argvp,char * cmdline,char * argv0)17975 setargv(int *argcp, char ***argvp, char *cmdline, char *argv0)
17976 {
17977     char *p, *arg, *argspace, **argv;
17978     int argc, size, inquote, copy, slashes;
17979 
17980     size = 2 + (argv0 ? 1 : 0);
17981     for (p = cmdline; *p != '\0'; p++) {
17982 	if (ISSPACE(*p)) {
17983 	    size++;
17984 	    while (ISSPACE(*p)) {
17985 		p++;
17986 	    }
17987 	    if (*p == '\0') {
17988 		break;
17989 	    }
17990 	}
17991     }
17992     argspace = malloc(size * sizeof (char *) + strlen(cmdline) + 1);
17993     argv = (char **) argspace;
17994     argspace += size * sizeof (char *);
17995     size--;
17996     argc = 0;
17997     if (argv0) {
17998 	argv[argc++] = argv0;
17999     }
18000     p = cmdline;
18001     for (; argc < size; argc++) {
18002 	argv[argc] = arg = argspace;
18003 	while (ISSPACE(*p)) {
18004 	    p++;
18005 	}
18006 	if (*p == '\0') {
18007 	    break;
18008 	}
18009 	inquote = 0;
18010 	slashes = 0;
18011 	while (1) {
18012 	    copy = 1;
18013 	    while (*p == '\\') {
18014 		slashes++;
18015 		p++;
18016 	    }
18017 	    if (*p == '"') {
18018 		if ((slashes & 1) == 0) {
18019 		    copy = 0;
18020 		    if (inquote && p[1] == '"') {
18021 			p++;
18022 			copy = 1;
18023 		    } else {
18024 			inquote = !inquote;
18025 		    }
18026 		}
18027 		slashes >>= 1;
18028 	    }
18029 	    while (slashes) {
18030 		*arg = '\\';
18031 		arg++;
18032 		slashes--;
18033 	    }
18034 	    if (*p == '\0' || (!inquote && ISSPACE(*p))) {
18035 		break;
18036 	    }
18037 	    if (copy != 0) {
18038 		*arg = *p;
18039 		arg++;
18040 	    }
18041 	    p++;
18042 	}
18043 	*arg = '\0';
18044 	argspace = arg + 1;
18045     }
18046     argv[argc] = 0;
18047     *argcp = argc;
18048     *argvp = argv;
18049 }
18050 
18051 /**
18052  * RunDLL32 entry point for SQLite shell
18053  * @param hwnd window handle of caller
18054  * @param hinst of this DLL
18055  * @param lpszCmdLine rundll32 command line tail
18056  * @param nCmdShow ignored
18057  */
18058 
18059 void CALLBACK
shell(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)18060 shell(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
18061 {
18062     int argc, needcon = 0;
18063     char **argv;
18064     extern int sqlite3_main(int, char **);
18065     static const char *name = "SQLite3 Shell";
18066     DWORD ftype0, ftype1, ftype2;
18067 
18068     ftype0 = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
18069     ftype1 = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
18070     ftype2 = GetFileType(GetStdHandle(STD_ERROR_HANDLE));
18071     if (ftype0 != FILE_TYPE_DISK && ftype0 != FILE_TYPE_CHAR &&
18072 	ftype0 != FILE_TYPE_PIPE) {
18073 	fclose(stdin);
18074 	++needcon;
18075 	ftype0 = FILE_TYPE_UNKNOWN;
18076     }
18077     if (ftype1 != FILE_TYPE_DISK && ftype1 != FILE_TYPE_CHAR &&
18078 	ftype1 != FILE_TYPE_PIPE) {
18079 	fclose(stdout);
18080 	++needcon;
18081 	ftype1 = FILE_TYPE_UNKNOWN;
18082     }
18083     if (ftype2 != FILE_TYPE_DISK && ftype2 != FILE_TYPE_CHAR &&
18084 	ftype2 != FILE_TYPE_PIPE) {
18085 	fclose(stderr);
18086 	++needcon;
18087 	ftype2 = FILE_TYPE_UNKNOWN;
18088     }
18089     if (needcon > 0) {
18090 	AllocConsole();
18091 	SetConsoleTitle(name);
18092     }
18093     if (ftype0 == FILE_TYPE_UNKNOWN) {
18094 	freopen("CONIN$", "r", stdin);
18095     }
18096     if (ftype1 == FILE_TYPE_UNKNOWN) {
18097 	freopen("CONOUT$", "w", stdout);
18098     }
18099     if (ftype2 == FILE_TYPE_UNKNOWN) {
18100 	freopen("CONOUT$", "w", stderr);
18101     }
18102     setargv(&argc, &argv, lpszCmdLine, (char *) name);
18103 #if defined(ENABLE_NVFS) && (ENABLE_NVFS)
18104     nvfs_init();
18105 #endif
18106     sqlite3_main(argc, argv);
18107 }
18108 
18109 #endif /* WITHOUT_SHELL */
18110 
18111 #endif /* _WIN32 || _WIN64 */
18112 
18113 #if defined(HAVE_ODBCINSTEXT_H) && (HAVE_ODBCINSTEXT_H)
18114 
18115 /*
18116  * unixODBC property page for this driver,
18117  * may or may not work depending on unixODBC version.
18118  */
18119 
18120 #include <odbcinstext.h>
18121 
18122 int
ODBCINSTGetProperties(HODBCINSTPROPERTY prop)18123 ODBCINSTGetProperties(HODBCINSTPROPERTY prop)
18124 {
18125     static const char *instYN[] = { "No", "Yes", NULL };
18126     static const char *syncPragma[] = { "NORMAL", "OFF", "FULL", NULL };
18127     static const char *jmPragma[] = {
18128 	"DELETE", "PERSIST", "OFF", "TRUNCATE", "MEMORY", "WAL", NULL
18129     };
18130 
18131     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18132     prop = prop->pNext;
18133     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18134     prop->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
18135     strncpy(prop->szName, "Database", INI_MAX_PROPERTY_NAME);
18136     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
18137     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18138     prop = prop->pNext;
18139     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18140     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
18141     strncpy(prop->szName, "Timeout", INI_MAX_PROPERTY_NAME);
18142     strncpy(prop->szValue, "100000", INI_MAX_PROPERTY_VALUE);
18143     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18144     prop = prop->pNext;
18145     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18146     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18147     prop->aPromptData = malloc(sizeof (instYN));
18148     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18149     strncpy(prop->szName, "StepAPI", INI_MAX_PROPERTY_NAME);
18150     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18151     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18152     prop = prop->pNext;
18153     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18154     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18155     prop->aPromptData = malloc(sizeof (instYN));
18156     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18157     strncpy(prop->szName, "ShortNames", INI_MAX_PROPERTY_NAME);
18158     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18159     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18160     prop = prop->pNext;
18161     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18162     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18163     prop->aPromptData = malloc(sizeof (instYN));
18164     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18165     strncpy(prop->szName, "LongNames", INI_MAX_PROPERTY_NAME);
18166     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18167     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18168     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18169     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18170     prop->aPromptData = malloc(sizeof (instYN));
18171     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18172     strncpy(prop->szName, "NoCreat", INI_MAX_PROPERTY_NAME);
18173     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18174 #ifdef WINTERFACE
18175     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18176     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18177     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18178     prop->aPromptData = malloc(sizeof (instYN));
18179     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18180     strncpy(prop->szName, "NoWCHAR", INI_MAX_PROPERTY_NAME);
18181     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18182 #endif
18183     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18184     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18185     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18186     prop->aPromptData = malloc(sizeof (instYN));
18187     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18188     strncpy(prop->szName, "FKSupport", INI_MAX_PROPERTY_NAME);
18189     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18190     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18191     prop = prop->pNext;
18192     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18193     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18194     prop->aPromptData = malloc(sizeof (syncPragma));
18195     memcpy(prop->aPromptData, syncPragma, sizeof (syncPragma));
18196     strncpy(prop->szName, "SyncPragma", INI_MAX_PROPERTY_NAME);
18197     strncpy(prop->szValue, "NORMAL", INI_MAX_PROPERTY_VALUE);
18198     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18199     prop = prop->pNext;
18200     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18201     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18202     prop->aPromptData = malloc(sizeof (jmPragma));
18203     memcpy(prop->aPromptData, jmPragma, sizeof (jmPragma));
18204     strncpy(prop->szName, "JournalMode", INI_MAX_PROPERTY_NAME);
18205     strncpy(prop->szValue, "DELETE", INI_MAX_PROPERTY_VALUE);
18206     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18207     prop = prop->pNext;
18208     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18209     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
18210     strncpy(prop->szName, "LoadExt", INI_MAX_PROPERTY_NAME);
18211     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
18212     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
18213     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
18214     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
18215     prop->aPromptData = malloc(sizeof (instYN));
18216     memcpy(prop->aPromptData, instYN, sizeof (instYN));
18217     strncpy(prop->szName, "BigInt", INI_MAX_PROPERTY_NAME);
18218     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
18219     return 1;
18220 }
18221 
18222 #endif /* HAVE_ODBCINSTEXT_H */
18223 
18224 #ifdef SQLITE_DYNLOAD
18225 
18226 /*
18227  * SQLite3 shared library/DLL stubs.
18228  */
18229 
18230 static void
dls_void(void)18231 dls_void(void)
18232 {
18233 }
18234 
18235 static int
dls_error(void)18236 dls_error(void)
18237 {
18238     return SQLITE_ERROR;
18239 }
18240 
18241 static int
dls_0(void)18242 dls_0(void)
18243 {
18244     return 0;
18245 }
18246 
18247 static void *
dls_null(void)18248 dls_null(void)
18249 {
18250     return NULL;
18251 }
18252 
18253 static const char *
dls_empty(void)18254 dls_empty(void)
18255 {
18256     return "";
18257 }
18258 
18259 static int
dls_snull(void)18260 dls_snull(void)
18261 {
18262     return SQLITE_NULL;
18263 }
18264 
18265 #define DLS_ENT(name, func)						\
18266     { "sqlite3_" #name, offsetof(struct dl_sqlite3_funcs, name),	\
18267       (void *) func }
18268 
18269 #define DLS_ENT3(name, off, func)					\
18270     { "sqlite3_" #name, offsetof(struct dl_sqlite3_funcs, off),		\
18271       (void *) func }
18272 
18273 #define DLS_END { NULL, 0, NULL }
18274 
18275 static struct {
18276     const char *name;
18277     int offset;
18278     void *func;
18279 } dls_nametab[] = {
18280     DLS_ENT(activate_see, dls_void),
18281     DLS_ENT(bind_blob, dls_error),
18282     DLS_ENT(bind_double, dls_error),
18283     DLS_ENT(bind_int, dls_error),
18284     DLS_ENT(bind_int64, dls_error),
18285     DLS_ENT(bind_null, dls_error),
18286     DLS_ENT(bind_parameter_count, dls_0),
18287     DLS_ENT(bind_text, dls_error),
18288     DLS_ENT(busy_handler, dls_error),
18289     DLS_ENT(changes, dls_0),
18290     DLS_ENT(close, dls_error),
18291     DLS_ENT(column_blob, dls_null),
18292     DLS_ENT(column_bytes, dls_0),
18293     DLS_ENT(column_count, dls_0),
18294     DLS_ENT(column_database_name, dls_empty),
18295     DLS_ENT(column_decltype, dls_empty),
18296     DLS_ENT(column_name, dls_empty),
18297     DLS_ENT(column_origin_name, dls_null),
18298     DLS_ENT(column_table_name, dls_null),
18299     DLS_ENT(column_text, dls_null),
18300     DLS_ENT(column_type, dls_snull),
18301     DLS_ENT(create_function, dls_error),
18302     DLS_ENT(enable_load_extension, dls_error),
18303     DLS_ENT(errcode, dls_error),
18304     DLS_ENT(errmsg, dls_empty),
18305     DLS_ENT(exec, dls_error),
18306     DLS_ENT(finalize, dls_error),
18307     DLS_ENT(free, free),
18308     DLS_ENT(free_table, dls_void),
18309     DLS_ENT(get_table, dls_error),
18310     DLS_ENT(interrupt, dls_void),
18311     DLS_ENT(key, dls_error),
18312     DLS_ENT(libversion, dls_empty),
18313     DLS_ENT(load_extension, dls_error),
18314     DLS_ENT(malloc, malloc),
18315     DLS_ENT(mprintf, dls_null),
18316     DLS_ENT(open, dls_error),
18317     DLS_ENT(open16, dls_error),
18318     DLS_ENT(open_v2, dls_error),
18319     DLS_ENT(prepare, dls_error),
18320     DLS_ENT(prepare_v2, dls_error),
18321     DLS_ENT(profile, dls_null),
18322     DLS_ENT(realloc, realloc),
18323     DLS_ENT(rekey, dls_error),
18324     DLS_ENT(reset, dls_error),
18325     DLS_ENT(result_blob, dls_void),
18326     DLS_ENT(result_error, dls_void),
18327     DLS_ENT(result_int, dls_void),
18328     DLS_ENT(result_null, dls_void),
18329     DLS_ENT(step, dls_error),
18330 #if defined(_WIN32) || defined(_WIN64)
18331     DLS_ENT3(strnicmp, xstrnicmp, _strnicmp),
18332 #else
18333     DLS_ENT3(strnicmp, xstrnicmp, strncasecmp),
18334 #endif
18335     DLS_ENT(table_column_metadata, dls_error),
18336     DLS_ENT(trace, dls_null),
18337     DLS_ENT(user_data, dls_null),
18338     DLS_ENT(value_blob, dls_null),
18339     DLS_ENT(value_bytes, dls_0),
18340     DLS_ENT(value_text, dls_empty),
18341     DLS_ENT(value_type, dls_snull),
18342     DLS_END
18343 };
18344 
18345 #if defined(_WIN32) || defined(_WIN64)
18346 
18347 static HMODULE sqlite3_dll = 0;
18348 
18349 static void
dls_init(void)18350 dls_init(void)
18351 {
18352     int i;
18353     static const char *dll_names[] = {
18354 	"System.Data.SQLite.dll",
18355 	"sqlite3.dll",
18356 	NULL,
18357     };
18358 
18359     i = 0;
18360     while (dll_names[i]) {
18361 	sqlite3_dll = LoadLibrary(dll_names[i]);
18362 	if (sqlite3_dll) {
18363 	    break;
18364 	}
18365 	++i;
18366     }
18367     i = 0;
18368     while (dls_nametab[i].name) {
18369 	void *func = 0, **loc;
18370 
18371 	if (sqlite3_dll) {
18372 	    func = (void *) GetProcAddress(sqlite3_dll, dls_nametab[i].name);
18373 	}
18374 	if (!func) {
18375 	    func = dls_nametab[i].func;
18376 	}
18377 	loc = (void **) ((char *) &dls_funcs + dls_nametab[i].offset);
18378 	*loc = func;
18379 	++i;
18380     }
18381     if (!sqlite3_dll) {
18382 	char buf[MAXPATHLEN], msg[MAXPATHLEN];
18383 
18384 	LoadString(hModule, IDS_DRVTITLE, buf, sizeof (buf));
18385 	LoadString(hModule, IDS_DLLERR, msg, sizeof (msg));
18386 	MessageBox(NULL, msg, buf,
18387 		   MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
18388 		   MB_SETFOREGROUND);
18389     }
18390 }
18391 
18392 static void
dls_fini(void)18393 dls_fini(void)
18394 {
18395     if (sqlite3_dll) {
18396 	FreeLibrary(sqlite3_dll);
18397 	sqlite3_dll = 0;
18398     }
18399 }
18400 
18401 #else
18402 
18403 #include <dlfcn.h>
18404 
18405 static void *libsqlite3_so = 0;
18406 
18407 void
dls_init(void)18408 dls_init(void)
18409 {
18410     int i;
18411 
18412     libsqlite3_so = dlopen("libsqlite3.so.0", RTLD_NOW | RTLD_GLOBAL);
18413     i = 0;
18414     while (dls_nametab[i].name) {
18415 	void *func = 0, **loc;
18416 
18417 	if (libsqlite3_so) {
18418 	    func = dlsym(libsqlite3_so, dls_nametab[i].name);
18419 	}
18420 	if (!func) {
18421 	    func = dls_nametab[i].func;
18422 	}
18423 	loc = (void **) ((char *) &dls_funcs + dls_nametab[i].offset);
18424 	*loc = func;
18425 	++i;
18426     }
18427     if (!libsqlite3_so) {
18428 	const char errmsg[] = "SQLite3 shared library not found.\n";
18429 
18430 	write(2, errmsg, sizeof (errmsg) - 1);
18431     }
18432 }
18433 
18434 void
dls_fini(void)18435 dls_fini(void)
18436 {
18437     if (libsqlite3_so) {
18438 	dlclose(libsqlite3_so);
18439 	libsqlite3_so = 0;
18440     }
18441 }
18442 
18443 #endif
18444 
18445 #endif
18446