1 /**
2  * @file sqlite4odbc.c
3  * SQLite4 ODBC Driver main module.
4  *
5  * $Id: sqlite4odbc.c,v 1.24 2020/06/20 11:56:09 chw Exp chw $
6  *
7  * Copyright (c) 2014-2020 Christian Werner <chw@ch-werner.de>
8  *
9  * See the file "license.terms" for information on usage
10  * and redistribution of this file and for a
11  * DISCLAIMER OF ALL WARRANTIES.
12  */
13 
14 #if defined(SQLITE_HAS_CODEC) && defined(SQLITE_API)
15 #undef WITH_SQLITE_DLLS
16 #undef SQLITE_DYNLOAD
17 #include "sqlite4.c"
18 #endif
19 
20 #if defined(WITH_SQLITE_DLLS) && (WITH_SQLITE_DLLS > 1)
21 #define SQLITE_DYNLOAD 1
22 #endif
23 
24 #include "sqlite4odbc.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_sqlite4_funcs {
39     int (*bind_blob)(sqlite4_stmt *p0, int p1, const void *p2, int p3,
40 		     void (*p4)(void *, void *), void *p5);
41     int (*bind_double)(sqlite4_stmt *p0, int p1, double p2);
42     int (*bind_int)(sqlite4_stmt *p0, int p1, int p2);
43     int (*bind_int64)(sqlite4_stmt *p0, int p1, sqlite4_int64 p2);
44     int (*bind_null)(sqlite4_stmt *p0, int p1);
45     int (*bind_parameter_count)(sqlite4_stmt *p0);
46     int (*bind_text)(sqlite4_stmt *p0, int p1, const char *p2, int p3,
47 		     void (*p4)(void *, void *), void *p5);
48     int (*changes)(sqlite4 *p0);
49     int (*close)(sqlite4 *p0, unsigned int p1);
50     const void * (*column_blob)(sqlite4_stmt *p0, int p1, int p2);
51     int (*column_bytes)(sqlite4_stmt *p0, int p1);
52     int (*column_count)(sqlite4_stmt *p0);
53     const char * (*column_database_name)(sqlite4_stmt *p0, int p1);
54     const char * (*column_decltype)(sqlite4_stmt *p0, int p1);
55     double (*column_double)(sqlite4_stmt *p0);
56     const char * (*column_name)(sqlite4_stmt *p0, int p1);
57     const char * (*column_origin_name)(sqlite4_stmt *p0, int p1);
58     const char * (*column_table_name)(sqlite4_stmt *p0, int p1);
59     const char * (*column_text)(sqlite4_stmt *p0, int p1, p2);
60     int (*column_type)(sqlite4_stmt *p0, int p1);
61     int (*create_function)(sqlite4 *p0, const char *p1, int p2,
62 			   void *p4,
63 			   void (*p5)(sqlite4_context *, int, sqlite4_value **),
64 			   void (*p6)(sqlite4_context *, int, sqlite4_value **),
65 			   void (*p7)(sqlite4_context *),
66 			   void (*p8)(void *));
67     int (*errcode)(sqlite4 *p0);
68     const char * (*errmsg)(sqlite4 *p0);
69     int (*exec)(sqlite4 *p0, const char *p1,
70 		int (*p2)(void *, int, char **, char **),
71 		void *p3);
72     int (*finalize)(sqlite4_stmt *p0);
73     void (*free)(sqlite4_env *p0, void *p1);
74     void (*interrupt)(sqlite4 *p0);
75 #if 0
76     sqlite4_int64 (*last_insert_rowid)(sqlite4 *p0);
77 #endif
78     const char * (*libversion)(void);
79 #if 0
80     int (*load_extension)(sqlite4 *p0, const char *p1, const char *p2,
81 			  char **p3);
82 #endif
83     void * (*malloc)(sqlite4_env *p0, int p1);
84     char * (*mprintf)(sqlite4_env *p0, const char *p1, ...);
85     int (*open)(sqlite4_env *p0, const char *p1, sqlite4 **p2, ...);
86     int (*prepare)(sqlite4 *p0, const char *p1, int p2, sqlite4_stmt **p3,
87 		   int *p4);
88     void (*profile)(sqlite4 *p0, void *p1,
89 		    void (*p2)(void *, const char *, sqlite4_uint64),
90 		    void *p3);
91     void * (*realloc)(sqlite4_env *p0, void *p1, int p2);
92     int (*reset)(sqlite4_stmt *p0);
93     void (*result_blob)(sqlite4_context *p0, const void *p1,
94 			int p2, void (*p3)(void *, void *), void *p4);
95     void (*result_error)(sqlite4_context *p0, const char *p1, int p2);
96     void (*result_int)(sqlite4_context *p0, int p1);
97     void (*result_null)(sqlite4_context *p0);
98     int (*step)(sqlite4_stmt *p0);
99     int (*xstrnicmp)(const char *p0, const char *p1, int p2);
100 #if 0
101     int (*table_column_metadata)(sqlite4 *p0, const char *p1,
102 				 const char *p2, const char *p3,
103 				 char const **p4, char const **p5,
104 				 int *p6, int *p7, int *p8);
105 #endif
106     void (*trace)(sqlite4 *p0, void *p1, void (*p2)(void *, const char *),
107 		  void *p2);
108     void * (*user_data)(sqlite4_context *p0);
109     const void * (*value_blob)(sqlite4_value *p0, int *p1);
110     int (*value_bytes)(sqlite4_value *p0);
111     const char * (*value_text)(sqlite4_value *p0, int *p1);
112     int (*value_type)(sqlite4_value *p0);
113 } dls_funcs;
114 
115 #define sqlite4_bind_blob             dls_funcs.bind_blob
116 #define sqlite4_bind_double           dls_funcs.bind_double
117 #define sqlite4_bind_int              dls_funcs.bind_int
118 #define sqlite4_bind_int64            dls_funcs.bind_int64
119 #define sqlite4_bind_null             dls_funcs.bind_null
120 #define sqlite4_bind_parameter_count  dls_funcs.bind_parameter_count
121 #define sqlite4_bind_text             dls_funcs.bind_text
122 #define sqlite4_changes               dls_funcs.changes
123 #define sqlite4_close                 dls_funcs.close
124 #define sqlite4_column_blob           dls_funcs.column_blob
125 #define sqlite4_column_bytes          dls_funcs.column_bytes
126 #define sqlite4_column_count          dls_funcs.column_count
127 #define sqlite4_column_database_name  dls_funcs.column_database_name
128 #define sqlite4_column_decltype       dls_funcs.column_decltype
129 #define sqlite4_column_double         dls_funcs.column_double
130 #define sqlite4_column_name           dls_funcs.column_name
131 #define sqlite4_column_origin_name    dls_funcs.column_origin_name
132 #define sqlite4_column_table_name     dls_funcs.column_table_name
133 #define sqlite4_column_text           dls_funcs.column_text
134 #define sqlite4_column_type           dls_funcs.column_type
135 #define sqlite4_create_function       dls_funcs.create_function
136 #define sqlite4_errcode               dls_funcs.errcode
137 #define sqlite4_errmsg                dls_funcs.errmsg
138 #define sqlite4_exec                  dls_funcs.exec
139 #define sqlite4_finalize              dls_funcs.finalize
140 #define sqlite4_free                  dls_funcs.free
141 #define sqlite4_interrupt             dls_funcs.interrupt
142 #if 0
143 #define sqlite4_last_insert_rowid     dls_funcs.last_insert_rowid
144 #endif
145 #define sqlite4_libversion            dls_funcs.libversion
146 #if 0
147 #define sqlite4_load_extension        dls_funcs.load_extension
148 #endif
149 #define sqlite4_malloc                dls_funcs.malloc
150 #define sqlite4_mprintf               dls_funcs.mprintf
151 #define sqlite4_open                  dls_funcs.open
152 #define sqlite4_prepare               dls_funcs.prepare
153 #define sqlite4_profile               dls_funcs.profile
154 #define sqlite4_realloc               dls_funcs.realloc
155 #define sqlite4_reset                 dls_funcs.reset
156 #define sqlite4_result_blob           dls_funcs.result_blob
157 #define sqlite4_result_error          dls_funcs.result_error
158 #define sqlite4_result_int            dls_funcs.result_int
159 #define sqlite4_result_null           dls_funcs.result_null
160 #define sqlite4_step                  dls_funcs.step
161 #define sqlite4_strnicmp              dls_funcs.xstrnicmp
162 #if 0
163 #define sqlite4_table_column_metadata dls_funcs.table_column_metadata
164 #endif
165 #define sqlite4_trace                 dls_funcs.trace
166 #define sqlite4_user_data             dls_funcs.user_data
167 #define sqlite4_value_blob            dls_funcs.value_blob
168 #define sqlite4_value_bytes           dls_funcs.value_bytes
169 #define sqlite4_value_text            dls_funcs.value_text
170 #define sqlite4_value_type            dls_funcs.value_type
171 
172 #endif
173 
174 #ifndef WITHOUT_WINTERFACE
175 #define WINTERFACE
176 #define WCHARSUPPORT
177 #endif
178 
179 #if !defined(_WIN32) && !defined(_WIN64)
180 #if !defined(WCHARSUPPORT) && defined(HAVE_SQLWCHAR) && (HAVE_SQLWCHAR)
181 #define WCHARSUPPORT
182 #endif
183 #endif
184 
185 #if defined(WINTERFACE)
186 #include <sqlucode.h>
187 #endif
188 
189 #if defined(_WIN32) || defined(_WIN64)
190 #include "resource3.h"
191 #define ODBC_INI "ODBC.INI"
192 #ifndef DRIVER_VER_INFO
193 #define DRIVER_VER_INFO VERSION
194 #endif
195 #else
196 #define ODBC_INI ".odbc.ini"
197 #endif
198 
199 #ifndef DRIVER_VER_INFO
200 #define DRIVER_VER_INFO "0.0"
201 #endif
202 
203 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
204 #ifdef _WIN64
205 #define COLATTRIBUTE_LAST_ARG_TYPE SQLLEN *
206 #else
207 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
208 #endif
209 #endif
210 
211 #ifndef SETSTMTOPTION_LAST_ARG_TYPE
212 #define SETSTMTOPTION_LAST_ARG_TYPE SQLROWCOUNT
213 #endif
214 
215 #undef min
216 #define min(a, b) ((a) < (b) ? (a) : (b))
217 #undef max
218 #define max(a, b) ((a) < (b) ? (b) : (a))
219 
220 #ifndef PTRDIFF_T
221 #define PTRDIFF_T int
222 #endif
223 
224 #define array_size(x) (sizeof (x) / sizeof (x[0]))
225 
226 #define stringify1(s) #s
227 #define stringify(s) stringify1(s)
228 
229 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
230 
231 /* Column types for static string column descriptions (SQLTables etc.) */
232 
233 #if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
234 #define SCOL_VARCHAR SQL_WVARCHAR
235 #define SCOL_CHAR SQL_WCHAR
236 #else
237 #define SCOL_VARCHAR SQL_VARCHAR
238 #define SCOL_CHAR SQL_CHAR
239 #endif
240 
241 #define ENV_MAGIC  0x53544145
242 #define DBC_MAGIC  0x53544144
243 #define DEAD_MAGIC 0xdeadbeef
244 
245 /**
246  * @typedef dstr
247  * @struct dstr
248  * Internal structure representing dynamic strings.
249  */
250 
251 typedef struct dstr {
252     int len;		/**< Current length. */
253     int max;		/**< Maximum length of buffer. */
254     int oom;		/**< True when out of memory. */
255     char buffer[1];	/**< String buffer. */
256 } dstr;
257 
258 static const char *xdigits = "0123456789ABCDEFabcdef";
259 
260 #ifdef MEMORY_DEBUG
261 
262 static void *
xmalloc_(int n,char * file,int line)263 xmalloc_(int n, char *file, int line)
264 {
265     int nn = n + 4 * sizeof (long);
266     long *p;
267 
268     p = malloc(nn);
269     if (!p) {
270 #if (MEMORY_DEBUG > 1)
271 	fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
272 #endif
273 	return NULL;
274     }
275     p[0] = 0xdead1234;
276     nn = nn / sizeof (long) - 1;
277     p[1] = n;
278     p[nn] = 0xdead5678;
279 #if (MEMORY_DEBUG > 1)
280     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
281 #endif
282     return (void *) &p[2];
283 }
284 
285 static void *
xrealloc_(void * old,int n,char * file,int line)286 xrealloc_(void *old, int n, char *file, int line)
287 {
288     int nn = n + 4 * sizeof (long), nnn;
289     long *p, *pp;
290 
291     if (n == 0 || !old) {
292 	return xmalloc_(n, file, line);
293     }
294     p = &((long *) old)[-2];
295     if (p[0] != 0xdead1234) {
296 	fprintf(stderr, "*** low end corruption @ %p\n", old);
297 	abort();
298     }
299     nnn = p[1] + 4 * sizeof (long);
300     nnn = nnn / sizeof (long) - 1;
301     if (p[nnn] != 0xdead5678) {
302 	fprintf(stderr, "*** high end corruption @ %p\n", old);
303 	abort();
304     }
305     pp = realloc(p, nn);
306     if (!pp) {
307 #if (MEMORY_DEBUG > 1)
308 	fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
309 #endif
310 	return NULL;
311     }
312 #if (MEMORY_DEBUG > 1)
313     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
314 #endif
315     p = pp;
316     p[1] = n;
317     nn = nn / sizeof (long) - 1;
318     p[nn] = 0xdead5678;
319     return (void *) &p[2];
320 }
321 
322 static void
xfree_(void * x,char * file,int line)323 xfree_(void *x, char *file, int line)
324 {
325     long *p;
326     int n;
327 
328     if (!x) {
329 	return;
330     }
331     p = &((long *) x)[-2];
332     if (p[0] != 0xdead1234) {
333 	fprintf(stderr, "*** low end corruption @ %p\n", x);
334 	abort();
335     }
336     n = p[1] + 4 * sizeof (long);
337     n = n / sizeof (long) - 1;
338     if (p[n] != 0xdead5678) {
339 	fprintf(stderr, "*** high end corruption @ %p\n", x);
340 	abort();
341     }
342 #if (MEMORY_DEBUG > 1)
343     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
344 #endif
345     free(p);
346 }
347 
348 static void
xfree__(void * x)349 xfree__(void *x)
350 {
351     xfree_(x, "unknown location", 0);
352 }
353 
354 static char *
xstrdup_(const char * str,char * file,int line)355 xstrdup_(const char *str, char *file, int line)
356 {
357     char *p;
358 
359     if (!str) {
360 #if (MEMORY_DEBUG > 1)
361 	fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
362 #endif
363 	return NULL;
364     }
365     p = xmalloc_(strlen(str) + 1, file, line);
366     if (p) {
367 	strcpy(p, str);
368     }
369 #if (MEMORY_DEBUG > 1)
370     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
371 #endif
372     return p;
373 }
374 
375 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
376 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
377 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
378 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
379 
380 #else
381 
382 #define xmalloc(x)    sqlite4_malloc(0, x)
383 #define xrealloc(x,y) sqlite4_realloc(0, x, y)
384 #define xfree(x)      sqlite4_free(0, x)
385 #define xstrdup(x)    strdup_(x)
386 
387 #endif
388 
389 #if defined(_WIN32) || defined(_WIN64)
390 
391 #define vsnprintf   _vsnprintf
392 #define snprintf    _snprintf
393 #define strcasecmp  _stricmp
394 #define strncasecmp _strnicmp
395 
396 #ifdef _MSC_VER
397 #define strtoll     _strtoi64
398 #define strtoull    _strtoui64
399 #endif
400 
401 static HINSTANCE NEAR hModule;	/* Saved module handle for resources */
402 
403 #endif
404 
405 #undef  strncasecmp
406 #define strncasecmp(A,B,C) sqlite4_strnicmp(A,B,C)
407 #undef  strcasecmp
408 #define strcasecmp(A,B) strcasecmp_(A,B)
409 
410 #if defined(__GNUC__) && (__GNUC__ >= 2)
411 static int strcasecmp_(const char *a, const char *b)
412     __attribute__((__unused__));
413 #endif
414 
strcasecmp_(const char * a,const char * b)415 static int strcasecmp_(const char *a, const char *b)
416 {
417     int c = strlen(a), d = strlen(b);
418 
419     if (c > d) {
420 	return strncasecmp(a, b, c);
421     }
422     return strncasecmp(a, b, d);
423 }
424 
425 #if defined(_WIN32) || defined(_WIN64)
426 
427 /*
428  * SQLHENV, SQLHDBC, and SQLHSTMT synchronization
429  * is done using a critical section in ENV and DBC
430  * structures.
431  */
432 
433 #define HDBC_LOCK(hdbc)				\
434 {						\
435     DBC *d;					\
436 						\
437     if ((hdbc) == SQL_NULL_HDBC) {		\
438 	return SQL_INVALID_HANDLE;		\
439     }						\
440     d = (DBC *) (hdbc);				\
441     if (d->magic != DBC_MAGIC) {		\
442 	return SQL_INVALID_HANDLE;		\
443     }						\
444     EnterCriticalSection(&d->cs);		\
445     d->owner = GetCurrentThreadId();		\
446 }
447 
448 #define HDBC_UNLOCK(hdbc)			\
449     if ((hdbc) != SQL_NULL_HDBC) {		\
450 	DBC *d;					\
451 						\
452 	d = (DBC *) (hdbc);			\
453 	if (d->magic == DBC_MAGIC) {		\
454 	    LeaveCriticalSection(&d->cs);	\
455 	}					\
456     }
457 
458 #define HSTMT_LOCK(hstmt)			\
459 {						\
460     DBC *d;					\
461 						\
462     if ((hstmt) == SQL_NULL_HSTMT) {		\
463 	return SQL_INVALID_HANDLE;		\
464     }						\
465     d = (DBC *) ((STMT *) (hstmt))->dbc;	\
466     if (d->magic != DBC_MAGIC) {		\
467 	return SQL_INVALID_HANDLE;		\
468     }						\
469     if (d->env->magic != ENV_MAGIC) {		\
470 	return SQL_INVALID_HANDLE;		\
471     }						\
472     EnterCriticalSection(&d->cs);		\
473     d->owner = GetCurrentThreadId();		\
474 }
475 
476 #define HSTMT_UNLOCK(hstmt)			\
477     if ((hstmt) != SQL_NULL_HSTMT) {		\
478 	DBC *d;					\
479 						\
480 	d = (DBC *) ((STMT *) (hstmt))->dbc;	\
481 	if (d->magic == DBC_MAGIC) {		\
482 	    LeaveCriticalSection(&d->cs);	\
483 	}					\
484     }
485 
486 #else
487 
488 /*
489  * On UN*X assume that we are single-threaded or
490  * the driver manager provides serialization for us.
491  *
492  * In iODBC (3.52.x) serialization can be turned
493  * on using the DSN property "ThreadManager=yes".
494  *
495  * In unixODBC that property is named
496  * "Threading=0-3" and takes one of these values:
497  *
498  *   0 - no protection
499  *   1 - statement level protection
500  *   2 - connection level protection
501  *   3 - environment level protection
502  *
503  * unixODBC 2.2.11 uses environment level protection
504  * by default when it has been built with pthread
505  * support.
506  */
507 
508 #define HDBC_LOCK(hdbc)
509 #define HDBC_UNLOCK(hdbc)
510 #define HSTMT_LOCK(hdbc)
511 #define HSTMT_UNLOCK(hdbc)
512 
513 #endif
514 
515 /*
516  * tolower() replacement w/o locale
517  */
518 
519 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
520 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
521 
522 static int
TOLOWER(int c)523 TOLOWER(int c)
524 {
525     if (c) {
526 	char *p = strchr(upper_chars, c);
527 
528 	if (p) {
529 	    c = lower_chars[p - upper_chars];
530 	}
531     }
532     return c;
533 }
534 
535 /*
536  * isdigit() replacement w/o ctype.h
537  */
538 
539 static const char digit_chars[] = "0123456789";
540 
541 #define ISDIGIT(c) \
542     ((c) && strchr(digit_chars, (c)) != NULL)
543 
544 /*
545  * isspace() replacement w/o ctype.h
546  */
547 
548 static const char space_chars[] = " \f\n\r\t\v";
549 
550 #define ISSPACE(c) \
551     ((c) && strchr(space_chars, (c)) != NULL)
552 
553 
554 /*
555  * Forward declarations of static functions.
556  */
557 
558 static void dbtraceapi(DBC *d, char *fn, const char *sql);
559 static void freedyncols(STMT *s);
560 static void freeresult(STMT *s, int clrcols);
561 static void freerows(char **rowp);
562 static void unbindcols(STMT *s);
563 static void s4stmt_drop(STMT *s);
564 
565 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
566 static SQLRETURN freestmt(HSTMT stmt);
567 static SQLRETURN mkbindcols(STMT *s, int ncols);
568 static SQLRETURN setupdyncols(STMT *s, sqlite4_stmt *s4stmt, int *ncolsp);
569 static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
570 static SQLRETURN starttran(STMT *s);
571 static SQLRETURN setupparam(STMT *s, char *sql, int pnum);
572 static SQLRETURN getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
573 			    SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp,
574 			    int partial);
575 
576 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
577 /* MS Access hack part 1 (reserved error -7748) */
578 static COL *statSpec2P, *statSpec3P;
579 #endif
580 
581 #if (MEMORY_DEBUG < 1)
582 /**
583  * Duplicate string using xmalloc().
584  * @param str string to be duplicated
585  * @result pointer to new string or NULL
586  */
587 
588 static char *
strdup_(const char * str)589 strdup_(const char *str)
590 {
591     char *p = NULL;
592 
593     if (str) {
594 	p = xmalloc(strlen(str) + 1);
595 	if (p) {
596 	    strcpy(p, str);
597 	}
598     }
599     return p;
600 }
601 #endif
602 
603 /**
604  * Append string to dynamic string.
605  * @param dsp dstr pointer
606  * @param str string to append
607  * @result dsp result dstr pointer or NULL.
608  */
609 
610 static dstr *
dsappend(dstr * dsp,const char * str)611 dsappend(dstr *dsp, const char *str)
612 {
613     int len;
614 
615     if (!str) {
616 	return dsp;
617     }
618     len = strlen(str);
619     if (!dsp) {
620 	int max = 256;
621 
622 	if (max < len) {
623 	    max += len;
624 	}
625 	dsp = xmalloc(max);
626 	if (dsp) {
627 	    dsp->max = max;
628 	    dsp->len = dsp->oom = 0;
629 	    goto copy;
630 	}
631 	return dsp;
632     }
633     if (dsp->oom) {
634 	return dsp;
635     }
636     if (dsp->len + len > dsp->max) {
637 	int max = dsp->max + len + 256;
638 	dstr *ndsp = xrealloc(dsp, max);
639 
640 	if (!ndsp) {
641 	    strcpy(dsp->buffer, "OUT OF MEMORY");
642 	    dsp->max = dsp->len = 13;
643 	    dsp->oom = 1;
644 	    return dsp;
645 	}
646 	dsp = ndsp;
647 	dsp->max = max;
648     }
649 copy:
650     strcpy(dsp->buffer + dsp->len, str);
651     dsp->len += len;
652     return dsp;
653 }
654 
655 /**
656  * Append a string double quoted to dynamic string.
657  * @param dsp dstr pointer
658  * @param str string to append
659  * @result dsp result dstr pointer or NULL.
660  */
661 
662 static dstr *
dsappendq(dstr * dsp,const char * str)663 dsappendq(dstr *dsp, const char *str)
664 {
665     int len;
666     const char *p;
667     char *q;
668 
669     if (!str) {
670 	return dsp;
671     }
672     len = strlen(str);
673     for (p = str; *p; ++p) {
674 	if (p[0] == '"') {
675 	    ++len;
676 	}
677     }
678     len += 2;
679     if (!dsp) {
680 	int max = 256;
681 
682 	if (max < len) {
683 	    max += len;
684 	}
685 	dsp = xmalloc(max);
686 	if (dsp) {
687 	    dsp->max = max;
688 	    dsp->len = dsp->oom = 0;
689 	    goto copy;
690 	}
691 	return dsp;
692     }
693     if (dsp->oom) {
694 	return dsp;
695     }
696     if (dsp->len + len > dsp->max) {
697 	int max = dsp->max + len + 256;
698 	dstr *ndsp = xrealloc(dsp, max);
699 
700 	if (!ndsp) {
701 	    strcpy(dsp->buffer, "OUT OF MEMORY");
702 	    dsp->max = dsp->len = 13;
703 	    dsp->oom = 1;
704 	    return dsp;
705 	}
706 	dsp = ndsp;
707 	dsp->max = max;
708     }
709 copy:
710     q = dsp->buffer + dsp->len;
711     *q++ = '"';
712     for (p = str; *p; ++p) {
713 	*q++ = *p;
714 	if (p[0] == '"') {
715 	    *q++ = '"';
716 	}
717     }
718     *q++ = '"';
719     *q = '\0';
720     dsp->len += len;
721     return dsp;
722 }
723 
724 /**
725  * Return dynamic string's value.
726  * @param dsp dstr pointer
727  * @result string value
728  */
729 
730 static const char *
dsval(dstr * dsp)731 dsval(dstr *dsp)
732 {
733     if (dsp) {
734 	return (const char *) dsp->buffer;
735     }
736     return "ERROR";
737 }
738 
739 /**
740  * Check error on dynamic string.
741  * @param dsp dstr pointer
742  * @result true when error pending
743  */
744 
745 static int
dserr(dstr * dsp)746 dserr(dstr *dsp)
747 {
748     return !dsp || dsp->oom;
749 }
750 
751 /**
752  * Free dynamic string.
753  * @param dsp dstr pointer
754  */
755 
756 static void
dsfree(dstr * dsp)757 dsfree(dstr *dsp)
758 {
759     if (dsp) {
760 	xfree(dsp);
761     }
762 }
763 
764 #ifdef WCHARSUPPORT
765 
766 /**
767  * Return length of UNICODE string.
768  * @param str UNICODE string
769  * @result length of string in characters
770  */
771 
772 static int
uc_strlen(SQLWCHAR * str)773 uc_strlen(SQLWCHAR *str)
774 {
775     int len = 0;
776 
777     if (str) {
778 	while (*str) {
779 	    ++len;
780 	    ++str;
781 	}
782     }
783     return len;
784 }
785 
786 /**
787  * Copy UNICODE string like strncpy().
788  * @param dest destination area
789  * @param src source area
790  * @param len length of source area in characters
791  * @return pointer to destination area
792  */
793 
794 static SQLWCHAR *
uc_strncpy(SQLWCHAR * dest,SQLWCHAR * src,int len)795 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
796 {
797     int i = 0;
798 
799     while (i < len) {
800 	if (!src[i]) {
801 	    break;
802 	}
803 	dest[i] = src[i];
804 	++i;
805     }
806     if (i < len) {
807 	dest[i] = 0;
808     }
809     return dest;
810 }
811 
812 /**
813  * Make UNICODE string from UTF8 string into buffer.
814  * @param str UTF8 string to be converted
815  * @param len length in characters of str or -1
816  * @param uc destination area to receive UNICODE string
817  * @param ucLen byte length of destination area
818  */
819 
820 static void
uc_from_utf_buf(unsigned char * str,int len,SQLWCHAR * uc,int ucLen)821 uc_from_utf_buf(unsigned char *str, int len, SQLWCHAR *uc, int ucLen)
822 {
823     ucLen = ucLen / sizeof (SQLWCHAR);
824     if (!uc || ucLen < 0) {
825 	return;
826     }
827     if (len < 0) {
828 	len = ucLen * 5;
829     }
830     uc[0] = 0;
831     if (str) {
832 	int i = 0;
833 
834 	while (i < len && *str && i < ucLen) {
835 	    unsigned char c = str[0];
836 
837 	    if (c < 0x80) {
838 		uc[i++] = c;
839 		++str;
840 	    } else if (c <= 0xc1 || c >= 0xf5) {
841 		/* illegal, ignored */
842 		++str;
843 	    } else if (c < 0xe0) {
844 		if ((str[1] & 0xc0) == 0x80) {
845 		    unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
846 
847 		    uc[i++] = t;
848 		    str += 2;
849 		} else {
850 		    uc[i++] = c;
851 		    ++str;
852 		}
853 	    } else if (c < 0xf0) {
854 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
855 		    unsigned long t = ((c & 0x0f) << 12) |
856 			((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
857 
858 		    uc[i++] = t;
859 		    str += 3;
860 		} else {
861 		    uc[i++] = c;
862 		    ++str;
863 		}
864 	    } else if (c < 0xf8) {
865 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
866 		    (str[3] & 0xc0) == 0x80) {
867 		    unsigned long t = ((c & 0x03) << 18) |
868 			((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
869 			(str[3] & 0x3f);
870 
871 		    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
872 			t >= 0x10000) {
873 			t -= 0x10000;
874 			uc[i++] = 0xd800 | ((t >> 10) & 0x3ff);
875 			if (i >= ucLen) {
876 			    break;
877 			}
878 			t = 0xdc00 | (t & 0x3ff);
879 		    }
880 		    uc[i++] = t;
881 		    str += 4;
882 		} else {
883 		    uc[i++] = c;
884 		    ++str;
885 		}
886 	    }
887 	}
888 	if (i < ucLen) {
889 	    uc[i] = 0;
890 	}
891     }
892 }
893 
894 /**
895  * Make UNICODE string from UTF8 string.
896  * @param str UTF8 string to be converted
897  * @param len length of UTF8 string
898  * @return alloc'ed UNICODE string to be free'd by uc_free()
899  */
900 
901 static SQLWCHAR *
uc_from_utf(unsigned char * str,int len)902 uc_from_utf(unsigned char *str, int len)
903 {
904     SQLWCHAR *uc = NULL;
905     int ucLen;
906 
907     if (str) {
908 	if (len == SQL_NTS) {
909 	    len = strlen((char *) str);
910 	}
911 	ucLen = sizeof (SQLWCHAR) * (len + 1);
912 	uc = xmalloc(ucLen);
913 	if (uc) {
914 	    uc_from_utf_buf(str, len, uc, ucLen);
915 	}
916     }
917     return uc;
918 }
919 
920 /**
921  * Make UTF8 string from UNICODE string.
922  * @param str UNICODE string to be converted
923  * @param len length of UNICODE string in bytes
924  * @return alloc'ed UTF8 string to be free'd by uc_free()
925  */
926 
927 static char *
uc_to_utf(SQLWCHAR * str,int len)928 uc_to_utf(SQLWCHAR *str, int len)
929 {
930     int i;
931     char *cp, *ret = NULL;
932 
933     if (!str) {
934 	return ret;
935     }
936     if (len == SQL_NTS) {
937 	len = uc_strlen(str);
938     } else {
939 	len = len / sizeof (SQLWCHAR);
940     }
941     cp = xmalloc(len * 6 + 1);
942     if (!cp) {
943 	return ret;
944     }
945     ret = cp;
946     for (i = 0; i < len; i++) {
947 	unsigned long c = str[i];
948 
949 	if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
950 	    c &= 0xffff;
951 	}
952 	if (c < 0x80) {
953 	    *cp++ = c;
954 	} else if (c < 0x800) {
955 	    *cp++ = 0xc0 | ((c >> 6) & 0x1f);
956 	    *cp++ = 0x80 | (c & 0x3f);
957 	} else if (c < 0x10000) {
958 	    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
959 		c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
960 		unsigned long c2 = str[i + 1] & 0xffff;
961 
962 		if (c2 >= 0xdc00 && c2 <= 0xdfff) {
963 		    c = (((c & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10000;
964 		    *cp++ = 0xf0 | ((c >> 18) & 0x07);
965 		    *cp++ = 0x80 | ((c >> 12) & 0x3f);
966 		    *cp++ = 0x80 | ((c >> 6) & 0x3f);
967 		    *cp++ = 0x80 | (c & 0x3f);
968 		    ++i;
969 		    continue;
970 		}
971 	    }
972 	    *cp++ = 0xe0 | ((c >> 12) & 0x0f);
973 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
974 	    *cp++ = 0x80 | (c & 0x3f);
975 	} else if (c <= 0x10ffff) {
976 	    *cp++ = 0xf0 | ((c >> 18) & 0x07);
977 	    *cp++ = 0x80 | ((c >> 12) & 0x3f);
978 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
979 	    *cp++ = 0x80 | (c & 0x3f);
980 	}
981     }
982     *cp = '\0';
983     return ret;
984 }
985 
986 #endif
987 
988 #ifdef WINTERFACE
989 
990 /**
991  * Make UTF8 string from UNICODE string.
992  * @param str UNICODE string to be converted
993  * @param len length of UNICODE string in characters
994  * @return alloc'ed UTF8 string to be free'd by uc_free()
995  */
996 
997 static char *
uc_to_utf_c(SQLWCHAR * str,int len)998 uc_to_utf_c(SQLWCHAR *str, int len)
999 {
1000     if (len != SQL_NTS) {
1001 	len = len * sizeof (SQLWCHAR);
1002     }
1003     return uc_to_utf(str, len);
1004 }
1005 
1006 #endif
1007 
1008 #if defined(WCHARSUPPORT) || defined(_WIN32) || defined(_WIN64)
1009 
1010 /**
1011  * Free converted UTF8 or UNICODE string.
1012  * @param str string to be free'd
1013  */
1014 
1015 static void
uc_free(void * str)1016 uc_free(void *str)
1017 {
1018     if (str) {
1019 	xfree(str);
1020     }
1021 }
1022 
1023 #endif
1024 
1025 #if defined(_WIN32) || defined(_WIN64)
1026 
1027 /**
1028  * Convert multibyte, current code page string to UTF8 string,
1029  * @param str multibyte string to be converted
1030  * @param len length of multibyte string
1031  * @return alloc'ed UTF8 string to be free'd by uc_free()
1032  */
1033 
1034 static char *
wmb_to_utf(char * str,int len)1035 wmb_to_utf(char *str, int len)
1036 {
1037     WCHAR *wstr;
1038     OSVERSIONINFO ovi;
1039     int nchar, is2k, cp = CP_OEMCP;
1040 
1041     ovi.dwOSVersionInfoSize = sizeof (ovi);
1042     GetVersionEx(&ovi);
1043     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1044     if (AreFileApisANSI()) {
1045 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1046     }
1047     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
1048     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1049     if (!wstr) {
1050 	return NULL;
1051     }
1052     wstr[0] = 0;
1053     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
1054     wstr[nchar] = 0;
1055     str = xmalloc((nchar + 1) * 7);
1056     if (!str) {
1057 	xfree(wstr);
1058 	return NULL;
1059     }
1060     str[0] = '\0';
1061     nchar = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, nchar * 7, 0, 0);
1062     str[nchar] = '\0';
1063     xfree(wstr);
1064     return str;
1065 }
1066 
1067 #ifndef WINTERFACE
1068 
1069 /**
1070  * Convert multibyte, current code page string to UTF8 string,
1071  * @param str multibyte string to be converted
1072  * @param len length of multibyte string
1073  * @return alloc'ed UTF8 string to be free'd by uc_free()
1074  */
1075 
1076 static char *
wmb_to_utf_c(char * str,int len)1077 wmb_to_utf_c(char *str, int len)
1078 {
1079     if (len == SQL_NTS) {
1080 	len = strlen(str);
1081     }
1082     return wmb_to_utf(str, len);
1083 }
1084 
1085 #endif
1086 
1087 /**
1088  * Convert UTF8 string to multibyte, current code page string,
1089  * @param str UTF8 string to be converted
1090  * @param len length of UTF8 string
1091  * @return alloc'ed multibyte string to be free'd by uc_free()
1092  */
1093 
1094 static char *
utf_to_wmb(char * str,int len)1095 utf_to_wmb(char *str, int len)
1096 {
1097     WCHAR *wstr;
1098     OSVERSIONINFO ovi;
1099     int nchar, is2k, cp = CP_OEMCP;
1100 
1101     ovi.dwOSVersionInfoSize = sizeof (ovi);
1102     GetVersionEx(&ovi);
1103     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1104     if (AreFileApisANSI()) {
1105 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1106     }
1107     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
1108     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1109     if (!wstr) {
1110 	return NULL;
1111     }
1112     wstr[0] = 0;
1113     nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, nchar);
1114     wstr[nchar] = 0;
1115     str = xmalloc((nchar + 1) * 7);
1116     if (!str) {
1117 	xfree(wstr);
1118 	return NULL;
1119     }
1120     str[0] = '\0';
1121     nchar = WideCharToMultiByte(cp, 0, wstr, -1, str, nchar * 7, 0, 0);
1122     str[nchar] = '\0';
1123     xfree(wstr);
1124     return str;
1125 }
1126 
1127 #ifdef WINTERFACE
1128 
1129 /**
1130  * Convert multibyte, current code page string to UNICODE string,
1131  * @param str multibyte string to be converted
1132  * @param len length of multibyte string
1133  * @return alloc'ed UNICODE string to be free'd by uc_free()
1134  */
1135 
1136 static WCHAR *
wmb_to_uc(char * str,int len)1137 wmb_to_uc(char *str, int len)
1138 {
1139     WCHAR *wstr;
1140     OSVERSIONINFO ovi;
1141     int nchar, is2k, cp = CP_OEMCP;
1142 
1143     ovi.dwOSVersionInfoSize = sizeof (ovi);
1144     GetVersionEx(&ovi);
1145     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1146     if (AreFileApisANSI()) {
1147 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1148     }
1149     nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
1150     wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
1151     if (!wstr) {
1152 	return NULL;
1153     }
1154     wstr[0] = 0;
1155     nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
1156     wstr[nchar] = 0;
1157     return wstr;
1158 }
1159 
1160 /**
1161  * Convert UNICODE string to multibyte, current code page string,
1162  * @param str UNICODE string to be converted
1163  * @param len length of UNICODE string
1164  * @return alloc'ed multibyte string to be free'd by uc_free()
1165  */
1166 
1167 static char *
uc_to_wmb(WCHAR * wstr,int len)1168 uc_to_wmb(WCHAR *wstr, int len)
1169 {
1170     char *str;
1171     OSVERSIONINFO ovi;
1172     int nchar, is2k, cp = CP_OEMCP;
1173 
1174     ovi.dwOSVersionInfoSize = sizeof (ovi);
1175     GetVersionEx(&ovi);
1176     is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
1177     if (AreFileApisANSI()) {
1178 	cp = is2k ? CP_THREAD_ACP : CP_ACP;
1179     }
1180     nchar = WideCharToMultiByte(cp, 0, wstr, len, NULL, 0, 0, 0);
1181     str = xmalloc((nchar + 1) * 2);
1182     if (!str) {
1183 	return NULL;
1184     }
1185     str[0] = '\0';
1186     nchar = WideCharToMultiByte(cp, 0, wstr, len, str, nchar * 2, 0, 0);
1187     str[nchar] = '\0';
1188     return str;
1189 }
1190 
1191 #endif /* WINTERFACE */
1192 
1193 #endif /* _WIN32 || _WIN64 */
1194 
1195 
1196 #ifdef USE_DLOPEN_FOR_GPPS
1197 
1198 #include <dlfcn.h>
1199 
1200 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
1201 
1202 /*
1203  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
1204  * dlopen(), in theory this makes the driver independent from the
1205  * driver manager, i.e. the same driver binary can run with iODBC
1206  * and unixODBC.
1207  */
1208 
1209 static void
drvgetgpps(DBC * d)1210 drvgetgpps(DBC *d)
1211 {
1212     void *lib;
1213     int (*gpps)();
1214 
1215     lib = dlopen("libodbcinst.so.2", RTLD_LAZY);
1216     if (!lib) {
1217 	lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
1218     }
1219     if (!lib) {
1220 	lib = dlopen("libodbcinst.so", RTLD_LAZY);
1221     }
1222     if (!lib) {
1223 	lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
1224     }
1225     if (!lib) {
1226 	lib = dlopen("libiodbcinst.so", RTLD_LAZY);
1227     }
1228     if (lib) {
1229 	gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
1230 	if (!gpps) {
1231 	    dlclose(lib);
1232 	    return;
1233 	}
1234 	d->instlib = lib;
1235 	d->gpps = gpps;
1236     }
1237 }
1238 
1239 static void
drvrelgpps(DBC * d)1240 drvrelgpps(DBC *d)
1241 {
1242     if (d->instlib) {
1243 	dlclose(d->instlib);
1244 	d->instlib = 0;
1245     }
1246 }
1247 
1248 static int
drvgpps(DBC * d,char * sect,char * ent,char * def,char * buf,int bufsiz,char * fname)1249 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
1250 	int bufsiz, char *fname)
1251 {
1252     if (d->gpps) {
1253 	return d->gpps(sect, ent, def, buf, bufsiz, fname);
1254     }
1255     strncpy(buf, def, bufsiz);
1256     buf[bufsiz - 1] = '\0';
1257     return 1;
1258 }
1259 #else
1260 #include <odbcinst.h>
1261 #define drvgetgpps(d)
1262 #define drvrelgpps(d)
1263 #endif
1264 
1265 /*
1266  * Internal function to bind sqlite4 parameters.
1267  */
1268 
1269 static void
s4bind(DBC * d,sqlite4_stmt * stmt,int nparams,BINDPARM * p)1270 s4bind(DBC *d, sqlite4_stmt *stmt, int nparams, BINDPARM *p)
1271 {
1272     int i;
1273 
1274     if (stmt && p && nparams > 0) {
1275 	for (i = 0; i < nparams; i++, p++) {
1276 	    switch (p->s4type) {
1277 	    default:
1278 	    case SQLITE4_NULL:
1279 		sqlite4_bind_null(stmt, i + 1);
1280 		if (d->trace) {
1281 		    fprintf(d->trace, "-- parameter %d: NULL\n", i + 1);
1282 		    fflush(d->trace);
1283 		}
1284 		break;
1285 	    case SQLITE4_TEXT:
1286 		sqlite4_bind_text(stmt, i + 1, p->s4val, p->s4size,
1287 				  SQLITE4_STATIC, 0);
1288 		if (d->trace) {
1289 		    fprintf(d->trace, "-- parameter %d: '%*s'\n", i + 1,
1290 			    p->s4size, (char *) p->s4val);
1291 		    fflush(d->trace);
1292 		}
1293 		break;
1294 	    case SQLITE4_BLOB:
1295 		sqlite4_bind_blob(stmt, i + 1, p->s4val, p->s4size,
1296 				  SQLITE4_STATIC, 0);
1297 		if (d->trace) {
1298 		    fprintf(d->trace, "-- parameter %d: [BLOB]'\n", i + 1);
1299 		    fflush(d->trace);
1300 		}
1301 		break;
1302 	    case SQLITE4_FLOAT:
1303 		sqlite4_bind_double(stmt, i + 1, p->s4dval);
1304 		if (d->trace) {
1305 		    fprintf(d->trace, "-- parameter %d: %g\n",
1306 			    i + 1, p->s4dval);
1307 		    fflush(d->trace);
1308 		}
1309 		break;
1310 	    case SQLITE4_INTEGER:
1311 		if (p->s4size > sizeof (int)) {
1312 		    sqlite4_bind_int64(stmt, i + 1, p->s4lival);
1313 		    if (d->trace) {
1314 			fprintf(d->trace,
1315 #ifdef _WIN32
1316 				"-- parameter %d: %I64d\n",
1317 #else
1318 				"-- parameter %d: %lld\n",
1319 #endif
1320 				i + 1, p->s4lival);
1321 			fflush(d->trace);
1322 		    }
1323 		} else {
1324 		    sqlite4_bind_int(stmt, i + 1, p->s4ival);
1325 		    if (d->trace) {
1326 			fprintf(d->trace, "-- parameter %d: %d\n",
1327 				i + 1, p->s4ival);
1328 			fflush(d->trace);
1329 		    }
1330 		}
1331 		break;
1332 	    }
1333 	}
1334     }
1335 }
1336 
1337 /**
1338  * @typedef TBLRES
1339  * @struct tblres
1340  * Internal structure for managing driver's
1341  * sqlite4_get_table() implementation.
1342  */
1343 
1344 typedef struct tblres {
1345     char **resarr;	/**< result array */
1346     char *errmsg;	/**< error message or NULL */
1347     sqlite4_stmt *stmt;	/**< sqlite4 statement pointer */
1348     STMT *s;		/**< Driver statement pointer */
1349     int nalloc;		/**< alloc'ed size of result array */
1350     int nrow;		/**< number of rows in result array */
1351     int ncol;		/**< number of columns in result array */
1352     PTRDIFF_T ndata;	/**< index into result array */
1353     int rc;		/**< SQLite return code */
1354 } TBLRES;
1355 
1356 /*
1357  * Driver's version of sqlite4_get_table() and friends which are
1358  * capable of dealing with blobs.
1359  */
1360 
1361 static int
drvgettable_row(TBLRES * t,int ncol,int rc)1362 drvgettable_row(TBLRES *t, int ncol, int rc)
1363 {
1364     int need;
1365     int i;
1366     char *p;
1367 
1368     if (t->nrow == 0 && rc == SQLITE4_ROW) {
1369 	need = ncol * 2;
1370     } else {
1371 	need = ncol;
1372     }
1373     if (t->ndata + need >= t->nalloc) {
1374 	char **resnew;
1375 	int nalloc = t->nalloc * 2 + need + 1;
1376 
1377 	resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
1378 	if (!resnew) {
1379 nomem:
1380 	    t->rc = SQLITE4_NOMEM;
1381 	    return 1;
1382 	}
1383 	t->nalloc = nalloc;
1384 	t->resarr = resnew;
1385     }
1386     /* column names when first row */
1387     if (t->nrow == 0) {
1388 	t->ncol = ncol;
1389 	for (i = 0; i < ncol; i++) {
1390 	    p = (char *) sqlite4_column_name(t->stmt, i);
1391 	    if (p) {
1392 		char *q = xmalloc(strlen(p) + 1);
1393 
1394 		if (!q) {
1395 		    goto nomem;
1396 		}
1397 		strcpy(q, p);
1398 		p = q;
1399 	    }
1400 	    t->resarr[t->ndata++] = p;
1401 	}
1402 	if (t->s && t->s->guessed_types) {
1403 	    int ncol2 = ncol;
1404 
1405 	    setupdyncols(t->s, t->stmt, &ncol2);
1406 	    t->s->guessed_types = 0;
1407 	    t->s->ncols = ncol;
1408 	}
1409     } else if (t->ncol != ncol) {
1410 	t->errmsg = sqlite4_mprintf(0, "drvgettable() called with two or"
1411 				    " more incompatible queries");
1412 	t->rc = SQLITE4_ERROR;
1413 	return 1;
1414     }
1415     /* copy row data */
1416     if (rc == SQLITE4_ROW) {
1417 	for (i = 0; i < ncol; i++) {
1418 	    int coltype = sqlite4_column_type(t->stmt, i);
1419 
1420 	    p = NULL;
1421 	    if (coltype == SQLITE4_BLOB) {
1422 		int k, nbytes;
1423 		char *qp;
1424 		unsigned const char *bp;
1425 
1426 		bp = sqlite4_column_blob(t->stmt, i, &nbytes);
1427 		qp = xmalloc(nbytes * 2 + 4);
1428 		if (!qp) {
1429 		    goto nomem;
1430 		}
1431 		p = qp;
1432 		*qp++ = 'X';
1433 		*qp++ = '\'';
1434 		for (k = 0; k < nbytes; k++) {
1435 		    *qp++ = xdigits[(bp[k] >> 4)];
1436 		    *qp++ = xdigits[(bp[k] & 0xF)];
1437 		}
1438 		*qp++ = '\'';
1439 		*qp = '\0';
1440 	    } else if (coltype != SQLITE4_NULL) {
1441 		int nbytes;
1442 
1443 		p = xstrdup((char *) sqlite4_column_text(t->stmt, i, &nbytes));
1444 		if (!p) {
1445 		    goto nomem;
1446 		}
1447 	    }
1448 	    t->resarr[t->ndata++] = p;
1449 	}
1450 	t->nrow++;
1451     }
1452     return 0;
1453 }
1454 
1455 static int
drvgettable(STMT * s,const char * sql,char *** resp,int * nrowp,int * ncolp,char ** errp,int nparam,BINDPARM * p)1456 drvgettable(STMT *s, const char *sql, char ***resp, int *nrowp,
1457 	    int *ncolp, char **errp, int nparam, BINDPARM *p)
1458 {
1459     DBC *d = (DBC *) s->dbc;
1460     int rc = SQLITE4_OK, keep = sql == NULL;
1461     TBLRES tres;
1462     int sqlleft = 0;
1463     int nretry = 0, haveerr = 0;
1464 
1465     if (!resp) {
1466 	return SQLITE4_ERROR;
1467     }
1468     *resp = NULL;
1469     if (nrowp) {
1470 	*nrowp = 0;
1471     }
1472     if (ncolp) {
1473 	*ncolp = 0;
1474     }
1475     tres.errmsg = NULL;
1476     tres.nrow = 0;
1477     tres.ncol = 0;
1478     tres.ndata = 1;
1479     tres.nalloc = 20;
1480     tres.rc = SQLITE4_OK;
1481     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
1482     tres.stmt = NULL;
1483     tres.s = s;
1484     if (!tres.resarr) {
1485 	return SQLITE4_NOMEM;
1486     }
1487     tres.resarr[0] = 0;
1488     if (sql == NULL) {
1489 	tres.stmt = s->s4stmt;
1490 	if (tres.stmt == NULL) {
1491 	    return SQLITE4_NOMEM;
1492 	}
1493 	goto retrieve;
1494     }
1495     while (sql && *sql && (rc == SQLITE4_OK ||
1496 			   (rc == SQLITE4_SCHEMA && (++nretry) < 2))) {
1497 	int ncol;
1498 
1499 	tres.stmt = NULL;
1500 	dbtraceapi(d, "sqlite4_prepare", sql);
1501 	rc = sqlite4_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
1502 	if (rc != SQLITE4_OK) {
1503 	    if (tres.stmt) {
1504 		dbtraceapi(d, "sqlite4_finalize", 0);
1505 		sqlite4_finalize(tres.stmt);
1506 		tres.stmt = NULL;
1507 	    }
1508 	    continue;
1509 	}
1510 	if (!tres.stmt) {
1511 	    /* this happens for a comment or white-space */
1512 	    sql += sqlleft;
1513 	    continue;
1514 	}
1515 retrieve:
1516 	if (sqlite4_bind_parameter_count(tres.stmt) != nparam) {
1517 	    if (errp) {
1518 		*errp =
1519 		    sqlite4_mprintf(0, "%s",
1520 				    "parameter marker count incorrect");
1521 	    }
1522 	    haveerr = 1;
1523 	    rc = SQLITE4_ERROR;
1524 	    goto tbldone;
1525 	}
1526 	s4bind(d, tres.stmt, nparam, p);
1527 	ncol = sqlite4_column_count(tres.stmt);
1528 	while (1) {
1529 	    if (s->max_rows && tres.nrow >= s->max_rows) {
1530 		rc = SQLITE4_OK;
1531 		break;
1532 	    }
1533 	    rc = sqlite4_step(tres.stmt);
1534 	    if (rc == SQLITE4_ROW || rc == SQLITE4_DONE) {
1535 		if (drvgettable_row(&tres, ncol, rc)) {
1536 		    rc = SQLITE4_ABORT;
1537 		    goto tbldone;
1538 		}
1539 	    }
1540 	    if (rc != SQLITE4_ROW) {
1541 		if (keep) {
1542 		    dbtraceapi(d, "sqlite4_reset", 0);
1543 		    rc = sqlite4_reset(tres.stmt);
1544 		    s->s4stmt_noreset = 1;
1545 		} else {
1546 		    dbtraceapi(d, "sqlite4_finalize", 0);
1547 		    rc = sqlite4_finalize(tres.stmt);
1548 		}
1549 		tres.stmt = 0;
1550 		if (rc != SQLITE4_SCHEMA) {
1551 		    nretry = 0;
1552 		    sql += sqlleft;
1553 		    while (sql && ISSPACE(*sql)) {
1554 			sql++;
1555 		    }
1556 		}
1557 		if (rc == SQLITE4_DONE) {
1558 		    rc = SQLITE4_OK;
1559 		}
1560 		break;
1561 	    }
1562 	}
1563     }
1564 tbldone:
1565     if (tres.stmt) {
1566 	if (keep) {
1567 	    if (!s->s4stmt_noreset) {
1568 		dbtraceapi(d, "sqlite4_reset", 0);
1569 		sqlite4_reset(tres.stmt);
1570 		s->s4stmt_noreset = 1;
1571 	    }
1572 	} else {
1573 	    dbtraceapi(d, "sqlite4_finalize", 0);
1574 	    sqlite4_finalize(tres.stmt);
1575 	}
1576     }
1577     if (haveerr) {
1578 	/* message already in *errp if any */
1579     } else if (rc != SQLITE4_OK && rc == sqlite4_errcode(d->sqlite) && errp) {
1580 	*errp = sqlite4_mprintf(0, "%s", sqlite4_errmsg(d->sqlite));
1581     } else if (errp) {
1582 	*errp = NULL;
1583     }
1584     if (tres.resarr) {
1585 	tres.resarr[0] = (char *) (tres.ndata - 1);
1586     }
1587     if (rc == SQLITE4_ABORT) {
1588 	freerows(&tres.resarr[1]);
1589 	if (tres.errmsg) {
1590 	    if (errp) {
1591 		if (*errp) {
1592 		    sqlite4_free(0, *errp);
1593 		}
1594 		*errp = tres.errmsg;
1595 	    } else {
1596 		sqlite4_free(0, tres.errmsg);
1597 	    }
1598 	}
1599 	return tres.rc;
1600     }
1601     sqlite4_free(0, tres.errmsg);
1602     if (rc != SQLITE4_OK) {
1603 	freerows(&tres.resarr[1]);
1604 	return rc;
1605     }
1606     *resp = &tres.resarr[1];
1607     if (ncolp) {
1608 	*ncolp = tres.ncol;
1609     }
1610     if (nrowp) {
1611 	*nrowp = tres.nrow;
1612     }
1613     return rc;
1614 }
1615 
1616 static int
sqlite4_get_table(sqlite4 * db,const char * sql,char *** resp,int * nrowp,int * ncolp,char ** errp)1617 sqlite4_get_table(sqlite4 *db, const char *sql, char ***resp, int *nrowp,
1618 		  int *ncolp, char **errp)
1619 {
1620     int rc = SQLITE4_OK;
1621     TBLRES tres;
1622     int sqlleft = 0;
1623     int nretry = 0, haveerr = 0;
1624 
1625     if (!resp) {
1626 	return SQLITE4_ERROR;
1627     }
1628     *resp = NULL;
1629     if (nrowp) {
1630 	*nrowp = 0;
1631     }
1632     if (ncolp) {
1633 	*ncolp = 0;
1634     }
1635     tres.errmsg = NULL;
1636     tres.nrow = 0;
1637     tres.ncol = 0;
1638     tres.ndata = 1;
1639     tres.nalloc = 20;
1640     tres.rc = SQLITE4_OK;
1641     tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
1642     tres.stmt = NULL;
1643     tres.s = 0;
1644     if (!tres.resarr) {
1645 	return SQLITE4_NOMEM;
1646     }
1647     tres.resarr[0] = 0;
1648     while (sql && *sql && (rc == SQLITE4_OK ||
1649 			   (rc == SQLITE4_SCHEMA && (++nretry) < 2))) {
1650 	int ncol;
1651 
1652 	tres.stmt = NULL;
1653 	rc = sqlite4_prepare(db, sql, -1, &tres.stmt, &sqlleft);
1654 	if (rc != SQLITE4_OK) {
1655 	    if (tres.stmt) {
1656 		sqlite4_finalize(tres.stmt);
1657 		tres.stmt = NULL;
1658 	    }
1659 	    continue;
1660 	}
1661 	if (!tres.stmt) {
1662 	    /* this happens for a comment or white-space */
1663 	    sql += sqlleft;
1664 	    continue;
1665 	}
1666 	ncol = sqlite4_column_count(tres.stmt);
1667 	while (1) {
1668 	    rc = sqlite4_step(tres.stmt);
1669 	    if (rc == SQLITE4_ROW || rc == SQLITE4_DONE) {
1670 		if (drvgettable_row(&tres, ncol, rc)) {
1671 		    rc = SQLITE4_ABORT;
1672 		    goto tbldone;
1673 		}
1674 	    }
1675 	    if (rc != SQLITE4_ROW) {
1676 		rc = sqlite4_finalize(tres.stmt);
1677 		tres.stmt = 0;
1678 		if (rc != SQLITE4_SCHEMA) {
1679 		    nretry = 0;
1680 		    sql += sqlleft;
1681 		    while (sql && ISSPACE(*sql)) {
1682 			sql++;
1683 		    }
1684 		}
1685 		if (rc == SQLITE4_DONE) {
1686 		    rc = SQLITE4_OK;
1687 		}
1688 		break;
1689 	    }
1690 	}
1691     }
1692 tbldone:
1693     if (tres.stmt) {
1694 	sqlite4_finalize(tres.stmt);
1695     }
1696     if (haveerr) {
1697 	/* message already in *errp if any */
1698     } else if (rc != SQLITE4_OK && rc == sqlite4_errcode(db) && errp) {
1699 	*errp = sqlite4_mprintf(0, "%s", sqlite4_errmsg(db));
1700     } else if (errp) {
1701 	*errp = NULL;
1702     }
1703     if (tres.resarr) {
1704 	tres.resarr[0] = (char *) (tres.ndata - 1);
1705     }
1706     if (rc == SQLITE4_ABORT) {
1707 	freerows(&tres.resarr[1]);
1708 	if (tres.errmsg) {
1709 	    if (errp) {
1710 		if (*errp) {
1711 		    sqlite4_free(0, *errp);
1712 		}
1713 		*errp = tres.errmsg;
1714 	    } else {
1715 		sqlite4_free(0, tres.errmsg);
1716 	    }
1717 	}
1718 	return tres.rc;
1719     }
1720     sqlite4_free(0, tres.errmsg);
1721     if (rc != SQLITE4_OK) {
1722 	freerows(&tres.resarr[1]);
1723 	return rc;
1724     }
1725     *resp = &tres.resarr[1];
1726     if (ncolp) {
1727 	*ncolp = tres.ncol;
1728     }
1729     if (nrowp) {
1730 	*nrowp = tres.nrow;
1731     }
1732     return rc;
1733 }
1734 
1735 /**
1736  * Set error message and SQL state on DBC
1737  * @param d database connection pointer
1738  * @param naterr native error code
1739  * @param msg error message
1740  * @param st SQL state
1741  */
1742 
1743 #if defined(__GNUC__) && (__GNUC__ >= 2)
1744 static void setstatd(DBC *, int, char *, char *, ...)
1745     __attribute__((format (printf, 3, 5)));
1746 #endif
1747 
1748 static void
setstatd(DBC * d,int naterr,char * msg,char * st,...)1749 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
1750 {
1751     va_list ap;
1752 
1753     if (!d) {
1754 	return;
1755     }
1756     d->naterr = naterr;
1757     d->logmsg[0] = '\0';
1758     if (msg) {
1759 	int count;
1760 
1761 	va_start(ap, st);
1762 	count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
1763 	va_end(ap);
1764 	if (count < 0) {
1765 	    d->logmsg[sizeof (d->logmsg) - 1] = '\0';
1766 	}
1767     }
1768     if (!st) {
1769 	st = "?????";
1770     }
1771     strncpy(d->sqlstate, st, 5);
1772     d->sqlstate[5] = '\0';
1773 }
1774 
1775 /**
1776  * Set error message and SQL state on statement
1777  * @param s statement pointer
1778  * @param naterr native error code
1779  * @param msg error message
1780  * @param st SQL state
1781  */
1782 
1783 #if defined(__GNUC__) && (__GNUC__ >= 2)
1784 static void setstat(STMT *, int, char *, char *, ...)
1785     __attribute__((format (printf, 3, 5)));
1786 #endif
1787 
1788 static void
setstat(STMT * s,int naterr,char * msg,char * st,...)1789 setstat(STMT *s, int naterr, char *msg, char *st, ...)
1790 {
1791     va_list ap;
1792 
1793     if (!s) {
1794 	return;
1795     }
1796     s->naterr = naterr;
1797     s->logmsg[0] = '\0';
1798     if (msg) {
1799 	int count;
1800 
1801 	va_start(ap, st);
1802 	count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
1803 	va_end(ap);
1804 	if (count < 0) {
1805 	    s->logmsg[sizeof (s->logmsg) - 1] = '\0';
1806 	}
1807     }
1808     if (!st) {
1809 	st = "?????";
1810     }
1811     strncpy(s->sqlstate, st, 5);
1812     s->sqlstate[5] = '\0';
1813 }
1814 
1815 /**
1816  * Report IM001 (not implemented) SQL error code for HDBC.
1817  * @param dbc database connection handle
1818  * @result ODBC error code
1819  */
1820 
1821 static SQLRETURN
drvunimpldbc(HDBC dbc)1822 drvunimpldbc(HDBC dbc)
1823 {
1824     DBC *d;
1825 
1826     if (dbc == SQL_NULL_HDBC) {
1827 	return SQL_INVALID_HANDLE;
1828     }
1829     d = (DBC *) dbc;
1830     setstatd(d, -1, "not supported", "IM001");
1831     return SQL_ERROR;
1832 }
1833 
1834 /**
1835  * Report IM001 (not implemented) SQL error code for HSTMT.
1836  * @param stmt statement handle
1837  * @result ODBC error code
1838  */
1839 
1840 static SQLRETURN
drvunimplstmt(HSTMT stmt)1841 drvunimplstmt(HSTMT stmt)
1842 {
1843     STMT *s;
1844 
1845     if (stmt == SQL_NULL_HSTMT) {
1846 	return SQL_INVALID_HANDLE;
1847     }
1848     s = (STMT *) stmt;
1849     setstat(s, -1, "not supported", "IM001");
1850     return SQL_ERROR;
1851 }
1852 
1853 /**
1854  * Free memory given pointer to memory pointer.
1855  * @param x pointer to pointer to memory to be free'd
1856  */
1857 
1858 static void
freep(void * x)1859 freep(void *x)
1860 {
1861     if (x && ((char **) x)[0]) {
1862 	xfree(((char **) x)[0]);
1863 	((char **) x)[0] = NULL;
1864     }
1865 }
1866 
1867 /**
1868  * Report S1000 (out of memory) SQL error given STMT.
1869  * @param s statement pointer
1870  * @result ODBC error code
1871  */
1872 
1873 static SQLRETURN
nomem(STMT * s)1874 nomem(STMT *s)
1875 {
1876     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
1877     return SQL_ERROR;
1878 }
1879 
1880 /**
1881  * Report S1000 (not connected) SQL error given STMT.
1882  * @param s statement pointer
1883  * @result ODBC error code
1884  */
1885 
1886 static SQLRETURN
noconn(STMT * s)1887 noconn(STMT *s)
1888 {
1889     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
1890     return SQL_ERROR;
1891 }
1892 
1893 /**
1894  * Internal locale neutral strtod function.
1895  * @param data pointer to string
1896  * @param endp pointer for ending character
1897  * @result double value
1898  */
1899 
1900 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
1901 
1902 static double
ln_strtod(const char * data,char ** endp)1903 ln_strtod(const char *data, char **endp)
1904 {
1905     struct lconv *lc = 0;
1906     char buf[128], *p, *end;
1907     double value;
1908 
1909     lc = localeconv();
1910     if (lc && lc->decimal_point && lc->decimal_point[0] &&
1911 	lc->decimal_point[0] != '.') {
1912 	strncpy(buf, data, sizeof (buf) - 1);
1913 	buf[sizeof (buf) - 1] = '\0';
1914 	p = strchr(buf, '.');
1915 	if (p) {
1916 	    *p = lc->decimal_point[0];
1917 	}
1918 	p = buf;
1919     } else {
1920 	p = (char *) data;
1921     }
1922     value = strtod(p, &end);
1923     end = (char *) data + (end - p);
1924     if (endp) {
1925 	*endp = end;
1926     }
1927     return value;
1928 }
1929 
1930 #else
1931 
1932 #define ln_strtod(A,B) strtod(A,B)
1933 
1934 #endif
1935 
1936 /**
1937  * Strip quotes from quoted string in-place.
1938  * @param str string
1939  */
1940 
1941 static char *
unquote(char * str)1942 unquote(char *str)
1943 {
1944     if (str) {
1945 	int len = strlen(str);
1946 
1947 	if (len > 1) {
1948 	    int end = len - 1;
1949 
1950 	    if ((str[0] == '\'' && str[end] == '\'') ||
1951 		(str[0] == '"' && str[end] == '"') ||
1952 		(str[0] == '[' && str[end] == ']')) {
1953 		memmove(str, str + 1, end - 1);
1954 		str[end - 1] = '\0';
1955 	    }
1956 	}
1957     }
1958     return str;
1959 }
1960 
1961 /**
1962  * Unescape search pattern for e.g. table name in
1963  * catalog functions. Replacements in string are done in-place.
1964  * @param str string
1965  * @result number of pattern characters in string or 0
1966  */
1967 
1968 static int
unescpat(char * str)1969 unescpat(char *str)
1970 {
1971     char *p, *q;
1972     int count = 0;
1973 
1974     p = str;
1975     while ((q = strchr(p, '_')) != NULL) {
1976 	if (q == str || q[-1] != '\\') {
1977 	    count++;
1978 	}
1979 	p = q + 1;
1980     }
1981     p = str;
1982     while ((q = strchr(p, '%')) != NULL) {
1983 	if (q == str || q[-1] != '\\') {
1984 	    count++;
1985 	}
1986 	p = q + 1;
1987     }
1988     p = str;
1989     while ((q = strchr(p, '\\')) != NULL) {
1990 	if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
1991 	    memmove(q, q + 1, strlen(q));
1992 	}
1993 	p = q + 1;
1994     }
1995     return count;
1996 }
1997 
1998 /**
1999  * SQL LIKE string match with optional backslash escape handling.
2000  * @param str string
2001  * @param pat pattern
2002  * @param esc when true, treat literally "\\" as "\", "\%" as "%", "\_" as "_"
2003  * @result true when pattern matched
2004  */
2005 
2006 static int
namematch(char * str,char * pat,int esc)2007 namematch(char *str, char *pat, int esc)
2008 {
2009     int cp, ch;
2010 
2011     while (1) {
2012 	cp = TOLOWER(*pat);
2013 	if (cp == '\0') {
2014 	    if (*str != '\0') {
2015 		goto nomatch;
2016 	    }
2017 	    break;
2018 	}
2019 	if (*str == '\0' && cp != '%') {
2020 	    goto nomatch;
2021 	}
2022 	if (cp == '%') {
2023 	    while (*pat == '%') {
2024 		++pat;
2025 	    }
2026 	    cp = TOLOWER(*pat);
2027 	    if (cp == '\0') {
2028 		break;
2029 	    }
2030 	    while (1) {
2031 		if (cp != '_' && cp != '\\') {
2032 		    while (*str) {
2033 			ch = TOLOWER(*str);
2034 			if (ch == cp) {
2035 			    break;
2036 			}
2037 			++str;
2038 		    }
2039 		}
2040 		if (namematch(str, pat, esc)) {
2041 		    goto match;
2042 		}
2043 		if (*str == '\0') {
2044 		    goto nomatch;
2045 		}
2046 		ch = TOLOWER(*str);
2047 		++str;
2048 	    }
2049 	}
2050 	if (cp == '_') {
2051 	    pat++;
2052 	    str++;
2053 	    continue;
2054 	}
2055 	if (esc && cp == '\\' &&
2056 	    (pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
2057 	    ++pat;
2058 	    cp = TOLOWER(*pat);
2059 	}
2060 	ch = TOLOWER(*str++);
2061 	++pat;
2062 	if (ch != cp) {
2063 	    goto nomatch;
2064 	}
2065     }
2066 match:
2067     return 1;
2068 nomatch:
2069     return 0;
2070 }
2071 
2072 /**
2073  * Set SQLite options (PRAGMAs) given SQLite handle.
2074  * @param x SQLite database handle
2075  * @param d DBC pointer
2076  * @result SQLite error code
2077  *
2078  * SQLite < 3.3.x and not shortnames DSN option:
2079  * "full_column_names" is always turned on and "short_column_names"
2080  * is always turned off, to get the table names in column labels.
2081  */
2082 
2083 static int
setsqliteopts(sqlite4 * x,DBC * d)2084 setsqliteopts(sqlite4 *x, DBC *d)
2085 {
2086     int count = 0, step = 0, max, rc = SQLITE4_ERROR;
2087 
2088     max = d->longnames ? 3 : 1;
2089     if (d->shortnames) {
2090 	max = 3;
2091     }
2092     while (step < max) {
2093 	if (step < 1) {
2094 	    rc = sqlite4_exec(x, "PRAGMA empty_result_callbacks = on;",
2095 			      NULL, NULL);
2096 	    if (rc == SQLITE4_OK) {
2097 		rc = sqlite4_exec(x, d->fksupport ?
2098 				  "PRAGMA foreign_keys = on;" :
2099 				  "PRAGMA foreign_keys = off;",
2100 				  NULL, NULL);
2101 	    }
2102 	} else if (step < 2) {
2103 	    rc = sqlite4_exec(x, d->shortnames ?
2104 			      "PRAGMA full_column_names = off;" :
2105 			      "PRAGMA full_column_names = on;",
2106 			      NULL, NULL);
2107 	} else if (step < 3) {
2108 	    rc = sqlite4_exec(x, d->shortnames ?
2109 			      "PRAGMA short_column_names = on;" :
2110 			      "PRAGMA short_column_names = off;",
2111 			      NULL, NULL);
2112 	}
2113 	if (rc != SQLITE4_OK) {
2114 	    return rc;
2115 	}
2116 	count = 0;
2117 	++step;
2118     }
2119     return SQLITE4_OK;
2120 }
2121 
2122 /**
2123  * Free counted array of char pointers.
2124  * @param rowp pointer to char pointer array
2125  *
2126  * The -1-th element of the array holds the array size.
2127  * All non-NULL pointers of the array and then the array
2128  * itself are free'd.
2129  */
2130 
2131 static void
freerows(char ** rowp)2132 freerows(char **rowp)
2133 {
2134     PTRDIFF_T size, i;
2135 
2136     if (!rowp) {
2137 	return;
2138     }
2139     --rowp;
2140     size = (PTRDIFF_T) rowp[0];
2141     for (i = 1; i <= size; i++) {
2142 	freep(&rowp[i]);
2143     }
2144     freep(&rowp);
2145 }
2146 
2147 /**
2148  * Map SQL field type from string to ODBC integer type code.
2149  * @param typename field type string
2150  * @param nosign pointer to indicator for unsigned field or NULL
2151  * @param ov3 boolean, true for SQL_OV_ODBC3
2152  * @param nowchar boolean, for WINTERFACE don't use WCHAR
2153  * @param dobigint boolean, force SQL_BIGINT on INTEGER columns
2154  * @result SQL data type
2155  */
2156 
2157 static int
mapsqltype(const char * typename,int * nosign,int ov3,int nowchar,int dobigint)2158 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar,
2159 	   int dobigint)
2160 {
2161     char *p, *q;
2162     int testsign = 0, result;
2163 
2164 #ifdef WINTERFACE
2165     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
2166 #else
2167     result = SQL_VARCHAR;
2168 #endif
2169     if (!typename) {
2170 	return result;
2171     }
2172     q = p = xmalloc(strlen(typename) + 1);
2173     if (!p) {
2174 	return result;
2175     }
2176     strcpy(p, typename);
2177     while (*q) {
2178 	*q = TOLOWER(*q);
2179 	++q;
2180     }
2181     if (strncmp(p, "inter", 5) == 0) {
2182     } else if (strncmp(p, "int", 3) == 0 ||
2183 	strncmp(p, "mediumint", 9) == 0) {
2184 	testsign = 1;
2185 	result = SQL_INTEGER;
2186     } else if (strncmp(p, "numeric", 7) == 0) {
2187 	result = SQL_DOUBLE;
2188     } else if (strncmp(p, "tinyint", 7) == 0) {
2189 	testsign = 1;
2190 	result = SQL_TINYINT;
2191     } else if (strncmp(p, "smallint", 8) == 0) {
2192 	testsign = 1;
2193 	result = SQL_SMALLINT;
2194     } else if (strncmp(p, "float", 5) == 0) {
2195 	result = SQL_DOUBLE;
2196     } else if (strncmp(p, "double", 6) == 0 ||
2197 	strncmp(p, "real", 4) == 0) {
2198 	result = SQL_DOUBLE;
2199     } else if (strncmp(p, "timestamp", 9) == 0) {
2200 #ifdef SQL_TYPE_TIMESTAMP
2201 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
2202 #else
2203 	result = SQL_TIMESTAMP;
2204 #endif
2205     } else if (strncmp(p, "datetime", 8) == 0) {
2206 #ifdef SQL_TYPE_TIMESTAMP
2207 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
2208 #else
2209 	result = SQL_TIMESTAMP;
2210 #endif
2211     } else if (strncmp(p, "time", 4) == 0) {
2212 #ifdef SQL_TYPE_TIME
2213 	result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
2214 #else
2215 	result = SQL_TIME;
2216 #endif
2217     } else if (strncmp(p, "date", 4) == 0) {
2218 #ifdef SQL_TYPE_DATE
2219 	result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
2220 #else
2221 	result = SQL_DATE;
2222 #endif
2223 #ifdef SQL_LONGVARCHAR
2224     } else if (strncmp(p, "text", 4) == 0 ||
2225 	       strncmp(p, "memo", 4) == 0 ||
2226 	       strncmp(p, "longvarchar", 11) == 0) {
2227 #ifdef WINTERFACE
2228 	result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
2229 #else
2230 	result = SQL_LONGVARCHAR;
2231 #endif
2232 #ifdef WINTERFACE
2233     } else if (strncmp(p, "wtext", 5) == 0 ||
2234 	       strncmp(p, "wvarchar", 8) == 0 ||
2235 	       strncmp(p, "longwvarchar", 12) == 0) {
2236 	result = SQL_WLONGVARCHAR;
2237 #endif
2238 #endif
2239 #ifdef SQL_BIT
2240     } else if (strncmp(p, "bool", 4) == 0 ||
2241 	       strncmp(p, "bit", 3) == 0) {
2242 	result = SQL_BIT;
2243 #endif
2244 #ifdef SQL_BIGINT
2245     } else if (strncmp(p, "bigint", 6) == 0) {
2246 	testsign = 1;
2247 	result = SQL_BIGINT;
2248 #endif
2249     } else if (strncmp(p, "blob", 4) == 0) {
2250 	result = SQL_BINARY;
2251     } else if (strncmp(p, "varbinary", 9) == 0) {
2252 	result = SQL_VARBINARY;
2253     } else if (strncmp(p, "longvarbinary", 13) == 0) {
2254 	result = SQL_LONGVARBINARY;
2255     }
2256     if (nosign) {
2257 	if (testsign) {
2258 	    *nosign = strstr(p, "unsigned") != NULL;
2259 	} else {
2260 	    *nosign = 1;
2261 	}
2262     }
2263 #ifdef SQL_BIGINT
2264     if (dobigint && result == SQL_INTEGER) {
2265 	result = SQL_BIGINT;
2266     }
2267 #endif
2268     xfree(p);
2269     return result;
2270 }
2271 
2272 /**
2273  * Get maximum display size and number of digits after decimal point
2274  * from field type specification.
2275  * @param typename field type specification
2276  * @param sqltype target SQL data type
2277  * @param mp pointer to maximum display size or NULL
2278  * @param dp pointer to number of digits after decimal point or NULL
2279  */
2280 
2281 static void
getmd(const char * typename,int sqltype,int * mp,int * dp)2282 getmd(const char *typename, int sqltype, int *mp, int *dp)
2283 {
2284     int m = 0, d = 0;
2285 
2286     switch (sqltype) {
2287     case SQL_INTEGER:       m = 10; d = 9; break;
2288     case SQL_TINYINT:       m = 4; d = 3; break;
2289     case SQL_SMALLINT:      m = 6; d = 5; break;
2290     case SQL_FLOAT:         m = 25; d = 24; break;
2291     case SQL_DOUBLE:        m = 54; d = 53; break;
2292     case SQL_VARCHAR:       m = 255; d = 0; break;
2293 #ifdef WINTERFACE
2294 #ifdef SQL_WVARCHAR
2295     case SQL_WVARCHAR:      m = 255; d = 0; break;
2296 #endif
2297 #endif
2298 #ifdef SQL_TYPE_DATE
2299     case SQL_TYPE_DATE:
2300 #endif
2301     case SQL_DATE:          m = 10; d = 0; break;
2302 #ifdef SQL_TYPE_TIME
2303     case SQL_TYPE_TIME:
2304 #endif
2305     case SQL_TIME:          m = 8; d = 0; break;
2306 #ifdef SQL_TYPE_TIMESTAMP
2307     case SQL_TYPE_TIMESTAMP:
2308 #endif
2309     case SQL_TIMESTAMP:     m = 32; d = 3; break;
2310 #ifdef SQL_LONGVARCHAR
2311     case SQL_LONGVARCHAR :  m = 65536; d = 0; break;
2312 #endif
2313 #ifdef WINTERFACE
2314 #ifdef SQL_WLONGVARCHAR
2315     case SQL_WLONGVARCHAR:  m = 65536; d = 0; break;
2316 #endif
2317 #endif
2318     case SQL_BINARY:
2319     case SQL_VARBINARY:     m = 255; d = 0; break;
2320     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
2321 #ifdef SQL_BIGINT
2322     case SQL_BIGINT:        m = 20; d = 19; break;
2323 #endif
2324 #ifdef SQL_BIT
2325     case SQL_BIT:	    m = 1; d = 1; break;
2326 #endif
2327     }
2328     if (m && typename) {
2329 	int mm, dd;
2330 	char clbr[4];
2331 
2332 	if (sscanf(typename, "%*[^(](%d,%d %1[)]", &mm, &dd, clbr) == 3) {
2333 	    m = mm;
2334 	    d = dd;
2335 	} else if (sscanf(typename, "%*[^(](%d %1[)]", &mm, clbr) == 2) {
2336 	    if (sqltype == SQL_TIMESTAMP) {
2337 		d = mm;
2338 	    }
2339 #ifdef SQL_TYPE_TIMESTAMP
2340 	    else if (sqltype == SQL_TYPE_TIMESTAMP) {
2341 		d = mm;
2342 	    }
2343 #endif
2344 	    else {
2345 		m = d = mm;
2346 	    }
2347 	}
2348     }
2349     if (mp) {
2350 	*mp = m;
2351     }
2352     if (dp) {
2353 	*dp = d;
2354     }
2355 }
2356 
2357 /**
2358  * Map SQL_C_DEFAULT to proper C type.
2359  * @param type input C type
2360  * @param stype input SQL type
2361  * @param nosign 0=signed, 0>unsigned, 0<undefined
2362  * @param nowchar when compiled with WINTERFACE don't use WCHAR
2363  * @result C type
2364  */
2365 
2366 static int
mapdeftype(int type,int stype,int nosign,int nowchar)2367 mapdeftype(int type, int stype, int nosign, int nowchar)
2368 {
2369     if (type == SQL_C_DEFAULT) {
2370 	switch (stype) {
2371 	case SQL_INTEGER:
2372 	    type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
2373 	    break;
2374 	case SQL_TINYINT:
2375 	    type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
2376 	    break;
2377 	case SQL_SMALLINT:
2378 	    type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
2379 	    break;
2380 	case SQL_FLOAT:
2381 	    type = SQL_C_FLOAT;
2382 	    break;
2383 	case SQL_DOUBLE:
2384 	    type = SQL_C_DOUBLE;
2385 	    break;
2386 	case SQL_TIMESTAMP:
2387 	    type = SQL_C_TIMESTAMP;
2388 	    break;
2389 	case SQL_TIME:
2390 	    type = SQL_C_TIME;
2391 	    break;
2392 	case SQL_DATE:
2393 	    type = SQL_C_DATE;
2394 	    break;
2395 #ifdef SQL_C_TYPE_TIMESTAMP
2396 	case SQL_TYPE_TIMESTAMP:
2397 	    type = SQL_C_TYPE_TIMESTAMP;
2398 	    break;
2399 #endif
2400 #ifdef SQL_C_TYPE_TIME
2401 	case SQL_TYPE_TIME:
2402 	    type = SQL_C_TYPE_TIME;
2403 	    break;
2404 #endif
2405 #ifdef SQL_C_TYPE_DATE
2406 	case SQL_TYPE_DATE:
2407 	    type = SQL_C_TYPE_DATE;
2408 	    break;
2409 #endif
2410 #ifdef WINTERFACE
2411 	case SQL_WVARCHAR:
2412 	case SQL_WCHAR:
2413 #ifdef SQL_WLONGVARCHAR
2414 	case SQL_WLONGVARCHAR:
2415 #endif
2416 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
2417 	    break;
2418 #endif
2419 	case SQL_BINARY:
2420 	case SQL_VARBINARY:
2421 	case SQL_LONGVARBINARY:
2422 	    type = SQL_C_BINARY;
2423 	    break;
2424 #ifdef SQL_BIT
2425 	case SQL_BIT:
2426 	    type = SQL_C_BIT;
2427 	    break;
2428 #endif
2429 #ifdef SQL_BIGINT
2430 	case SQL_BIGINT:
2431 	    type = SQL_C_CHAR;
2432 	    break;
2433 #endif
2434 	default:
2435 #ifdef WINTERFACE
2436 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
2437 #else
2438 	    type = SQL_C_CHAR;
2439 #endif
2440 	    break;
2441 	}
2442     }
2443     return type;
2444 }
2445 
2446 /**
2447  * Check if query is a DDL statement.
2448  * @param sql query string
2449  * @result true or false
2450  */
2451 
2452 static int
checkddl(char * sql)2453 checkddl(char *sql)
2454 {
2455     int isddl = 0;
2456 
2457     while (*sql && ISSPACE(*sql)) {
2458 	++sql;
2459     }
2460     if (*sql && *sql != ';') {
2461 	int i, size;
2462 	static const struct {
2463 	    int len;
2464 	    const char *str;
2465 	} ddlstr[] = {
2466 	    { 5, "alter" },
2467 	    { 7, "analyze" },
2468 	    { 6, "attach" },
2469 	    { 5, "begin" },
2470 	    { 6, "commit" },
2471 	    { 6, "create" },
2472 	    { 6, "detach" },
2473 	    { 4, "drop" },
2474 	    { 3, "end" },
2475 	    { 7, "reindex" },
2476 	    { 7, "release" },
2477 	    { 8, "rollback" },
2478 	    { 9, "savepoint" },
2479 	    { 6, "vacuum" }
2480 	};
2481 
2482 	size = strlen(sql);
2483 	for (i = 0; i < array_size(ddlstr); i++) {
2484 	    if (size >= ddlstr[i].len &&
2485 		strncasecmp(sql, ddlstr[i].str, ddlstr[i].len) == 0) {
2486 		isddl = 1;
2487 		break;
2488 	    }
2489 	}
2490     }
2491     return isddl;
2492 }
2493 
2494 /**
2495  * Fixup query string with optional parameter markers.
2496  * @param sql original query string
2497  * @param sqlLen length of query string or SQL_NTS
2498  * @param nparam output number of parameters
2499  * @param isselect output indicator for SELECT (1) or DDL statement (2)
2500  * @param errmsg output error message
2501  * @result newly allocated string containing query string for SQLite or NULL
2502  */
2503 
2504 static char *
fixupsql(char * sql,int sqlLen,int * nparam,int * isselect,char ** errmsg)2505 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg)
2506 {
2507     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
2508     int np = 0, isddl = -1, size;
2509 
2510     if (errmsg) {
2511 	*errmsg = NULL;
2512     }
2513     if (sqlLen != SQL_NTS) {
2514 	qz = q = xmalloc(sqlLen + 1);
2515 	if (!qz) {
2516 	    return NULL;
2517 	}
2518 	memcpy(q, sql, sqlLen);
2519 	q[sqlLen] = '\0';
2520 	size = sqlLen * 4;
2521     } else {
2522 	size = strlen(sql) * 4;
2523     }
2524     size += sizeof (char *) - 1;
2525     size &= ~(sizeof (char *) - 1);
2526     p = xmalloc(size);
2527     if (!p) {
2528 errout:
2529 	freep(&qz);
2530 	return NULL;
2531     }
2532     memset(p, 0, size);
2533     out = p;
2534     while (*q) {
2535 	switch (*q) {
2536 	case '\'':
2537 	case '\"':
2538 	    if (q == inq) {
2539 		inq = NULL;
2540 	    } else if (!inq) {
2541 		inq = q + 1;
2542 
2543 		while (*inq) {
2544 		    if (*inq == *q) {
2545 			if (inq[1] == *q) {
2546 			    inq++;
2547 			} else {
2548 			    break;
2549 			}
2550 		    }
2551 		    inq++;
2552 		}
2553 	    }
2554 	    *p++ = *q;
2555 	    break;
2556 	case '?':
2557 	    *p++ = *q;
2558 	    if (!inq) {
2559 		np++;
2560 	    }
2561 	    break;
2562 	case ';':
2563 	    if (!inq) {
2564 		if (isddl < 0) {
2565 		    isddl = checkddl(out);
2566 		}
2567 		if (isddl == 0) {
2568 		    char *qq = q;
2569 
2570 		    do {
2571 			++qq;
2572 		    } while (*qq && ISSPACE(*qq));
2573 		    if (*qq && *qq != ';') {
2574 			freep(&out);
2575 			if (errmsg) {
2576 			    *errmsg = "only one SQL statement allowed";
2577 			}
2578 			goto errout;
2579 		    }
2580 		}
2581 	    }
2582 	    *p++ = *q;
2583 	    break;
2584 	case '{':
2585 	    /*
2586 	     * Deal with escape sequences:
2587 	     * {d 'YYYY-MM-DD'}, {t ...}, {ts ...}
2588 	     * {oj ...}, {fn ...} etc.
2589 	     */
2590 	    if (!inq) {
2591 		int ojfn = 0, brc = 0;
2592 		char *inq2 = NULL, *end = q + 1, *start;
2593 
2594 		while (*end && ISSPACE(*end)) {
2595 		    ++end;
2596 		}
2597 		if (*end != 'd' && *end != 'D' &&
2598 		    *end != 't' && *end != 'T') {
2599 		    ojfn = 1;
2600 		}
2601 		start = end;
2602 		while (*end) {
2603 		    if (inq2 && *end == *inq2) {
2604 			inq2 = NULL;
2605 		    } else if (inq2 == NULL && *end == '{') {
2606 			char *nerr = 0, *nsql;
2607 
2608 			nsql = fixupsql(end, SQL_NTS, 0, 0, &nerr);
2609 			if (nsql && !nerr) {
2610 			    strcpy(end, nsql);
2611 			} else {
2612 			    brc++;
2613 			}
2614 			freep(&nsql);
2615 		    } else if (inq2 == NULL && *end == '}') {
2616 			if (brc-- <= 0) {
2617 			    break;
2618 			}
2619 		    } else if (inq2 == NULL && (*end == '\'' || *end == '"')) {
2620 			inq2 = end;
2621 		    } else if (inq2 == NULL && *end == '?') {
2622 			np++;
2623 		    }
2624 		    ++end;
2625 		}
2626 		if (*end == '}') {
2627 		    char *end2 = end - 1;
2628 
2629 		    if (ojfn) {
2630 			while (start < end) {
2631 			    if (ISSPACE(*start)) {
2632 				break;
2633 			    }
2634 			    ++start;
2635 			}
2636 			while (start < end) {
2637 			    *p++ = *start;
2638 			    ++start;
2639 			}
2640 			q = end;
2641 			break;
2642 		    } else {
2643 			while (start < end2 && *start != '\'') {
2644 			    ++start;
2645 			}
2646 			while (end2 > start && *end2 != '\'') {
2647 			    --end2;
2648 			}
2649 			if (*start == '\'' && *end2 == '\'') {
2650 			    while (start <= end2) {
2651 				*p++ = *start;
2652 				++start;
2653 			    }
2654 			    q = end;
2655 			    break;
2656 			}
2657 		    }
2658 		}
2659 	    }
2660 	    /* FALL THROUGH */
2661 	default:
2662 	    *p++ = *q;
2663 	}
2664 	++q;
2665     }
2666     freep(&qz);
2667     *p = '\0';
2668     if (nparam) {
2669 	*nparam = np;
2670     }
2671     if (isselect) {
2672 	if (isddl < 0) {
2673 	    isddl = checkddl(out);
2674 	}
2675 	if (isddl > 0) {
2676 	    *isselect = 2;
2677 	} else {
2678 	    int incom = 0;
2679 
2680 	    p = out;
2681 	    while (*p) {
2682 		switch (*p) {
2683 		case '-':
2684 		    if (!incom && p[1] == '-') {
2685 			incom = -1;
2686 		    }
2687 		    break;
2688 		case '\n':
2689 		    if (incom < 0) {
2690 			incom = 0;
2691 		    }
2692 		    break;
2693 		case '/':
2694 		    if (incom > 0 && p[-1] == '*') {
2695 			incom = 0;
2696 			p++;
2697 			continue;
2698 		    } else if (!incom && p[1] == '*') {
2699 			incom = 1;
2700 		    }
2701 		    break;
2702 		}
2703 		if (!incom && !ISSPACE(*p)) {
2704 		    break;
2705 		}
2706 		p++;
2707 	    }
2708 	    size = strlen(p);
2709 	    if (size >= 6 &&
2710 		(strncasecmp(p, "select", 6) == 0 ||
2711 		 strncasecmp(p, "pragma", 6) == 0)) {
2712 		*isselect = 1;
2713 	    } else if (size >= 7 &&
2714 		       strncasecmp(p, "explain", 7) == 0) {
2715 		*isselect = 1;
2716 	    } else {
2717 		*isselect = 0;
2718 	    }
2719 	}
2720     }
2721     return out;
2722 }
2723 
2724 /**
2725  * Find column given name in string array.
2726  * @param cols string array
2727  * @param ncols number of strings
2728  * @param name column name
2729  * @result >= 0 on success, -1 on error
2730  */
2731 
2732 static int
findcol(char ** cols,int ncols,char * name)2733 findcol(char **cols, int ncols, char *name)
2734 {
2735     int i;
2736 
2737     if (cols) {
2738 	for (i = 0; i < ncols; i++) {
2739 	    if (strcmp(cols[i], name) == 0) {
2740 		return i;
2741 	    }
2742 	}
2743     }
2744     return -1;
2745 }
2746 
2747 /**
2748  * Fixup column information for a running statement.
2749  * @param s statement to get fresh column information
2750  * @param d DBC pointer
2751  *
2752  * The column labels get the table names stripped
2753  * when there's more than one column and all table
2754  * names are identical.
2755  *
2756  * The "dyncols" field of STMT is filled with column
2757  * information obtained by SQLite "PRAGMA table_info"
2758  * for each column whose table name is known. If the
2759  * types are already present as with SQLite 2.5.7
2760  * this information is used instead.
2761  */
2762 
2763 static void
fixupdyncols(STMT * s,DBC * d)2764 fixupdyncols(STMT *s, DBC *d)
2765 {
2766     int i, k;
2767 
2768     if (!s->dyncols) {
2769 	return;
2770     }
2771     /* fixup labels */
2772     if (!s->longnames) {
2773 	if (s->dcols > 1) {
2774 	    char *table = s->dyncols[0].table;
2775 
2776 	    for (i = 1; table[0] && i < s->dcols; i++) {
2777 		if (strcmp(s->dyncols[i].table, table)) {
2778 		    break;
2779 		}
2780 	    }
2781 	    if (i >= s->dcols) {
2782 		for (i = 0; i < s->dcols; i++) {
2783 		    s->dyncols[i].label = s->dyncols[i].column;
2784 		}
2785 	    }
2786 	} else if (s->dcols == 1) {
2787 	    s->dyncols[0].label = s->dyncols[0].column;
2788 	}
2789     }
2790     for (i = 0; i < s->dcols; i++) {
2791 	s->dyncols[i].type =
2792 	    mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3,
2793 		       s->nowchar[0] || s->nowchar[1], s->dobigint);
2794 	getmd(s->dyncols[i].typename, s->dyncols[i].type,
2795 	      &s->dyncols[i].size, &s->dyncols[i].prec);
2796 #ifdef SQL_LONGVARCHAR
2797 	if (s->dyncols[i].type == SQL_VARCHAR &&
2798 	    s->dyncols[i].size > 255) {
2799 	    s->dyncols[i].type = SQL_LONGVARCHAR;
2800 	}
2801 #endif
2802 #ifdef WINTERFACE
2803 #ifdef SQL_WLONGVARCHAR
2804 	if (s->dyncols[i].type == SQL_WVARCHAR &&
2805 	    s->dyncols[i].size > 255) {
2806 	    s->dyncols[i].type = SQL_WLONGVARCHAR;
2807 	}
2808 #endif
2809 #endif
2810 	if (s->dyncols[i].type == SQL_VARBINARY &&
2811 	    s->dyncols[i].size > 255) {
2812 	    s->dyncols[i].type = SQL_LONGVARBINARY;
2813 	}
2814     }
2815     for (i = 1, k = 0; i < s->dcols; i++) {
2816 	if (strcmp(s->dyncols[i].table, s->dyncols[0].table) == 0) {
2817 	    k++;
2818 	}
2819     }
2820     s->one_tbl = (k && k + 1 == s->dcols) ? 1 : 0;
2821     k = 0;
2822     if (s->one_tbl) {
2823 	for (i = 0; i < s->dcols; i++) {
2824 	    if (s->dyncols[i].ispk > 0) {
2825 		++k;
2826 		if (s->has_rowid < 0 && s->dyncols[i].isrowid > 0) {
2827 		    s->has_rowid = i;
2828 		}
2829 	    }
2830 	}
2831     }
2832     s->has_pk = k;
2833 }
2834 
2835 /**
2836  * Return number of month days.
2837  * @param year
2838  * @param month 1..12
2839  * @result number of month days or 0
2840  */
2841 
2842 static int
getmdays(int year,int month)2843 getmdays(int year, int month)
2844 {
2845     static const int mdays[] = {
2846 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2847     };
2848     int mday;
2849 
2850     if (month < 1) {
2851 	return 0;
2852     }
2853     mday = mdays[(month - 1) % 12];
2854     if (mday == 28 && year % 4 == 0 &&
2855 	(!(year % 100 == 0) || year % 400 == 0)) {
2856 	mday++;
2857     }
2858     return mday;
2859 }
2860 
2861 /**
2862  * Convert string to ODBC DATE_STRUCT.
2863  * @param str string to be converted
2864  * @param ds output DATE_STRUCT
2865  * @result 0 on success, -1 on error
2866  *
2867  * Strings of the format 'YYYYMMDD' or 'YYYY-MM-DD' or
2868  * 'YYYY/MM/DD' or 'MM/DD/YYYY' are converted to a
2869  * DATE_STRUCT.
2870  */
2871 
2872 static int
str2date(char * str,DATE_STRUCT * ds)2873 str2date(char *str, DATE_STRUCT *ds)
2874 {
2875     int i, err = 0;
2876     char *p, *q, sepc = '\0';
2877 
2878     ds->year = ds->month = ds->day = 0;
2879     p = str;
2880     while (*p && !ISDIGIT(*p)) {
2881 	++p;
2882     }
2883     q = p;
2884     i = 0;
2885     while (*q && !ISDIGIT(*q)) {
2886 	++i;
2887 	++q;
2888     }
2889     if (i >= 8) {
2890 	char buf[8];
2891 
2892 	strncpy(buf, p + 0, 4); buf[4] = '\0';
2893 	ds->year = strtol(buf, NULL, 10);
2894 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2895 	ds->month = strtol(buf, NULL, 10);
2896 	strncpy(buf, p + 6, 2); buf[2] = '\0';
2897 	ds->day = strtol(buf, NULL, 10);
2898 	goto done;
2899     }
2900     i = 0;
2901     while (i < 3) {
2902 	int n;
2903 
2904 	q = NULL;
2905 	n = strtol(p, &q, 10);
2906 	if (!q || q == p) {
2907 	    if (*q == '\0') {
2908 		if (i == 0) {
2909 		    err = 1;
2910 		}
2911 		goto done;
2912 	    }
2913 	}
2914 	if (!sepc) {
2915 	    sepc = *q;
2916 	}
2917 	if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
2918 	    switch (i) {
2919 	    case 0: ds->year = n; break;
2920 	    case 1: ds->month = n; break;
2921 	    case 2: ds->day = n; break;
2922 	    }
2923 	    ++i;
2924 	    if (*q) {
2925 		++q;
2926 	    }
2927 	} else {
2928 	    i = 0;
2929 	    while (*q && !ISDIGIT(*q)) {
2930 		++q;
2931 	    }
2932 	}
2933 	p = q;
2934     }
2935 done:
2936     /* final check for overflow */
2937     if (err ||
2938 	ds->month < 1 || ds->month > 12 ||
2939 	ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
2940 	if (sepc == '/') {
2941 	    /* Try MM/DD/YYYY format */
2942 	    int t[3];
2943 
2944 	    t[0] = ds->year;
2945 	    t[1] = ds->month;
2946 	    t[2] = ds->day;
2947 	    ds->year = t[2];
2948 	    ds->day = t[1];
2949 	    ds->month = t[0];
2950 	    if (ds->month >= 1 && ds->month <= 12 &&
2951 		(ds->day >= 1 || ds->day <= getmdays(ds->year, ds->month))) {
2952 		return 0;
2953 	    }
2954 	}
2955 	return -1;
2956     }
2957     return 0;
2958 }
2959 
2960 /**
2961  * Convert string to ODBC TIME_STRUCT.
2962  * @param str string to be converted
2963  * @param ts output TIME_STRUCT
2964  * @result 0 on success, -1 on error
2965  *
2966  * Strings of the format 'HHMMSS' or 'HH:MM:SS'
2967  * are converted to a TIME_STRUCT.
2968  */
2969 
2970 static int
str2time(char * str,TIME_STRUCT * ts)2971 str2time(char *str, TIME_STRUCT *ts)
2972 {
2973     int i, err = 0, ampm = -1;
2974     char *p, *q;
2975 
2976     ts->hour = ts->minute = ts->second = 0;
2977     p = str;
2978     while (*p && !ISDIGIT(*p)) {
2979 	++p;
2980     }
2981     q = p;
2982     i = 0;
2983     while (*q && ISDIGIT(*q)) {
2984 	++i;
2985 	++q;
2986     }
2987     if (i >= 6) {
2988 	char buf[4];
2989 
2990 	strncpy(buf, p + 0, 2); buf[2] = '\0';
2991 	ts->hour = strtol(buf, NULL, 10);
2992 	strncpy(buf, p + 2, 2); buf[2] = '\0';
2993 	ts->minute = strtol(buf, NULL, 10);
2994 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2995 	ts->second = strtol(buf, NULL, 10);
2996 	goto done;
2997     }
2998     i = 0;
2999     while (i < 3) {
3000 	int n;
3001 
3002 	q = NULL;
3003 	n = strtol(p, &q, 10);
3004 	if (!q || q == p) {
3005 	    if (*q == '\0') {
3006 		if (i == 0) {
3007 		    err = 1;
3008 		}
3009 		goto done;
3010 	    }
3011 	}
3012 	if (*q == ':' || *q == '\0' || i == 2) {
3013 	    switch (i) {
3014 	    case 0: ts->hour = n; break;
3015 	    case 1: ts->minute = n; break;
3016 	    case 2: ts->second = n; break;
3017 	    }
3018 	    ++i;
3019 	    if (*q) {
3020 		++q;
3021 	    }
3022 	} else {
3023 	    i = 0;
3024 	    while (*q && !ISDIGIT(*q)) {
3025 		++q;
3026 	    }
3027 	}
3028 	p = q;
3029     }
3030     if (!err) {
3031 	while (*p) {
3032 	    if ((p[0] == 'p' || p[0] == 'P') &&
3033 		(p[1] == 'm' || p[1] == 'M')) {
3034 		ampm = 1;
3035 	    } else if ((p[0] == 'a' || p[0] == 'A') &&
3036 		(p[1] == 'm' || p[1] == 'M')) {
3037 		ampm = 0;
3038 	    }
3039 	    ++p;
3040 	}
3041 	if (ampm > 0) {
3042 	    if (ts->hour < 12) {
3043 		ts->hour += 12;
3044 	    }
3045 	} else if (ampm == 0) {
3046 	    if (ts->hour == 12) {
3047 		ts->hour = 0;
3048 	    }
3049 	}
3050     }
3051 done:
3052     /* final check for overflow */
3053     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
3054 	return -1;
3055     }
3056     return 0;
3057 }
3058 
3059 /**
3060  * Convert string to ODBC TIMESTAMP_STRUCT.
3061  * @param str string to be converted
3062  * @param tss output TIMESTAMP_STRUCT
3063  * @result 0 on success, -1 on error
3064  *
3065  * Strings of the format 'YYYYMMDDhhmmssff' or 'YYYY-MM-DD hh:mm:ss ff'
3066  * or 'YYYY/MM/DD hh:mm:ss ff' or 'hh:mm:ss ff YYYY-MM-DD' are
3067  * converted to a TIMESTAMP_STRUCT. The ISO8601 formats
3068  *    YYYY-MM-DDThh:mm:ss[.f]Z
3069  *    YYYY-MM-DDThh:mm:ss[.f]shh:mm
3070  * are also supported. In case a time zone field is present,
3071  * the resulting TIMESTAMP_STRUCT is expressed in UTC.
3072  */
3073 
3074 static int
str2timestamp(char * str,TIMESTAMP_STRUCT * tss)3075 str2timestamp(char *str, TIMESTAMP_STRUCT *tss)
3076 {
3077     int i, m, n, err = 0, ampm = -1;
3078     char *p, *q, in = '\0', sepc = '\0';
3079 
3080     tss->year = tss->month = tss->day = 0;
3081     tss->hour = tss->minute = tss->second = 0;
3082     tss->fraction = 0;
3083     p = str;
3084     while (*p && !ISDIGIT(*p)) {
3085 	++p;
3086     }
3087     q = p;
3088     i = 0;
3089     while (*q && ISDIGIT(*q)) {
3090 	++i;
3091 	++q;
3092     }
3093     if (i >= 14) {
3094 	char buf[16];
3095 
3096 	strncpy(buf, p + 0, 4); buf[4] = '\0';
3097 	tss->year = strtol(buf, NULL, 10);
3098 	strncpy(buf, p + 4, 2); buf[2] = '\0';
3099 	tss->month = strtol(buf, NULL, 10);
3100 	strncpy(buf, p + 6, 2); buf[2] = '\0';
3101 	tss->day = strtol(buf, NULL, 10);
3102 	strncpy(buf, p + 8, 2); buf[2] = '\0';
3103 	tss->hour = strtol(buf, NULL, 10);
3104 	strncpy(buf, p + 10, 2); buf[2] = '\0';
3105 	tss->minute = strtol(buf, NULL, 10);
3106 	strncpy(buf, p + 12, 2); buf[2] = '\0';
3107 	tss->second = strtol(buf, NULL, 10);
3108 	if (i > 14) {
3109 	    m = i - 14;
3110 	    strncpy(buf, p + 14, m);
3111 	    while (m < 9) {
3112 		buf[m] = '0';
3113 		++m;
3114 	    }
3115 	    buf[m] = '\0';
3116 	    tss->fraction = strtol(buf, NULL, 10);
3117 	}
3118 	m = 7;
3119 	goto done;
3120     }
3121     m = i = 0;
3122     while ((m & 7) != 7) {
3123 	q = NULL;
3124 	n = strtol(p, &q, 10);
3125 	if (!q || q == p) {
3126 	    if (*q == '\0') {
3127 		if (m < 1) {
3128 		    err = 1;
3129 		}
3130 		goto done;
3131 	    }
3132 	}
3133 	if (in == '\0') {
3134 	    switch (*q) {
3135 	    case '-':
3136 	    case '/':
3137 		if ((m & 1) == 0) {
3138 		    in = *q;
3139 		    i = 0;
3140 		}
3141 		break;
3142 	    case ':':
3143 		if ((m & 2) == 0) {
3144 		    in = *q;
3145 		    i = 0;
3146 		}
3147 		break;
3148 	    case ' ':
3149 	    case '.':
3150 		break;
3151 	    default:
3152 		in = '\0';
3153 		i = 0;
3154 		break;
3155 	    }
3156 	}
3157 	switch (in) {
3158 	case '-':
3159 	case '/':
3160 	    if (!sepc) {
3161 		sepc = in;
3162 	    }
3163 	    switch (i) {
3164 	    case 0: tss->year = n; break;
3165 	    case 1: tss->month = n; break;
3166 	    case 2: tss->day = n; break;
3167 	    }
3168 	    if (++i >= 3) {
3169 		i = 0;
3170 		m |= 1;
3171 		if (!(m & 2)) {
3172 		    m |= 8;
3173 		}
3174 		goto skip;
3175 	    } else {
3176 		++q;
3177 	    }
3178 	    break;
3179 	case ':':
3180 	    switch (i) {
3181 	    case 0: tss->hour = n; break;
3182 	    case 1: tss->minute = n; break;
3183 	    case 2: tss->second = n; break;
3184 	    }
3185 	    if (++i >= 3) {
3186 		i = 0;
3187 		m |= 2;
3188 		if (*q == '.') {
3189 		    in = '.';
3190 		    goto skip2;
3191 		}
3192 		if (*q == ' ') {
3193 		    if ((m & 1) == 0) {
3194 			char *e = NULL;
3195 
3196 			(void) strtol(q + 1, &e, 10);
3197 			if (e && *e == '-') {
3198 			    goto skip;
3199 			}
3200 		    }
3201 		    in = '.';
3202 		    goto skip2;
3203 		}
3204 		goto skip;
3205 	    } else {
3206 		++q;
3207 	    }
3208 	    break;
3209 	case '.':
3210 	    if (++i >= 1) {
3211 		int ndig = q - p;
3212 
3213 		if (p[0] == '+' || p[0] == '-') {
3214 		    ndig--;
3215 		}
3216 		while (ndig < 9) {
3217 		    n = n * 10;
3218 		    ++ndig;
3219 		}
3220 		tss->fraction = n;
3221 		m |= 4;
3222 		i = 0;
3223 	    }
3224 	default:
3225 	skip:
3226 	    in = '\0';
3227 	skip2:
3228 	    while (*q && !ISDIGIT(*q)) {
3229 		if ((q[0] == 'a' || q[0] == 'A') &&
3230 		    (q[1] == 'm' || q[1] == 'M')) {
3231 		    ampm = 0;
3232 		    ++q;
3233 		} else if ((q[0] == 'p' || q[0] == 'P') &&
3234 			   (q[1] == 'm' || q[1] == 'M')) {
3235 		    ampm = 1;
3236 		    ++q;
3237 		}
3238 		++q;
3239 	    }
3240 	}
3241 	p = q;
3242     }
3243     if ((m & 7) > 1 && (m & 8)) {
3244 	/* ISO8601 timezone */
3245 	if (p > str && ISDIGIT(*p)) {
3246 	    int nn, sign;
3247 
3248 	    q = p - 1;
3249 	    if (*q != '+' && *q != '-') {
3250 		goto done;
3251 	    }
3252 	    sign = (*q == '+') ? -1 : 1;
3253 	    q = NULL;
3254 	    n = strtol(p, &q, 10);
3255 	    if (!q || *q++ != ':' || !ISDIGIT(*q)) {
3256 		goto done;
3257 	    }
3258 	    p = q;
3259 	    q = NULL;
3260 	    nn = strtol(p, &q, 10);
3261 	    tss->minute += nn * sign;
3262 	    if ((SQLSMALLINT) tss->minute < 0) {
3263 		tss->hour -= 1;
3264 		tss->minute += 60;
3265 	    } else if (tss->minute >= 60) {
3266 		tss->hour += 1;
3267 		tss->minute -= 60;
3268 	    }
3269 	    tss->hour += n * sign;
3270 	    if ((SQLSMALLINT) tss->hour < 0) {
3271 		tss->day -= 1;
3272 		tss->hour += 24;
3273 	    } else if (tss->hour >= 24) {
3274 		tss->day += 1;
3275 		tss->hour -= 24;
3276 	    }
3277 	    if ((short) tss->day < 1 || tss->day >= 28) {
3278 		int mday, pday, pmon;
3279 
3280 		mday = getmdays(tss->year, tss->month);
3281 		pmon = tss->month - 1;
3282 		if (pmon < 1) {
3283 		    pmon = 12;
3284 		}
3285 		pday = getmdays(tss->year, pmon);
3286 		if ((SQLSMALLINT) tss->day < 1) {
3287 		    tss->month -= 1;
3288 		    tss->day = pday;
3289 		} else if (tss->day > mday) {
3290 		    tss->month += 1;
3291 		    tss->day = 1;
3292 		}
3293 		if ((SQLSMALLINT) tss->month < 1) {
3294 		    tss->year -= 1;
3295 		    tss->month = 12;
3296 		} else if (tss->month > 12) {
3297 		    tss->year += 1;
3298 		    tss->month = 1;
3299 		}
3300 	    }
3301 	}
3302     }
3303 done:
3304     if ((m & 1) &&
3305 	(tss->month < 1 || tss->month > 12 ||
3306 	 tss->day < 1 || tss->day > getmdays(tss->year, tss->month))) {
3307 	if (sepc == '/') {
3308 	    /* Try MM/DD/YYYY format */
3309 	    int t[3];
3310 
3311 	    t[0] = tss->year;
3312 	    t[1] = tss->month;
3313 	    t[2] = tss->day;
3314 	    tss->year = t[2];
3315 	    tss->day = t[1];
3316 	    tss->month = t[0];
3317 	}
3318     }
3319     /* Replace missing year/month/day with current date */
3320     if (!err && (m & 1) == 0) {
3321 #ifdef _WIN32
3322 	SYSTEMTIME t;
3323 
3324 	GetLocalTime(&t);
3325 	tss->year = t.wYear;
3326 	tss->month = t.wMonth;
3327 	tss->day = t.wDay;
3328 #else
3329 	struct timeval tv;
3330 	struct tm tm;
3331 
3332 	gettimeofday(&tv, NULL);
3333 	tm = *localtime(&tv.tv_sec);
3334 	tss->year = tm.tm_year + 1900;
3335 	tss->month = tm.tm_mon + 1;
3336 	tss->day = tm.tm_mday;
3337 #endif
3338     }
3339     /* Normalize fraction */
3340     if (tss->fraction < 0) {
3341 	tss->fraction = 0;
3342     }
3343     /* Final check for overflow */
3344     if (err ||
3345 	tss->month < 1 || tss->month > 12 ||
3346 	tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
3347 	tss->hour > 23 || tss->minute > 59 || tss->second > 59) {
3348 	return -1;
3349     }
3350     if ((m & 7) > 1) {
3351 	if (ampm > 0) {
3352 	    if (tss->hour < 12) {
3353 		tss->hour += 12;
3354 	    }
3355 	} else if (ampm == 0) {
3356 	    if (tss->hour == 12) {
3357 		tss->hour = 0;
3358 	    }
3359 	}
3360     }
3361     return ((m & 7) < 1) ? -1 : 0;
3362 }
3363 
3364 /**
3365  * Get boolean flag from string.
3366  * @param string string to be inspected
3367  * @result true or false
3368  */
3369 
3370 static int
getbool(char * string)3371 getbool(char *string)
3372 {
3373     if (string) {
3374 	return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
3375     }
3376     return 0;
3377 }
3378 
3379 /**
3380  * Internal function to release memory of blob
3381  * @param dummy unused
3382  * @param p pointer to memory
3383  */
3384 
3385 static void
blob_free(void * dummy,void * p)3386 blob_free(void *dummy, void *p)
3387 {
3388     sqlite4_free(0, p);
3389 }
3390 
3391 /**
3392  * SQLite function to import a BLOB from a file
3393  * @param ctx function context
3394  * @param nargs number arguments
3395  * @param args arguments
3396  */
3397 
3398 static void
blob_import(sqlite4_context * ctx,int nargs,sqlite4_value ** args)3399 blob_import(sqlite4_context *ctx, int nargs, sqlite4_value **args)
3400 {
3401 #if 0
3402     DBC *d = (DBC *) sqlite4_user_data(ctx);
3403 #endif
3404     char *filename = 0;
3405 
3406     if (nargs > 0) {
3407 	if (sqlite4_value_type(args[0]) != SQLITE4_NULL) {
3408 	    int nbytes;
3409 
3410 	    filename = (char *) sqlite4_value_text(args[0], &nbytes);
3411 	}
3412     }
3413     if (filename) {
3414 #ifdef _WIN32
3415 	char *wname = utf_to_wmb(filename, -1);
3416 	FILE *f;
3417 #else
3418 	FILE *f = fopen(filename, "r");
3419 #endif
3420 	char *p;
3421 	long n, nn;
3422 
3423 #ifdef _WIN32
3424 	if (wname) {
3425 	    f = fopen(wname, "rb");
3426 	} else {
3427 	    sqlite4_result_error(ctx, "out of memory", -1);
3428 	    return;
3429 	}
3430 	uc_free(wname);
3431 #endif
3432 	if (f) {
3433 	    if (fseek(f, 0, SEEK_END) == 0) {
3434 		n = ftell(f);
3435 		if (fseek(f, 0, SEEK_SET) == 0) {
3436 		    p = sqlite4_malloc(0, n);
3437 		    if (p) {
3438 			nn = fread(p, 1, n, f);
3439 			if (nn != n) {
3440 			    sqlite4_result_error(ctx, "read error", -1);
3441 			    sqlite4_free(0, p);
3442 			} else {
3443 			    sqlite4_result_blob(ctx, p, n, blob_free, 0);
3444 			}
3445 		    } else {
3446 			sqlite4_result_error(ctx, "out of memory", -1);
3447 		    }
3448 		} else {
3449 		    sqlite4_result_error(ctx, "seek error", -1);
3450 		}
3451 	    } else {
3452 		sqlite4_result_error(ctx, "seek error", -1);
3453 	    }
3454 	    fclose(f);
3455 	} else {
3456 	    sqlite4_result_error(ctx, "cannot open file", -1);
3457 	}
3458     } else {
3459 	sqlite4_result_error(ctx, "no filename given", -1);
3460     }
3461 }
3462 
3463 /**
3464  * SQLite function to export a BLOB to a file
3465  * @param ctx function context
3466  * @param nargs number arguments
3467  * @param args arguments
3468  */
3469 
3470 static void
blob_export(sqlite4_context * ctx,int nargs,sqlite4_value ** args)3471 blob_export(sqlite4_context *ctx, int nargs, sqlite4_value **args)
3472 {
3473 #if 0
3474     DBC *d = (DBC *) sqlite4_user_data(ctx);
3475 #endif
3476     char *filename = 0;
3477     char *p = 0;
3478     int n = 0;
3479 
3480     if (nargs > 0) {
3481 	p = (char *) sqlite4_value_blob(args[0], &n);
3482     }
3483     if (nargs > 1) {
3484 	if (sqlite4_value_type(args[1]) != SQLITE4_NULL) {
3485 	    int nbytes;
3486 
3487 	    filename = (char *) sqlite4_value_text(args[1], &nbytes);
3488 	}
3489     }
3490     if (p) {
3491 	if (filename) {
3492 #ifdef _WIN32
3493 	    char *wname = utf_to_wmb(filename, -1);
3494 	    FILE *f;
3495 #else
3496 	    FILE *f = fopen(filename, "w");
3497 #endif
3498 	    int nn;
3499 
3500 #ifdef _WIN32
3501 	    if (wname) {
3502 		f = fopen(wname, "wb");
3503 	    } else {
3504 		sqlite4_result_error(ctx, "out of memory", -1);
3505 		return;
3506 	    }
3507 	    uc_free(wname);
3508 #endif
3509 	    if (f) {
3510 		nn = fwrite(p, 1, n, f);
3511 		fclose(f);
3512 		if (nn != n) {
3513 		    sqlite4_result_error(ctx, "write error", -1);
3514 		} else {
3515 		    sqlite4_result_int(ctx, nn);
3516 		}
3517 	    } else {
3518 		sqlite4_result_error(ctx, "cannot open file", -1);
3519 	    }
3520 	} else {
3521 	    sqlite4_result_error(ctx, "no filename given", -1);
3522 	}
3523     } else {
3524 	sqlite4_result_null(ctx);
3525     }
3526 }
3527 
3528 /**
3529  * SQLite trace or profile callback
3530  * @param arg DBC pointer
3531  * @param msg log message, SQL text
3532  * @param et  elapsed time
3533  */
3534 
3535 static void
dbtrace(void * arg,const char * msg,sqlite4_uint64 et)3536 dbtrace(void *arg, const char *msg, sqlite4_uint64 et)
3537 {
3538     DBC *d = (DBC *) arg;
3539 
3540     if (msg && d->trace) {
3541 	int len = strlen(msg);
3542 	unsigned long s, f;
3543 
3544 	if (len > 0) {
3545 	    char *end = "\n";
3546 
3547 	    if (msg[len - 1] != ';') {
3548 		end = ";\n";
3549 	    }
3550 	    fprintf(d->trace, "%s%s", msg, end);
3551 	    s = et / 1000000000LL;
3552 	    f = et % 1000000000LL;
3553 	    fprintf(d->trace, "-- took %lu.%09lu seconds\n", s, f);
3554 	    fflush(d->trace);
3555 	}
3556     }
3557 }
3558 
3559 /**
3560  * Trace function for SQLite API calls
3561  * @param d pointer to database connection handle
3562  * @param fn SQLite function name
3563  * @param sql SQL string
3564  */
3565 
3566 static void
dbtraceapi(DBC * d,char * fn,const char * sql)3567 dbtraceapi(DBC *d, char *fn, const char *sql)
3568 {
3569     if (fn && d->trace) {
3570 	if (sql) {
3571 	    fprintf(d->trace, "-- %s: %s\n", fn, sql);
3572 	} else {
3573 	    fprintf(d->trace, "-- %s\n", fn);
3574 	}
3575 	fflush(d->trace);
3576     }
3577 }
3578 
3579 /**
3580  * Trace function for SQLite return codes
3581  * @param d pointer to database connection handle
3582  * @param rc SQLite return code
3583  * @param err error string or NULL
3584  */
3585 
3586 static void
dbtracerc(DBC * d,int rc,char * err)3587 dbtracerc(DBC *d, int rc, char *err)
3588 {
3589     if (rc != SQLITE4_OK && d->trace) {
3590 	fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
3591 	fprintf(d->trace, err ? ": %s\n" : "\n", err);
3592 	fflush(d->trace);
3593     }
3594 }
3595 
3596 /**
3597  * Open SQLite database file given file name and flags.
3598  * @param d DBC pointer
3599  * @param name file name
3600  * @param isu true/false: file name is UTF8 encoded
3601  * @param dsn data source name
3602  * @param sflag STEPAPI flag
3603  * @param spflag SyncPragma string
3604  * @param ntflag NoTransaction string
3605  * @param jmode JournalMode string
3606  * @param busy busy/lock timeout
3607  * @result ODBC error code
3608  */
3609 
3610 static SQLRETURN
dbopen(DBC * d,char * name,int isu,char * dsn,char * sflag,char * spflag,char * ntflag,char * jmode,char * busy)3611 dbopen(DBC *d, char *name, int isu, char *dsn, char *sflag,
3612        char *spflag, char *ntflag, char *jmode, char *busy)
3613 {
3614     char *endp = NULL;
3615     int rc, tmp, busyto = 100000;
3616     int flags = SQLITE4_OPEN_READWRITE | SQLITE4_OPEN_CREATE;
3617     char *uname = name;
3618 
3619     if (d->sqlite) {
3620 	if (d->trace) {
3621 	    fprintf(d->trace, "-- sqlite4_close (deferred): '%s'\n",
3622 		    d->dbname);
3623 	    fflush(d->trace);
3624 	}
3625 	sqlite4_close(d->sqlite, 0);
3626 	d->sqlite = NULL;
3627     }
3628     if (d->nocreat) {
3629 	flags &= ~ SQLITE4_OPEN_CREATE;
3630     }
3631 #if defined(_WIN32) || defined(_WIN64)
3632     if (!isu) {
3633 	char expname[SQL_MAX_MESSAGE_LENGTH * 2];
3634 
3635 	expname[0] = '\0';
3636 	rc = ExpandEnvironmentStrings(name, expname, sizeof (expname));
3637 	if (rc <= sizeof (expname)) {
3638 	    uname = wmb_to_utf(expname, rc - 1);
3639 	} else {
3640 	    uname = wmb_to_utf(name, -1);
3641 	}
3642 	if (!uname) {
3643 	    rc = SQLITE4_NOMEM;
3644 	    setstatd(d, rc, "out of memory", (*d->ov3) ? "HY000" : "S1000");
3645 	    return SQL_ERROR;
3646 	}
3647     }
3648 #endif
3649 #ifdef SQLITE4_OPEN_URI
3650     flags |= SQLITE4_OPEN_URI;
3651 #endif
3652     rc = sqlite4_open(0, uname, &d->sqlite, /* flags ?? */ 0);
3653 #if defined(WINTERFACE) || defined(_WIN32) || defined(_WIN64)
3654     if (uname != name) {
3655 	uc_free(uname);
3656     }
3657 #endif
3658     if (rc != SQLITE4_OK) {
3659 connfail:
3660 	setstatd(d, rc, "connect failed", (*d->ov3) ? "HY000" : "S1000");
3661 	if (d->sqlite) {
3662 	    sqlite4_close(d->sqlite, 0);
3663 	    d->sqlite = NULL;
3664 	}
3665 	return SQL_ERROR;
3666     }
3667     d->pwd = NULL;
3668     d->pwdLen = 0;
3669     if (d->trace) {
3670 	sqlite4_profile(d->sqlite, d, dbtrace, 0);
3671     }
3672     d->step_enable = getbool(sflag);
3673     d->trans_disable = getbool(ntflag);
3674     d->curtype = d->step_enable ?
3675 	SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
3676     tmp = strtol(busy, &endp, 0);
3677     if (endp && *endp == '\0' && endp != busy) {
3678 	busyto = tmp;
3679     }
3680     if (busyto < 1 || busyto > 1000000) {
3681 	busyto = 1000000;
3682     }
3683     d->timeout = busyto;
3684     freep(&d->dbname);
3685     d->dbname = xstrdup(name);
3686     freep(&d->dsn);
3687     d->dsn = xstrdup(dsn);
3688     if ((rc = setsqliteopts(d->sqlite, d)) != SQLITE4_OK) {
3689 	if (d->trace) {
3690 	    fprintf(d->trace, "-- sqlite4_close: '%s'\n",
3691 		    d->dbname);
3692 	    fflush(d->trace);
3693 	}
3694 	sqlite4_close(d->sqlite, 0);
3695 	d->sqlite = NULL;
3696 	goto connfail;
3697     }
3698     if (!spflag || spflag[0] == '\0') {
3699 	spflag = "NORMAL";
3700     }
3701     if (spflag[0] != '\0') {
3702 	char syncp[128];
3703 
3704 	sprintf(syncp, "PRAGMA synchronous = %8.8s;", spflag);
3705 	sqlite4_exec(d->sqlite, syncp, NULL, NULL);
3706     }
3707     if (jmode[0] != '\0') {
3708 	char jourp[128];
3709 
3710 	sprintf(jourp, "PRAGMA journal_mode = %16.16s;", jmode);
3711 	sqlite4_exec(d->sqlite, jourp, NULL, NULL);
3712     }
3713     if (d->trace) {
3714 	fprintf(d->trace, "-- sqlite4_open: '%s'\n", d->dbname);
3715 	fflush(d->trace);
3716     }
3717 #if defined(_WIN32) || defined(_WIN64)
3718     {
3719 	char pname[MAX_PATH];
3720 	HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
3721 			       FALSE, GetCurrentProcessId());
3722 
3723 	pname[0] = '\0';
3724 	if (h) {
3725 	    HMODULE m = NULL, l = LoadLibrary("psapi.dll");
3726 	    DWORD need;
3727 	    typedef BOOL (WINAPI *epmfunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
3728 	    typedef BOOL (WINAPI *gmbfunc)(HANDLE, HMODULE, LPSTR, DWORD);
3729 	    epmfunc epm;
3730 	    gmbfunc gmb;
3731 
3732 	    if (l) {
3733 		epm = (epmfunc) GetProcAddress(l, "EnumProcessModules");
3734 		gmb = (gmbfunc) GetProcAddress(l, "GetModuleBaseNameA");
3735 		if (epm && gmb && epm(h, &m, sizeof (m), &need)) {
3736 		    gmb(h, m, pname, sizeof (pname));
3737 		}
3738 		FreeLibrary(l);
3739 	    }
3740 	    CloseHandle(h);
3741 	}
3742 	d->xcelqrx = strncasecmp(pname, "EXCEL", 5) == 0 ||
3743 		     strncasecmp(pname, "MSQRY", 5) == 0;
3744 	if (d->trace && d->xcelqrx) {
3745 	    fprintf(d->trace, "-- enabled EXCEL quirks\n");
3746 	    fflush(d->trace);
3747 	}
3748     }
3749 #endif
3750     sqlite4_create_function(d->sqlite, "blob_import", 1, d,
3751 			    blob_import, 0, 0, 0);
3752     sqlite4_create_function(d->sqlite, "blob_export", 2, d,
3753 			    blob_export, 0, 0, 0);
3754     return SQL_SUCCESS;
3755 }
3756 
3757 /**
3758  * Load SQLite extension modules, if any
3759  * @param d DBC pointer
3760  * @param exts string, comma separated extension names
3761  */
3762 
3763 static void
dbloadext(DBC * d,char * exts)3764 dbloadext(DBC *d, char *exts)
3765 {
3766 #if 0
3767     char *p;
3768     char path[SQL_MAX_MESSAGE_LENGTH];
3769     int plen = 0;
3770 
3771     if (!d->sqlite) {
3772 	return;
3773     }
3774 #if defined(_WIN32) || defined(_WIN64)
3775     GetModuleFileName(hModule, path, sizeof (path));
3776     p = strrchr(path, '\\');
3777     plen = p ? ((p + 1) - path) : 0;
3778 #endif
3779     do {
3780 	p = strchr(exts, ',');
3781 	if (p) {
3782 	    strncpy(path + plen, exts, p - exts);
3783 	    path[plen + (p - exts)] = '\0';
3784 	} else {
3785 	    strcpy(path + plen, exts);
3786 	}
3787 	if (exts[0]) {
3788 	    char *errmsg = NULL;
3789 	    int rc;
3790 #if defined(_WIN32) || defined(_WIN64)
3791 	    char *q;
3792 
3793 	    q = path + plen;
3794 	    if (!(q[0] &&
3795 		  ((q[1] == ':' && (q[2] == '\\' || q[2] == '/')) ||
3796 		   q[0] == '\\' || q[0] == '/' || q[0] == '.'))) {
3797 		q = path;
3798 	    }
3799 	    rc = sqlite4_load_extension(d->sqlite, q, 0, &errmsg);
3800 #else
3801 	    rc = sqlite4_load_extension(d->sqlite, path, 0, &errmsg);
3802 #endif
3803 	    if (rc != SQLITE4_OK) {
3804 #if defined(_WIN32) || defined(_WIN64)
3805 		char buf[512], msg[512];
3806 
3807 		LoadString(hModule, IDS_EXTERR, buf, sizeof (buf));
3808 		wsprintf(msg, buf, q, errmsg ?
3809 			 errmsg : "no error info available");
3810 		LoadString(hModule, IDS_EXTTITLE, buf, sizeof (buf));
3811 		MessageBox(NULL, msg, buf,
3812 			   MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
3813 			   MB_SETFOREGROUND);
3814 #else
3815 		fprintf(stderr, "extension '%s' did not load%s%s\n",
3816 			path, errmsg ? ": " : "", errmsg ? errmsg : "");
3817 #endif
3818 	    }
3819 	}
3820 	if (p) {
3821 	    exts = p + 1;
3822 	}
3823     } while (p);
3824 #endif
3825 }
3826 
3827 /**
3828  * Find out column type
3829  * @param s4stmt SQLite statement pointer
3830  * @param col column number
3831  * @param d DBC pointer (for tracing only)
3832  * @param guessed_types flag array
3833  * @result type name as string
3834  */
3835 
3836 static char *
s4stmt_coltype(sqlite4_stmt * s4stmt,int col,DBC * d,int * guessed_types)3837 s4stmt_coltype(sqlite4_stmt *s4stmt, int col, DBC *d, int *guessed_types)
3838 {
3839     char *typename = (char *) sqlite4_column_decltype(s4stmt, col);
3840     char guess[64];
3841 
3842     guess[0] = '\0';
3843     if (!typename) {
3844 	int coltype = sqlite4_column_type(s4stmt, col);
3845 
3846 	if (guessed_types) {
3847 	    guessed_types[0]++;
3848 	}
3849 	if (d->trace) {
3850 	    sprintf(guess, " (guessed from %d)", coltype);
3851 	}
3852 	switch (coltype) {
3853 	case SQLITE4_INTEGER: typename = "integer"; break;
3854 	case SQLITE4_FLOAT:   typename = "double";  break;
3855 	default:
3856 	case SQLITE4_TEXT:    typename = "varchar"; break;
3857 	case SQLITE4_BLOB:    typename = "blob";    break;
3858 #if 0
3859 	case SQLITE4_NULL:    typename = "null";    break;
3860 #endif
3861 	}
3862     }
3863     if (d->trace) {
3864 	fprintf(d->trace, "-- column %d type%s: '%s'\n", col + 1,
3865 		guess, typename);
3866 	fflush(d->trace);
3867     }
3868     return typename;
3869 }
3870 
3871 /**
3872  * Add meta data for column
3873  * @param s4stmt SQLite statement pointer
3874  * @param col column number
3875  * @param d DBC pointer (for tracing only)
3876  * @param ci pointer to COL
3877  */
3878 
3879 static void
s4stmt_addmeta(sqlite4_stmt * s4stmt,int col,DBC * d,COL * ci)3880 s4stmt_addmeta(sqlite4_stmt *s4stmt, int col, DBC *d, COL *ci)
3881 {
3882     int nn = 0, pk = 0, ai = 0;
3883     const char *dn, *tn, *cn, *dummy[4];
3884 
3885     dn = sqlite4_column_database_name(s4stmt, col);
3886     tn = sqlite4_column_table_name(s4stmt, col);
3887     cn = sqlite4_column_origin_name(s4stmt, col);
3888     dummy[0] = dummy[1] = 0;
3889 #if 0
3890     if (tn && cn) {
3891 	sqlite4_table_column_metadata(d->sqlite, dn, tn, cn,
3892 				      dummy, dummy + 1,
3893 				      &nn, &pk, &ai);
3894     }
3895 #endif
3896     ci->autoinc = ai ? SQL_TRUE: SQL_FALSE;
3897     ci->notnull = nn ? SQL_NO_NULLS : SQL_NULLABLE;
3898     ci->ispk = pk ? 1 : 0;
3899     if (d->trace) {
3900 	fprintf(d->trace, "-- column %d %s\n",
3901 		col + 1, nn ? "notnull" : "nullable");
3902 	if (ai) {
3903 	    fprintf(d->trace, "-- column %d autoincrement\n", col + 1);
3904 	}
3905 	fflush(d->trace);
3906     }
3907     ci->isrowid = 0;
3908     if (ci->ispk && tn) {
3909 	nn = pk = ai = 0;
3910 	dummy[2] = dummy[3] = 0;
3911 
3912 #if 0
3913 	sqlite4_table_column_metadata(d->sqlite, dn, tn, "rowid",
3914 				      dummy + 2, dummy + 3,
3915 				      &nn, &pk, &ai);
3916 #endif
3917 	if (pk && dummy[0] && dummy[0] == dummy[2]) {
3918 	    ci->isrowid = 1;
3919 	}
3920     }
3921 }
3922 
3923 /**
3924  * Do one sqlite statement step gathering one result row
3925  * @param s statement pointer
3926  * @result ODBC error code
3927  */
3928 
3929 static int
s4stmt_step(STMT * s)3930 s4stmt_step(STMT *s)
3931 {
3932     DBC *d = (DBC *) s->dbc;
3933     char **rowd = NULL;
3934     const char *errp = NULL;
3935     int i, ncols, rc;
3936 
3937     if (s != d->cur_s4stmt || !s->s4stmt) {
3938 	setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
3939 	return SQL_ERROR;
3940     }
3941     rc = sqlite4_step(s->s4stmt);
3942     if (rc == SQLITE4_ROW || rc == SQLITE4_DONE) {
3943 	++s->s4stmt_rownum;
3944 	ncols = sqlite4_column_count(s->s4stmt);
3945 	if (d->s4stmt_needmeta && s->s4stmt_rownum == 0 && ncols > 0) {
3946 	    PTRDIFF_T size;
3947 	    char *p;
3948 	    COL *dyncols;
3949 	    const char *colname, *typename;
3950 	    char *tblname, *dbname;
3951 
3952 	    for (i = size = 0; i < ncols; i++) {
3953 		colname = sqlite4_column_name(s->s4stmt, i);
3954 		size += 3 + 3 * strlen(colname);
3955 	    }
3956 	    tblname = (char *) size;
3957 	    for (i = 0; i < ncols; i++) {
3958 		p = (char *) sqlite4_column_table_name(s->s4stmt, i);
3959 		size += 2 + (p ? strlen(p) : 0);
3960 	    }
3961 	    dbname = (char *) size;
3962 	    for (i = 0; i < ncols; i++) {
3963 		p = (char *) sqlite4_column_database_name(s->s4stmt, i);
3964 		size += 2 + (p ? strlen(p) : 0);
3965 	    }
3966 	    dyncols = xmalloc(ncols * sizeof (COL) + size);
3967 	    if (!dyncols) {
3968 		freedyncols(s);
3969 		s->ncols = 0;
3970 		dbtraceapi(d, "sqlite4_finalize", 0);
3971 		sqlite4_finalize(s->s4stmt);
3972 		s->s4stmt = NULL;
3973 		d->cur_s4stmt = NULL;
3974 		return nomem(s);
3975 	    }
3976 	    p = (char *) (dyncols + ncols);
3977 	    tblname = p + (PTRDIFF_T) tblname;
3978 	    dbname = p + (PTRDIFF_T) dbname;
3979 	    for (i = 0; i < ncols; i++) {
3980 		char *q;
3981 
3982 		colname = sqlite4_column_name(s->s4stmt, i);
3983 		if (d->trace) {
3984 		    fprintf(d->trace, "-- column %d name: '%s'\n",
3985 			    i + 1, colname);
3986 		    fflush(d->trace);
3987 		}
3988 		q = (char *) sqlite4_column_table_name(s->s4stmt, i);
3989 		strcpy(tblname, q ? q : "");
3990 		if (d->trace) {
3991 		    fprintf(d->trace, "-- table %d name: '%s'\n",
3992 			    i + 1, tblname);
3993 		    fflush(d->trace);
3994 		}
3995 		dyncols[i].table = tblname;
3996 		tblname += strlen(tblname) + 1;
3997 		q = (char *) sqlite4_column_database_name(s->s4stmt, i);
3998 		strcpy(dbname, q ? q : "");
3999 		if (d->trace) {
4000 		    fprintf(d->trace, "-- database %d name: '%s'\n",
4001 			    i + 1, dbname);
4002 		    fflush(d->trace);
4003 		}
4004 		dyncols[i].db = dbname;
4005 		dbname += strlen(dbname) + 1;
4006 		typename = s4stmt_coltype(s->s4stmt, i, d, 0);
4007 		strcpy(p, colname);
4008 		dyncols[i].label = p;
4009 		p += strlen(p) + 1;
4010 		q = strchr(colname, '.');
4011 		if (q) {
4012 		    char *q2 = strchr(q + 1, '.');
4013 
4014 		    /* SQLite 3.3.4 produces view.table.column sometimes */
4015 		    if (q2) {
4016 			q = q2;
4017 		    }
4018 		}
4019 		if (q) {
4020 		    strncpy(p, colname, q - colname);
4021 		    p[q - colname] = '\0';
4022 		    p += strlen(p) + 1;
4023 		    strcpy(p, q + 1);
4024 		    dyncols[i].column = p;
4025 		    p += strlen(p) + 1;
4026 		} else {
4027 		    strcpy(p, colname);
4028 		    dyncols[i].column = p;
4029 		    p += strlen(p) + 1;
4030 		}
4031 		if (s->longnames) {
4032 		    dyncols[i].column = dyncols[i].label;
4033 		}
4034 #ifdef SQL_LONGVARCHAR
4035 		dyncols[i].type = SQL_LONGVARCHAR;
4036 		dyncols[i].size = 65535;
4037 #else
4038 		dyncols[i].type = SQL_VARCHAR;
4039 		dyncols[i].size = 255;
4040 #endif
4041 		dyncols[i].index = i;
4042 		dyncols[i].scale = 0;
4043 		dyncols[i].prec = 0;
4044 		dyncols[i].nosign = 1;
4045 		s4stmt_addmeta(s->s4stmt, i, d, &dyncols[i]);
4046 		dyncols[i].typename = xstrdup(typename);
4047 	    }
4048 	    freedyncols(s);
4049 	    s->ncols = s->dcols = ncols;
4050 	    s->dyncols = s->cols = dyncols;
4051 	    fixupdyncols(s, d);
4052 	    mkbindcols(s, s->ncols);
4053 	    d->s4stmt_needmeta = 0;
4054 	}
4055 	if (ncols <= 0) {
4056 	    goto killstmt;
4057 	}
4058 	if (rc == SQLITE4_DONE) {
4059 	    freeresult(s, 0);
4060 	    s->nrows = 0;
4061 	    dbtraceapi(d, "sqlite4_finalize", 0);
4062 	    sqlite4_finalize(s->s4stmt);
4063 	    s->s4stmt = NULL;
4064 	    d->cur_s4stmt = NULL;
4065 	    return SQL_SUCCESS;
4066 	}
4067 	rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
4068 	if (rowd) {
4069 	    const char *value;
4070 
4071 	    rowd[0] = (char *) ((PTRDIFF_T) (ncols * 2));
4072 	    ++rowd;
4073 	    for (i = 0; i < ncols; i++) {
4074 		int coltype = sqlite4_column_type(s->s4stmt, i);
4075 
4076 		rowd[i] = rowd[i + ncols] = NULL;
4077 		if (coltype == SQLITE4_BLOB) {
4078 		    int k, nbytes;
4079 		    char *qp;
4080 		    unsigned const char *bp;
4081 
4082 		    bp = sqlite4_column_blob(s->s4stmt, i, &nbytes);
4083 		    qp = xmalloc(nbytes * 2 + 4);
4084 		    if (qp) {
4085 			rowd[i + ncols] = qp;
4086 			*qp++ = 'X';
4087 			*qp++ = '\'';
4088 			for (k = 0; k < nbytes; k++) {
4089 			    *qp++ = xdigits[(bp[k] >> 4)];
4090 			    *qp++ = xdigits[(bp[k] & 0xF)];
4091 			}
4092 			*qp++ = '\'';
4093 			*qp = '\0';
4094 		    }
4095 #ifdef _MSC_VER
4096 		} else if (coltype == SQLITE4_FLOAT) {
4097 		    struct lconv *lc = 0;
4098 		    double d = sqlite4_column_double(s->s4stmt, i);
4099 		    char *p, buffer[128];
4100 
4101 		    /*
4102 		     * This avoids floating point rounding
4103 		     * and formatting problems of some SQLite
4104 		     * versions in conjunction with MSVC 2010.
4105 		     */
4106 		    snprintf(buffer, sizeof (buffer), "%.15g", d);
4107 		    lc = localeconv();
4108 		    if (lc && lc->decimal_point && lc->decimal_point[0] &&
4109 			lc->decimal_point[0] != '.') {
4110 			p = strchr(buffer, lc->decimal_point[0]);
4111 			if (p) {
4112 			    *p = '.';
4113 			}
4114 		    }
4115 		    rowd[i + ncols] = xstrdup(buffer);
4116 #endif
4117 		} else if (coltype != SQLITE4_NULL) {
4118 		    int nbytes;
4119 
4120 		    value = sqlite4_column_text(s->s4stmt, i, &nbytes);
4121 		    rowd[i + ncols] = xstrdup((char *) value);
4122 		}
4123 	    }
4124 	    for (i = 0; i < ncols; i++) {
4125 		int coltype = sqlite4_column_type(s->s4stmt, i);
4126 
4127 		value = NULL;
4128 		if (coltype == SQLITE4_BLOB) {
4129 		    int nbytes;
4130 
4131 		    value = sqlite4_column_blob(s->s4stmt, i, &nbytes);
4132 		} else if (coltype != SQLITE4_NULL) {
4133 		    int nbytes;
4134 
4135 		    value = sqlite4_column_text(s->s4stmt, i, &nbytes);
4136 		}
4137 		if (value && !rowd[i + ncols]) {
4138 		    freerows(rowd);
4139 		    rowd = 0;
4140 		    break;
4141 		}
4142 	    }
4143 	}
4144 	if (rowd) {
4145 	    freeresult(s, 0);
4146 	    s->nrows = 1;
4147 	    s->rows = rowd;
4148 	    s->rowfree = freerows;
4149 	    if (rc == SQLITE4_DONE) {
4150 		dbtraceapi(d, "sqlite4_finalize", 0);
4151 		sqlite4_finalize(s->s4stmt);
4152 		s->s4stmt = NULL;
4153 		d->cur_s4stmt = NULL;
4154 	    }
4155 	    return SQL_SUCCESS;
4156 	}
4157     }
4158 killstmt:
4159     dbtraceapi(d, "sqlite4_reset", 0);
4160     rc = sqlite4_reset(s->s4stmt);
4161     s->s4stmt_noreset = 1;
4162     errp = sqlite4_errmsg(d->sqlite);
4163     if (d->cur_s4stmt == s) {
4164 	d->cur_s4stmt = NULL;
4165     }
4166     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
4167 	    errp ? errp : "unknown error", rc);
4168     return SQL_ERROR;
4169 }
4170 
4171 /**
4172  * Stop running sqlite statement
4173  * @param s statement pointer
4174  */
4175 
4176 static void
s4stmt_end(STMT * s)4177 s4stmt_end(STMT *s)
4178 {
4179     DBC *d;
4180 
4181     if (!s || !s->s4stmt) {
4182 	return;
4183     }
4184     d = (DBC *) s->dbc;
4185     if (d) {
4186 	d->busyint = 0;
4187     }
4188     if (!s->s4stmt_noreset) {
4189 	dbtraceapi(d, "sqlite4_reset", 0);
4190 	sqlite4_reset(s->s4stmt);
4191 	s->s4stmt_noreset = 1;
4192 	s->s4stmt_rownum = -1;
4193     }
4194     if (d->cur_s4stmt == s) {
4195 	d->cur_s4stmt = NULL;
4196     }
4197 }
4198 
4199 /**
4200  * Conditionally stop running sqlite statement
4201  * @param s statement pointer
4202  */
4203 
4204 static void
s4stmt_end_if(STMT * s)4205 s4stmt_end_if(STMT *s)
4206 {
4207     DBC *d = (DBC *) s->dbc;
4208 
4209     if (d) {
4210 	d->busyint = 0;
4211     }
4212     if (d && d->cur_s4stmt == s) {
4213 	s4stmt_end(s);
4214     }
4215 }
4216 
4217 /**
4218  * Drop running sqlite statement in STMT
4219  * @param s statement pointer
4220  */
4221 
4222 static void
s4stmt_drop(STMT * s)4223 s4stmt_drop(STMT *s)
4224 {
4225     if (s->s4stmt) {
4226 	DBC *d = (DBC *) s->dbc;
4227 
4228 	if (d) {
4229 	    dbtraceapi(d, "sqlite4_finalize", 0);
4230 	}
4231 	sqlite4_finalize(s->s4stmt);
4232 	s->s4stmt = NULL;
4233 	s->s4stmt_rownum = 0;
4234     }
4235 }
4236 
4237 /**
4238  * Start sqlite statement for execution of SELECT statement.
4239  * @param s statement pointer
4240  * @result ODBC error code
4241  */
4242 
4243 static SQLRETURN
s4stmt_start(STMT * s)4244 s4stmt_start(STMT *s)
4245 {
4246     DBC *d = (DBC *) s->dbc;
4247     int sqlleft;
4248     sqlite4_stmt *s4stmt = NULL;
4249     int rc, nretry = 0;
4250 
4251     d->s4stmt_needmeta = 0;
4252     if (!s->s4stmt) {
4253 	dbtraceapi(d, "sqlite4_prepare", (char *) s->query);
4254 	do {
4255 	    s4stmt = NULL;
4256 	    rc = sqlite4_prepare(d->sqlite, (char *) s->query, -1,
4257 				 &s4stmt, &sqlleft);
4258 	    if (rc != SQLITE4_OK) {
4259 		if (s4stmt) {
4260 		    sqlite4_finalize(s4stmt);
4261 		    s4stmt = NULL;
4262 		}
4263 	    }
4264 	} while (rc == SQLITE4_SCHEMA && (++nretry) < 2);
4265 	dbtracerc(d, rc, NULL);
4266 	if (rc != SQLITE4_OK) {
4267 	    if (s4stmt) {
4268 		dbtraceapi(d, "sqlite4_finalize", NULL);
4269 		sqlite4_finalize(s4stmt);
4270 	    }
4271 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
4272 		    sqlite4_errmsg(d->sqlite), rc);
4273 	    return SQL_ERROR;
4274 	}
4275 	if (sqlite4_bind_parameter_count(s4stmt) != s->nparams) {
4276 	    dbtraceapi(d, "sqlite4_finalize", 0);
4277 	    sqlite4_finalize(s4stmt);
4278 	    setstat(s, SQLITE4_ERROR, "parameter marker count incorrect",
4279 		    (*s->ov3) ? "HY000" : "S1000");
4280 	    return SQL_ERROR;
4281 	}
4282 	s->s4stmt = s4stmt;
4283 	s->s4stmt_noreset = 1;
4284 	d->s4stmt_needmeta = 1;
4285     }
4286     d->cur_s4stmt = s;
4287     s->s4stmt_rownum = -1;
4288     s4bind(d, s->s4stmt, s->nparams, s->bindparms);
4289     return SQL_SUCCESS;
4290 }
4291 
4292 #ifndef WINTERFACE
4293 /**
4294  * Function not implemented.
4295  */
4296 
4297 SQLRETURN SQL_API
SQLDataSources(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)4298 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
4299 	       SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
4300 	       SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
4301 {
4302     if (env == SQL_NULL_HENV) {
4303 	return SQL_INVALID_HANDLE;
4304     }
4305     return SQL_ERROR;
4306 }
4307 #endif
4308 
4309 #ifdef WINTERFACE
4310 /**
4311  * Function not implemented.
4312  */
4313 
4314 SQLRETURN SQL_API
SQLDataSourcesW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLWCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)4315 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
4316 		SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
4317 		SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
4318 {
4319     if (env == SQL_NULL_HENV) {
4320 	return SQL_INVALID_HANDLE;
4321     }
4322     return SQL_ERROR;
4323 }
4324 #endif
4325 
4326 #ifndef WINTERFACE
4327 /**
4328  * Function not implemented.
4329  */
4330 
4331 SQLRETURN SQL_API
SQLDrivers(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)4332 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
4333 	   SQLSMALLINT descmax, SQLSMALLINT *desclenp,
4334 	   SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
4335 {
4336     if (env == SQL_NULL_HENV) {
4337 	return SQL_INVALID_HANDLE;
4338     }
4339     return SQL_ERROR;
4340 }
4341 #endif
4342 
4343 #ifdef WINTERFACE
4344 /**
4345  * Function not implemented.
4346  */
4347 
4348 SQLRETURN SQL_API
SQLDriversW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLWCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)4349 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
4350 	    SQLSMALLINT descmax, SQLSMALLINT *desclenp,
4351 	    SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
4352 {
4353     if (env == SQL_NULL_HENV) {
4354 	return SQL_INVALID_HANDLE;
4355     }
4356     return SQL_ERROR;
4357 }
4358 #endif
4359 
4360 #ifndef WINTERFACE
4361 /**
4362  * Function not implemented.
4363  */
4364 
4365 SQLRETURN SQL_API
SQLBrowseConnect(SQLHDBC dbc,SQLCHAR * connin,SQLSMALLINT conninLen,SQLCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)4366 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
4367 		 SQLCHAR *connout, SQLSMALLINT connoutMax,
4368 		 SQLSMALLINT *connoutLen)
4369 {
4370     SQLRETURN ret;
4371 
4372     HDBC_LOCK(dbc);
4373     ret = drvunimpldbc(dbc);
4374     HDBC_UNLOCK(dbc);
4375     return ret;
4376 }
4377 #endif
4378 
4379 #ifdef WINTERFACE
4380 /**
4381  * Function not implemented.
4382  */
4383 
4384 SQLRETURN SQL_API
SQLBrowseConnectW(SQLHDBC dbc,SQLWCHAR * connin,SQLSMALLINT conninLen,SQLWCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)4385 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
4386 		  SQLWCHAR *connout, SQLSMALLINT connoutMax,
4387 		  SQLSMALLINT *connoutLen)
4388 {
4389     SQLRETURN ret;
4390 
4391     HDBC_LOCK(dbc);
4392     ret = drvunimpldbc(dbc);
4393     HDBC_UNLOCK(dbc);
4394     return ret;
4395 }
4396 #endif
4397 
4398 /**
4399  * Internal put (partial) parameter data into executing statement.
4400  * @param stmt statement handle
4401  * @param data pointer to data
4402  * @param len length of data
4403  * @result ODBC error code
4404  */
4405 
4406 static SQLRETURN
drvputdata(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)4407 drvputdata(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
4408 {
4409     STMT *s;
4410     int i, dlen, done = 0;
4411     BINDPARM *p;
4412 
4413     if (stmt == SQL_NULL_HSTMT) {
4414 	return SQL_INVALID_HANDLE;
4415     }
4416     s = (STMT *) stmt;
4417     if (!s->query || s->nparams <= 0) {
4418 seqerr:
4419 	setstat(s, -1, "sequence error", "HY010");
4420 	return SQL_ERROR;
4421     }
4422     for (i = (s->pdcount < 0) ? 0 : s->pdcount; i < s->nparams; i++) {
4423 	p = &s->bindparms[i];
4424 	if (p->need > 0) {
4425 	    int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
4426 
4427 	    if (len == SQL_NULL_DATA) {
4428 		freep(&p->parbuf);
4429 		p->param = NULL;
4430 		p->len = SQL_NULL_DATA;
4431 		p->need = -1;
4432 	    } else if (type != SQL_C_CHAR
4433 #ifdef WCHARSUPPORT
4434 		       && type != SQL_C_WCHAR
4435 #endif
4436 		       && type != SQL_C_BINARY) {
4437 		int size = 0;
4438 
4439 		switch (type) {
4440 		case SQL_C_TINYINT:
4441 		case SQL_C_UTINYINT:
4442 		case SQL_C_STINYINT:
4443 #ifdef SQL_BIT
4444 		case SQL_C_BIT:
4445 #endif
4446 		    size = sizeof (SQLCHAR);
4447 		    break;
4448 		case SQL_C_SHORT:
4449 		case SQL_C_USHORT:
4450 		case SQL_C_SSHORT:
4451 		    size = sizeof (SQLSMALLINT);
4452 		    break;
4453 		case SQL_C_LONG:
4454 		case SQL_C_ULONG:
4455 		case SQL_C_SLONG:
4456 		    size = sizeof (SQLINTEGER);
4457 		    break;
4458 #ifdef SQL_BIGINT
4459 		case SQL_C_UBIGINT:
4460 		case SQL_C_SBIGINT:
4461 		    size = sizeof (SQLBIGINT);
4462 		    break;
4463 #endif
4464 		case SQL_C_FLOAT:
4465 		    size = sizeof (float);
4466 		    break;
4467 		case SQL_C_DOUBLE:
4468 		    size = sizeof (double);
4469 		    break;
4470 #ifdef SQL_C_TYPE_DATE
4471 		case SQL_C_TYPE_DATE:
4472 #endif
4473 		case SQL_C_DATE:
4474 		    size = sizeof (DATE_STRUCT);
4475 		    break;
4476 #ifdef SQL_C_TYPE_DATE
4477 		case SQL_C_TYPE_TIME:
4478 #endif
4479 		case SQL_C_TIME:
4480 		    size = sizeof (TIME_STRUCT);
4481 		    break;
4482 #ifdef SQL_C_TYPE_DATE
4483 		case SQL_C_TYPE_TIMESTAMP:
4484 #endif
4485 		case SQL_C_TIMESTAMP:
4486 		    size = sizeof (TIMESTAMP_STRUCT);
4487 		    break;
4488 		}
4489 		freep(&p->parbuf);
4490 		p->parbuf = xmalloc(size);
4491 		if (!p->parbuf) {
4492 		    return nomem(s);
4493 		}
4494 		p->param = p->parbuf;
4495 		memcpy(p->param, data, size);
4496 		p->len = size;
4497 		p->need = -1;
4498 	    } else if (len == SQL_NTS && (
4499 		       type == SQL_C_CHAR
4500 #ifdef WCHARSUPPORT
4501 		       || type == SQL_C_WCHAR
4502 #endif
4503 		      )) {
4504 		char *dp = data;
4505 
4506 #ifdef WCHARSUPPORT
4507 		if (type == SQL_C_WCHAR) {
4508 		    dp = uc_to_utf(data, len);
4509 		    if (!dp) {
4510 			return nomem(s);
4511 		    }
4512 		}
4513 #endif
4514 #if defined(_WIN32) || defined(_WIN64)
4515 		if (*s->oemcp) {
4516 		    dp = wmb_to_utf(data, strlen (data));
4517 		    if (!dp) {
4518 			return nomem(s);
4519 		    }
4520 		}
4521 #endif
4522 		dlen = strlen(dp);
4523 		freep(&p->parbuf);
4524 		p->parbuf = xmalloc(dlen + 1);
4525 		if (!p->parbuf) {
4526 		    if (dp != data) {
4527 			uc_free(dp);
4528 		    }
4529 		    return nomem(s);
4530 		}
4531 		p->param = p->parbuf;
4532 		strcpy(p->param, dp);
4533 		if (dp != data) {
4534 		    uc_free(dp);
4535 		}
4536 		p->len = dlen;
4537 		p->need = -1;
4538 	    } else if (len < 0) {
4539 		setstat(s, -1, "invalid length", "HY090");
4540 		return SQL_ERROR;
4541 	    } else {
4542 		dlen = min(p->len - p->offs, len);
4543 		if (!p->param) {
4544 		    setstat(s, -1, "no memory for parameter", "HY013");
4545 		    return SQL_ERROR;
4546 		}
4547 		memcpy((char *) p->param + p->offs, data, dlen);
4548 		p->offs += dlen;
4549 		if (p->offs >= p->len) {
4550 #ifdef WCHARSUPPORT
4551 		    if (type == SQL_C_WCHAR) {
4552 			char *dp = uc_to_utf(p->param, p->len);
4553 			char *np;
4554 			int nlen;
4555 
4556 			if (!dp) {
4557 			    return nomem(s);
4558 			}
4559 			nlen = strlen(dp);
4560 			np = xmalloc(nlen + 1);
4561 			if (!np) {
4562 			    uc_free(dp);
4563 			    return nomem(s);
4564 			}
4565 			strcpy(np, dp);
4566 			uc_free(dp);
4567 			if (p->param == p->parbuf) {
4568 			    freep(&p->parbuf);
4569 			}
4570 			p->parbuf = p->param = np;
4571 			p->len = nlen;
4572 		    } else {
4573 			*((char *) p->param + p->len) = '\0';
4574 		    }
4575 		    p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR)
4576 			    ? -1 : 0;
4577 #else
4578 		    *((char *) p->param + p->len) = '\0';
4579 		    p->need = (type == SQL_C_CHAR) ? -1 : 0;
4580 #endif
4581 #if defined(_WIN32) || defined(_WIN64)
4582 		    if (type == SQL_C_CHAR && *s->oemcp &&
4583 			!(p->stype == SQL_BINARY ||
4584 			  p->stype == SQL_VARBINARY ||
4585 			  p->stype == SQL_LONGVARBINARY)) {
4586 			char *dp = wmb_to_utf(p->param, p->len);
4587 
4588 			if (!dp) {
4589 			    return nomem(s);
4590 			}
4591 			if (p->param == p->parbuf) {
4592 			    freep(&p->parbuf);
4593 			}
4594 			p->parbuf = p->param = dp;
4595 			p->len = strlen(dp);
4596 		    }
4597 		    if (p->type == SQL_C_WCHAR &&
4598 			(p->stype == SQL_VARCHAR ||
4599 			 p->stype == SQL_LONGVARCHAR) &&
4600 			 p->len == p->coldef * sizeof (SQLWCHAR)) {
4601 			/* fix for MS-Access */
4602 			p->len = p->coldef;
4603 		    }
4604 #endif
4605 		}
4606 	    }
4607 	    done = 1;
4608 	    break;
4609 	}
4610     }
4611     if (!done) {
4612 	goto seqerr;
4613     }
4614     return SQL_SUCCESS;
4615 }
4616 
4617 /**
4618  * Put (partial) parameter data into executing statement.
4619  * @param stmt statement handle
4620  * @param data pointer to data
4621  * @param len length of data
4622  * @result ODBC error code
4623  */
4624 
4625 SQLRETURN SQL_API
SQLPutData(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)4626 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
4627 {
4628     SQLRETURN ret;
4629 
4630     HSTMT_LOCK(stmt);
4631     ret = drvputdata(stmt, data, len);
4632     HSTMT_UNLOCK(stmt);
4633     return ret;
4634 }
4635 
4636 /**
4637  * Clear out parameter bindings, if any.
4638  * @param s statement pointer
4639  */
4640 
4641 static SQLRETURN
freeparams(STMT * s)4642 freeparams(STMT *s)
4643 {
4644     if (s->bindparms) {
4645 	int n;
4646 
4647 	for (n = 0; n < s->nbindparms; n++) {
4648 	    freep(&s->bindparms[n].parbuf);
4649 	    memset(&s->bindparms[n], 0, sizeof (BINDPARM));
4650 	}
4651     }
4652     return SQL_SUCCESS;
4653 }
4654 
4655 /**
4656  * Setup sqlite4 parameter for statement parameter.
4657  * @param s statement pointer
4658  * @param sql sql string
4659  * @param pnum parameter number
4660  * @result ODBC error code
4661  *
4662  * The parameter is converted within BINDPARM in order to
4663  * be presented to sqlite4_bind_*() functions.
4664  */
4665 
4666 static SQLRETURN
setupparam(STMT * s,char * sql,int pnum)4667 setupparam(STMT *s, char *sql, int pnum)
4668 {
4669     int type, len = 0, needalloc = 0;
4670     BINDPARM *p;
4671 
4672     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
4673 	goto error;
4674     }
4675     p = &s->bindparms[pnum];
4676     type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
4677 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
4678     /* MS Access hack part 4 (map SQL_C_DEFAULT to SQL_C_CHAR) */
4679     if (type == SQL_C_WCHAR && p->type == SQL_C_DEFAULT) {
4680 	type = SQL_C_CHAR;
4681     }
4682 #endif
4683     if (p->need > 0) {
4684 	return setupparbuf(s, p);
4685     }
4686     p->strbuf[0] = '\0';
4687     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
4688 	p->s4type = SQLITE4_NULL;
4689 	p->s4size = 0;
4690 	return SQL_SUCCESS;
4691     }
4692     if (type == SQL_C_CHAR &&
4693 	(p->stype == SQL_BINARY ||
4694 	 p->stype == SQL_VARBINARY ||
4695 	 p->stype == SQL_LONGVARBINARY)) {
4696 	type = SQL_C_BINARY;
4697     }
4698     switch (type) {
4699     case SQL_C_BINARY:
4700 	p->s4type = SQLITE4_BLOB;
4701 	p->s4size = p->len;
4702 	p->s4val = p->param;
4703 	if (p->need < 0) {
4704 	    break;
4705 	}
4706 	if (!p->lenp) {
4707 	    len = p->len;
4708 	} else if (*p->lenp == SQL_DATA_AT_EXEC) {
4709 	    len = p->len;
4710 	} else {
4711 	    len = *p->lenp;
4712 	    if (len <= SQL_LEN_DATA_AT_EXEC_OFFSET) {
4713 		len = SQL_LEN_DATA_AT_EXEC(len);
4714 	    }
4715 	}
4716 	if (len < 0) {
4717 	    setstat(s, -1, "invalid length", "HY009");
4718 	    return SQL_ERROR;
4719 	}
4720 	p->len = len;
4721 	p->max = p->len;
4722 	p->need = -1;
4723 	p->s4size = len;
4724 	break;
4725 #ifdef WCHARSUPPORT
4726     case SQL_C_WCHAR:
4727 #endif
4728     case SQL_C_CHAR:
4729 	p->s4type = SQLITE4_TEXT;
4730 	p->s4size = -1;
4731 	p->s4val = p->param;
4732 	if (!p->parbuf) {
4733 #ifdef WCHARSUPPORT
4734 	    if (type == SQL_C_WCHAR) {
4735 		if (!p->lenp || *p->lenp == SQL_NTS) {
4736 		    p->max = uc_strlen(p->param) * sizeof (SQLWCHAR);
4737 		} else if (*p->lenp >= 0) {
4738 		    p->max = *p->lenp;
4739 		}
4740 	    } else
4741 #endif
4742 	    if (type == SQL_C_CHAR) {
4743 		if (!p->lenp || *p->lenp == SQL_NTS) {
4744 		    p->len = p->max = strlen(p->param);
4745 #if defined(_WIN32) || defined(_WIN64)
4746 		    needalloc = 1;
4747 #endif
4748 		} else if (*p->lenp >= 0) {
4749 		    p->len = p->max = *p->lenp;
4750 		    needalloc = 1;
4751 		}
4752 	    }
4753 	}
4754 	if (p->need < 0 && p->parbuf == p->param) {
4755 	    break;
4756 	}
4757 #ifdef WCHARSUPPORT
4758 	if (type == SQL_C_WCHAR) {
4759 	    char *dp = uc_to_utf(p->param, p->max);
4760 
4761 	    if (!dp) {
4762 		return nomem(s);
4763 	    }
4764 	    if (p->param == p->parbuf) {
4765 		freep(&p->parbuf);
4766 	    }
4767 	    p->parbuf = p->param = dp;
4768 	    p->need = -1;
4769 	    p->len = strlen(p->param);
4770 	    p->s4val = p->param;
4771 	    p->s4size = p->len;
4772 	} else
4773 #endif
4774 	if (type == SQL_C_CHAR) {
4775 	    p->s4val = p->param;
4776 	    if (needalloc) {
4777 		char *dp;
4778 
4779 #if defined(_WIN32) || defined(_WIN64)
4780 		if (*s->oemcp) {
4781 		    dp = wmb_to_utf(p->param, p->len);
4782 		} else {
4783 		    dp = xmalloc(p->len + 1);
4784 		}
4785 #else
4786 		dp = xmalloc(p->len + 1);
4787 #endif
4788 		if (!dp) {
4789 		    return nomem(s);
4790 		}
4791 #if defined(_WIN32) || defined(_WIN64)
4792 		if (*s->oemcp) {
4793 		    p->len = strlen(dp);
4794 		} else {
4795 		    memcpy(dp, p->param, p->len);
4796 		    dp[p->len] = '\0';
4797 		}
4798 #else
4799 		memcpy(dp, p->param, p->len);
4800 		dp[p->len] = '\0';
4801 #endif
4802 		if (p->param == p->parbuf) {
4803 		    freep(&p->parbuf);
4804 		}
4805 		p->parbuf = p->param = dp;
4806 		p->need = -1;
4807 		p->s4val = p->param;
4808 		p->s4size = p->len;
4809 	    }
4810 	}
4811 	break;
4812     case SQL_C_UTINYINT:
4813     case SQL_C_TINYINT:
4814     case SQL_C_STINYINT:
4815 	p->s4type = SQLITE4_INTEGER;
4816 	p->s4size = sizeof (int);
4817 	p->s4ival = *((SQLCHAR *) p->param);
4818 	break;
4819     case SQL_C_USHORT:
4820 	p->s4type = SQLITE4_INTEGER;
4821 	p->s4size = sizeof (int);
4822 	p->s4ival = *((SQLUSMALLINT *) p->param);
4823 	break;
4824     case SQL_C_SHORT:
4825     case SQL_C_SSHORT:
4826 	p->s4type = SQLITE4_INTEGER;
4827 	p->s4size = sizeof (int);
4828 	p->s4ival = *((SQLSMALLINT *) p->param);
4829 	break;
4830     case SQL_C_ULONG:
4831 	p->s4type = SQLITE4_INTEGER;
4832 	p->s4size = sizeof (int);
4833 	p->s4ival = *((SQLUINTEGER *) p->param);
4834 	break;
4835     case SQL_C_LONG:
4836     case SQL_C_SLONG:
4837 	p->s4type = SQLITE4_INTEGER;
4838 	p->s4size = sizeof (int);
4839 	p->s4ival = *((SQLINTEGER *) p->param);
4840 	break;
4841 #ifdef SQL_BIT
4842     case SQL_C_BIT:
4843 	p->s4type = SQLITE4_INTEGER;
4844 	p->s4size = sizeof (int);
4845 	p->s4ival = (*((SQLCHAR *) p->param)) ? 1 : 0;
4846 	break;
4847 #endif
4848 #ifdef SQL_BIGINT
4849     case SQL_C_SBIGINT:
4850 	p->s4type = SQLITE4_INTEGER;
4851 	p->s4size = sizeof (sqlite4_int64);
4852 	p->s4lival = *((sqlite4_int64 *) p->param);
4853 	break;
4854     case SQL_C_UBIGINT:
4855 	p->s4type = SQLITE4_INTEGER;
4856 	p->s4size = sizeof (sqlite4_int64);
4857 	p->s4lival = *((sqlite4_uint64 *) p->param);
4858 	break;
4859 #endif
4860     case SQL_C_FLOAT:
4861 	p->s4type = SQLITE4_FLOAT;
4862 	p->s4size = sizeof (double);
4863 	p->s4dval = *((float *) p->param);
4864 	break;
4865     case SQL_C_DOUBLE:
4866 	p->s4type = SQLITE4_FLOAT;
4867 	p->s4size = sizeof (double);
4868 	p->s4dval = *((double *) p->param);
4869 	break;
4870 #ifdef SQL_C_TYPE_DATE
4871     case SQL_C_TYPE_DATE:
4872 #endif
4873     case SQL_C_DATE:
4874 	sprintf(p->strbuf, "%04d-%02d-%02d",
4875 		((DATE_STRUCT *) p->param)->year,
4876 		((DATE_STRUCT *) p->param)->month,
4877 		((DATE_STRUCT *) p->param)->day);
4878 	p->s4type = SQLITE4_TEXT;
4879 	p->s4size = -1;
4880 	p->s4val = p->strbuf;
4881 	break;
4882 #ifdef SQL_C_TYPE_TIME
4883     case SQL_C_TYPE_TIME:
4884 #endif
4885     case SQL_C_TIME:
4886 	sprintf(p->strbuf, "%02d:%02d:%02d",
4887 		((TIME_STRUCT *) p->param)->hour,
4888 		((TIME_STRUCT *) p->param)->minute,
4889 		((TIME_STRUCT *) p->param)->second);
4890 	p->s4type = SQLITE4_TEXT;
4891 	p->s4size = -1;
4892 	p->s4val = p->strbuf;
4893 	break;
4894 #ifdef SQL_C_TYPE_TIMESTAMP
4895     case SQL_C_TYPE_TIMESTAMP:
4896 #endif
4897     case SQL_C_TIMESTAMP:
4898 	len = (int) ((TIMESTAMP_STRUCT *) p->param)->fraction;
4899 	len /= 1000000;
4900 	len = len % 1000;
4901 	if (len < 0) {
4902 	    len = 0;
4903 	}
4904 	if (p->coldef && p->coldef <= 16) {
4905 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
4906 		    ((TIMESTAMP_STRUCT *) p->param)->year,
4907 		    ((TIMESTAMP_STRUCT *) p->param)->month,
4908 		    ((TIMESTAMP_STRUCT *) p->param)->day,
4909 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
4910 		    ((TIMESTAMP_STRUCT *) p->param)->minute);
4911 	} else if (p->coldef && p->coldef <= 19) {
4912 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
4913 		    ((TIMESTAMP_STRUCT *) p->param)->year,
4914 		    ((TIMESTAMP_STRUCT *) p->param)->month,
4915 		    ((TIMESTAMP_STRUCT *) p->param)->day,
4916 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
4917 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
4918 		    ((TIMESTAMP_STRUCT *) p->param)->second);
4919 	} else {
4920 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
4921 		    ((TIMESTAMP_STRUCT *) p->param)->year,
4922 		    ((TIMESTAMP_STRUCT *) p->param)->month,
4923 		    ((TIMESTAMP_STRUCT *) p->param)->day,
4924 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
4925 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
4926 		    ((TIMESTAMP_STRUCT *) p->param)->second,
4927 		    len);
4928 	}
4929 	p->s4type = SQLITE4_TEXT;
4930 	p->s4size = -1;
4931 	p->s4val = p->strbuf;
4932 	break;
4933     default:
4934     error:
4935 	setstat(s, -1, "unsupported parameter type",
4936 		(*s->ov3) ? "07009" : "S1093");
4937 	return SQL_ERROR;
4938     }
4939     return SQL_SUCCESS;
4940 }
4941 
4942 /**
4943  * Internal bind parameter on HSTMT.
4944  * @param stmt statement handle
4945  * @param pnum parameter number, starting at 1
4946  * @param iotype input/output type of parameter
4947  * @param buftype type of host variable
4948  * @param ptype
4949  * @param coldef
4950  * @param scale
4951  * @param data pointer to host variable
4952  * @param buflen length of host variable
4953  * @param len output length pointer
4954  * @result ODBC error code
4955  */
4956 
4957 static SQLRETURN
drvbindparam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLUINTEGER coldef,SQLSMALLINT scale,SQLPOINTER data,SQLINTEGER buflen,SQLLEN * len)4958 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
4959 	     SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
4960 	     SQLSMALLINT scale,
4961 	     SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
4962 {
4963     STMT *s;
4964     BINDPARM *p;
4965 
4966     if (stmt == SQL_NULL_HSTMT) {
4967 	return SQL_INVALID_HANDLE;
4968     }
4969     s = (STMT *) stmt;
4970     if (pnum == 0) {
4971 	setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
4972 	return SQL_ERROR;
4973     }
4974     if (!data && !len) {
4975 	setstat(s, -1, "invalid buffer", "HY003");
4976 	return SQL_ERROR;
4977     }
4978     --pnum;
4979     if (s->bindparms) {
4980 	if (pnum >= s->nbindparms) {
4981 	    BINDPARM *newparms;
4982 
4983 	    newparms = xrealloc(s->bindparms,
4984 				(pnum + 1) * sizeof (BINDPARM));
4985 	    if (!newparms) {
4986 outofmem:
4987 		return nomem(s);
4988 	    }
4989 	    s->bindparms = newparms;
4990 	    memset(&s->bindparms[s->nbindparms], 0,
4991 		   (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
4992 	    s->nbindparms = pnum + 1;
4993 	}
4994     } else {
4995 	int npar = max(10, pnum + 1);
4996 
4997 	s->bindparms = xmalloc(npar * sizeof (BINDPARM));
4998 	if (!s->bindparms) {
4999 	    goto outofmem;
5000 	}
5001 	memset(s->bindparms, 0, npar * sizeof (BINDPARM));
5002 	s->nbindparms = npar;
5003     }
5004     switch (buftype) {
5005     case SQL_C_STINYINT:
5006     case SQL_C_UTINYINT:
5007     case SQL_C_TINYINT:
5008 #ifdef SQL_C_BIT
5009     case SQL_C_BIT:
5010 #endif
5011 	buflen = sizeof (SQLCHAR);
5012 	break;
5013     case SQL_C_SHORT:
5014     case SQL_C_USHORT:
5015     case SQL_C_SSHORT:
5016 	buflen = sizeof (SQLSMALLINT);
5017 	break;
5018     case SQL_C_SLONG:
5019     case SQL_C_ULONG:
5020     case SQL_C_LONG:
5021 	buflen = sizeof (SQLINTEGER);
5022 	break;
5023     case SQL_C_FLOAT:
5024 	buflen = sizeof (float);
5025 	break;
5026     case SQL_C_DOUBLE:
5027 	buflen = sizeof (double);
5028 	break;
5029     case SQL_C_TIMESTAMP:
5030 #ifdef SQL_C_TYPE_TIMESTAMP
5031     case SQL_C_TYPE_TIMESTAMP:
5032 #endif
5033 	buflen = sizeof (TIMESTAMP_STRUCT);
5034 	break;
5035     case SQL_C_TIME:
5036 #ifdef SQL_C_TYPE_TIME
5037     case SQL_C_TYPE_TIME:
5038 #endif
5039 	buflen = sizeof (TIME_STRUCT);
5040 	break;
5041     case SQL_C_DATE:
5042 #ifdef SQL_C_TYPE_DATE
5043     case SQL_C_TYPE_DATE:
5044 #endif
5045 	buflen = sizeof (DATE_STRUCT);
5046 	break;
5047 #ifdef SQL_C_UBIGINT
5048     case SQL_C_UBIGINT:
5049 	buflen = sizeof (SQLBIGINT);
5050 	break;
5051 #endif
5052 #ifdef SQL_C_SBIGINT
5053     case SQL_C_SBIGINT:
5054 	buflen = sizeof (SQLBIGINT);
5055 	break;
5056 #endif
5057 #ifdef SQL_C_BIGINT
5058     case SQL_C_BIGINT:
5059 	buflen = sizeof (SQLBIGINT);
5060 	break;
5061 #endif
5062     }
5063     p = &s->bindparms[pnum];
5064     p->type = buftype;
5065     p->stype = ptype;
5066     p->coldef = coldef;
5067     p->scale = scale;
5068     p->max = buflen;
5069     p->inc = buflen;
5070     p->lenp = p->lenp0 = len;
5071     p->offs = 0;
5072     p->len = 0;
5073     p->param0 = data;
5074     freep(&p->parbuf);
5075     p->param = p->param0;
5076     p->bound = 1;
5077     p->need = 0;
5078     return SQL_SUCCESS;
5079 }
5080 
5081 /**
5082  * Bind parameter on HSTMT.
5083  * @param stmt statement handle
5084  * @param pnum parameter number, starting at 1
5085  * @param iotype input/output type of parameter
5086  * @param buftype type of host variable
5087  * @param ptype
5088  * @param coldef
5089  * @param scale
5090  * @param data pointer to host variable
5091  * @param buflen length of host variable
5092  * @param len output length pointer
5093  * @result ODBC error code
5094  */
5095 
5096 SQLRETURN SQL_API
SQLBindParameter(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER data,SQLLEN buflen,SQLLEN * len)5097 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
5098 		 SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
5099 		 SQLSMALLINT scale,
5100 		 SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
5101 {
5102     SQLRETURN ret;
5103 
5104     HSTMT_LOCK(stmt);
5105     ret = drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
5106 		       scale, data, buflen, len);
5107     HSTMT_UNLOCK(stmt);
5108     return ret;
5109 }
5110 
5111 #ifndef HAVE_IODBC
5112 /**
5113  * Bind parameter on HSTMT.
5114  * @param stmt statement handle
5115  * @param pnum parameter number, starting at 1
5116  * @param vtype input/output type of parameter
5117  * @param ptype
5118  * @param lenprec
5119  * @param scale
5120  * @param val pointer to host variable
5121  * @param lenp output length pointer
5122  * @result ODBC error code
5123  */
5124 
5125 SQLRETURN SQL_API
SQLBindParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT vtype,SQLSMALLINT ptype,SQLULEN lenprec,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * lenp)5126 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
5127 	     SQLSMALLINT ptype, SQLULEN lenprec,
5128 	     SQLSMALLINT scale, SQLPOINTER val,
5129 	     SQLLEN *lenp)
5130 {
5131     SQLRETURN ret;
5132 
5133     HSTMT_LOCK(stmt);
5134     ret = drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
5135 		       lenprec, scale, val, 0, lenp);
5136     HSTMT_UNLOCK(stmt);
5137     return ret;
5138 }
5139 #endif
5140 
5141 /**
5142  * Return number of parameters.
5143  * @param stmt statement handle
5144  * @param nparam output parameter count
5145  * @result ODBC error code
5146  */
5147 
5148 SQLRETURN SQL_API
SQLNumParams(SQLHSTMT stmt,SQLSMALLINT * nparam)5149 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
5150 {
5151     STMT *s;
5152     SQLSMALLINT dummy;
5153 
5154     HSTMT_LOCK(stmt);
5155     if (stmt == SQL_NULL_HSTMT) {
5156 	return SQL_INVALID_HANDLE;
5157     }
5158     s = (STMT *) stmt;
5159     if (!nparam) {
5160 	nparam = &dummy;
5161     }
5162     *nparam = s->nparams;
5163     HSTMT_UNLOCK(stmt);
5164     return SQL_SUCCESS;
5165 }
5166 
5167 /**
5168  * Setup parameter buffer for deferred parameter.
5169  * @param s pointer to STMT
5170  * @param p pointer to BINDPARM
5171  * @result ODBC error code (success indicated by SQL_NEED_DATA)
5172  */
5173 
5174 static SQLRETURN
setupparbuf(STMT * s,BINDPARM * p)5175 setupparbuf(STMT *s, BINDPARM *p)
5176 {
5177     if (!p->parbuf) {
5178 	if (*p->lenp == SQL_DATA_AT_EXEC) {
5179 	    p->len = p->max;
5180 	} else {
5181 	    p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
5182 	}
5183 	if (p->len < 0 && p->len != SQL_NTS &&
5184 	    p->len != SQL_NULL_DATA) {
5185 	    setstat(s, -1, "invalid length", "HY009");
5186 	    return SQL_ERROR;
5187 	}
5188 	if (p->len >= 0) {
5189 	    p->parbuf = xmalloc(p->len + 2);
5190 	    if (!p->parbuf) {
5191 		return nomem(s);
5192 	    }
5193 	    p->param = p->parbuf;
5194 	} else {
5195 	    p->param = NULL;
5196 	}
5197     }
5198     return SQL_NEED_DATA;
5199 }
5200 
5201 /**
5202  * Retrieve next parameter for sending data to executing query.
5203  * @param stmt statement handle
5204  * @param pind pointer to output parameter indicator
5205  * @result ODBC error code
5206  */
5207 
5208 SQLRETURN SQL_API
SQLParamData(SQLHSTMT stmt,SQLPOINTER * pind)5209 SQLParamData(SQLHSTMT stmt, SQLPOINTER *pind)
5210 {
5211     STMT *s;
5212     int i;
5213     SQLPOINTER dummy;
5214     SQLRETURN ret;
5215     BINDPARM *p;
5216 
5217     HSTMT_LOCK(stmt);
5218     if (stmt == SQL_NULL_HSTMT) {
5219 	return SQL_INVALID_HANDLE;
5220     }
5221     s = (STMT *) stmt;
5222     if (!pind) {
5223 	pind = &dummy;
5224     }
5225     if (s->pdcount < s->nparams) {
5226 	s->pdcount++;
5227     }
5228     for (i = 0; i < s->pdcount; i++) {
5229 	p = &s->bindparms[i];
5230 	if (p->need > 0) {
5231 	    int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
5232 
5233 	    p->need = (type == SQL_C_CHAR || type == SQL_C_WCHAR) ? -1 : 0;
5234 	}
5235     }
5236     for (; i < s->nparams; i++) {
5237 	p = &s->bindparms[i];
5238 	if (p->need > 0) {
5239 	    *pind = (SQLPOINTER) p->param0;
5240 	    ret = setupparbuf(s, p);
5241 	    s->pdcount = i;
5242 	    goto done;
5243 	}
5244     }
5245     ret = drvexecute(stmt, 0);
5246 done:
5247     HSTMT_UNLOCK(stmt);
5248     return ret;
5249 }
5250 
5251 /**
5252  * Return information about parameter.
5253  * @param stmt statement handle
5254  * @param pnum parameter number, starting at 1
5255  * @param dtype output type indicator
5256  * @param size output size indicator
5257  * @param decdigits output number of digits
5258  * @param nullable output NULL allowed indicator
5259  * @result ODBC error code
5260  */
5261 
5262 SQLRETURN SQL_API
SQLDescribeParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT * dtype,SQLULEN * size,SQLSMALLINT * decdigits,SQLSMALLINT * nullable)5263 SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT *dtype,
5264 		 SQLULEN *size, SQLSMALLINT *decdigits, SQLSMALLINT *nullable)
5265 {
5266     STMT *s;
5267     SQLRETURN ret = SQL_ERROR;
5268 
5269     HSTMT_LOCK(stmt);
5270     if (stmt == SQL_NULL_HSTMT) {
5271 	return SQL_INVALID_HANDLE;
5272     }
5273     s = (STMT *) stmt;
5274     --pnum;
5275     if (pnum >= s->nparams) {
5276 	setstat(s, -1, "invalid parameter index",
5277 		(*s->ov3) ? "HY000" : "S1000");
5278 	goto done;
5279     }
5280     if (dtype) {
5281 #ifdef SQL_LONGVARCHAR
5282 #ifdef WINTERFACE
5283 	*dtype = s->nowchar[0] ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
5284 #else
5285 	*dtype = SQL_LONGVARCHAR;
5286 #endif
5287 #else
5288 #ifdef WINTERFACE
5289 	*dtype = s->nowchar[0] ? SQL_VARCHAR : SQL_WVARCHAR;
5290 #else
5291 	*dtype = SQL_VARCHAR;
5292 #endif
5293 #endif
5294     }
5295     if (size) {
5296 #ifdef SQL_LONGVARCHAR
5297 	*size = 65536;
5298 #else
5299 	*size = 255;
5300 #endif
5301     }
5302     if (decdigits) {
5303 	*decdigits = 0;
5304     }
5305     if (nullable) {
5306 	*nullable = SQL_NULLABLE;
5307     }
5308     ret = SQL_SUCCESS;
5309 done:
5310     HSTMT_UNLOCK(stmt);
5311     return ret;
5312 }
5313 
5314 /**
5315  * Set information on parameter.
5316  * @param stmt statement handle
5317  * @param par parameter number, starting at 1
5318  * @param type type of host variable
5319  * @param sqltype
5320  * @param coldef
5321  * @param scale
5322  * @param val pointer to host variable
5323  * @param nval output length pointer
5324  * @result ODBC error code
5325  */
5326 
5327 SQLRETURN SQL_API
SQLSetParam(SQLHSTMT stmt,SQLUSMALLINT par,SQLSMALLINT type,SQLSMALLINT sqltype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * nval)5328 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
5329 	    SQLSMALLINT sqltype, SQLULEN coldef,
5330 	    SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
5331 {
5332     SQLRETURN ret;
5333 
5334     HSTMT_LOCK(stmt);
5335     ret = drvbindparam(stmt, par, SQL_PARAM_INPUT,
5336 		       type, sqltype, coldef, scale, val,
5337 		       SQL_SETPARAM_VALUE_MAX, nval);
5338     HSTMT_UNLOCK(stmt);
5339     return ret;
5340 }
5341 
5342 /**
5343  * Function not implemented.
5344  */
5345 
5346 SQLRETURN SQL_API
SQLParamOptions(SQLHSTMT stmt,SQLULEN rows,SQLULEN * rowp)5347 SQLParamOptions(SQLHSTMT stmt, SQLULEN rows, SQLULEN *rowp)
5348 {
5349     SQLRETURN ret;
5350 
5351     HSTMT_LOCK(stmt);
5352     ret = drvunimplstmt(stmt);
5353     HSTMT_UNLOCK(stmt);
5354     return ret;
5355 }
5356 
5357 #ifndef WINTERFACE
5358 /**
5359  * Function not implemented.
5360  */
5361 
5362 SQLRETURN SQL_API
SQLGetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)5363 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
5364 		SQLSMALLINT fieldid, SQLPOINTER value,
5365 		SQLINTEGER buflen, SQLINTEGER *strlen)
5366 {
5367     return SQL_ERROR;
5368 }
5369 #endif
5370 
5371 #ifdef WINTERFACE
5372 /**
5373  * Function not implemented.
5374  */
5375 
5376 SQLRETURN SQL_API
SQLGetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)5377 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
5378 		 SQLSMALLINT fieldid, SQLPOINTER value,
5379 		 SQLINTEGER buflen, SQLINTEGER *strlen)
5380 {
5381     return SQL_ERROR;
5382 }
5383 #endif
5384 
5385 #ifndef WINTERFACE
5386 /**
5387  * Function not implemented.
5388  */
5389 
5390 SQLRETURN SQL_API
SQLSetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)5391 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
5392 		SQLSMALLINT fieldid, SQLPOINTER value,
5393 		SQLINTEGER buflen)
5394 {
5395     return SQL_ERROR;
5396 }
5397 #endif
5398 
5399 #ifdef WINTERFACE
5400 /**
5401  * Function not implemented.
5402  */
5403 
5404 SQLRETURN SQL_API
SQLSetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)5405 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
5406 		 SQLSMALLINT fieldid, SQLPOINTER value,
5407 		 SQLINTEGER buflen)
5408 {
5409     return SQL_ERROR;
5410 }
5411 #endif
5412 
5413 #ifndef WINTERFACE
5414 /**
5415  * Function not implemented.
5416  */
5417 
5418 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)5419 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
5420 	      SQLCHAR *name, SQLSMALLINT buflen,
5421 	      SQLSMALLINT *strlen, SQLSMALLINT *type,
5422 	      SQLSMALLINT *subtype, SQLLEN *len,
5423 	      SQLSMALLINT *prec, SQLSMALLINT *scale,
5424 	      SQLSMALLINT *nullable)
5425 {
5426     return SQL_ERROR;
5427 }
5428 #endif
5429 
5430 #ifdef WINTERFACE
5431 /**
5432  * Function not implemented.
5433  */
5434 
5435 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)5436 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
5437 	       SQLWCHAR *name, SQLSMALLINT buflen,
5438 	       SQLSMALLINT *strlen, SQLSMALLINT *type,
5439 	       SQLSMALLINT *subtype, SQLLEN *len,
5440 	       SQLSMALLINT *prec, SQLSMALLINT *scale,
5441 	       SQLSMALLINT *nullable)
5442 {
5443     return SQL_ERROR;
5444 }
5445 #endif
5446 
5447 /**
5448  * Function not implemented.
5449  */
5450 
5451 SQLRETURN SQL_API
SQLSetDescRec(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT type,SQLSMALLINT subtype,SQLLEN len,SQLSMALLINT prec,SQLSMALLINT scale,SQLPOINTER data,SQLLEN * strlen,SQLLEN * indicator)5452 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
5453 	      SQLSMALLINT type, SQLSMALLINT subtype,
5454 	      SQLLEN len, SQLSMALLINT prec,
5455 	      SQLSMALLINT scale, SQLPOINTER data,
5456 	      SQLLEN *strlen, SQLLEN *indicator)
5457 {
5458     return SQL_ERROR;
5459 }
5460 
5461 /**
5462  * Setup empty result set from constant column specification.
5463  * @param stmt statement handle
5464  * @param colspec column specification array (default, ODBC2)
5465  * @param ncols number of columns (default, ODBC2)
5466  * @param colspec3 column specification array (ODBC3)
5467  * @param ncols4 number of columns (ODBC3)
5468  * @param nret returns number of columns
5469  * @result ODBC error code
5470  */
5471 
5472 static SQLRETURN
mkresultset(HSTMT stmt,COL * colspec,int ncols,COL * colspec3,int ncols4,int * nret)5473 mkresultset(HSTMT stmt, COL *colspec, int ncols, COL *colspec3,
5474 	    int ncols4, int *nret)
5475 {
5476     STMT *s;
5477     DBC *d;
5478 
5479     if (stmt == SQL_NULL_HSTMT) {
5480 	return SQL_INVALID_HANDLE;
5481     }
5482     s = (STMT *) stmt;
5483     if (s->dbc == SQL_NULL_HDBC) {
5484 noconn:
5485 	return noconn(s);
5486     }
5487     d = (DBC *) s->dbc;
5488     if (!d->sqlite) {
5489 	goto noconn;
5490     }
5491     s4stmt_end_if(s);
5492     freeresult(s, 0);
5493     if (colspec3 && *s->ov3) {
5494 	s->ncols = ncols4;
5495 	s->cols = colspec3;
5496     } else {
5497 	s->ncols = ncols;
5498 	s->cols = colspec;
5499     }
5500     mkbindcols(s, s->ncols);
5501     s->nowchar[1] = 1;
5502     s->nrows = 0;
5503     s->rowp = s->rowprs = -1;
5504     s->isselect = -1;
5505     if (nret) {
5506 	*nret = s->ncols;
5507     }
5508     return SQL_SUCCESS;
5509 }
5510 
5511 /**
5512  * Columns for result set of SQLTablePrivileges().
5513  */
5514 
5515 static COL tablePrivSpec2[] = {
5516     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5517     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
5518     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5519     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5520     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5521     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
5522     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
5523 };
5524 
5525 static COL tablePrivSpec3[] = {
5526     { "SYSTEM", "TABLEPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
5527     { "SYSTEM", "TABLEPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
5528     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
5529     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
5530     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
5531     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
5532     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
5533 };
5534 
5535 /**
5536  * Retrieve privileges on tables and/or views.
5537  * @param stmt statement handle
5538  * @param cat catalog name/pattern or NULL
5539  * @param catLen length of catalog name/pattern or SQL_NTS
5540  * @param schema schema name/pattern or NULL
5541  * @param schemaLen length of schema name/pattern or SQL_NTS
5542  * @param table table name/pattern or NULL
5543  * @param tableLen length of table name/pattern or SQL_NTS
5544  * @result ODBC error code
5545  */
5546 
5547 static SQLRETURN
drvtableprivileges(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5548 drvtableprivileges(SQLHSTMT stmt,
5549 		   SQLCHAR *cat, SQLSMALLINT catLen,
5550 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
5551 		   SQLCHAR *table, SQLSMALLINT tableLen)
5552 {
5553     SQLRETURN ret;
5554     STMT *s;
5555     DBC *d;
5556     int ncols, rc, size, npatt;
5557     char *errp = NULL, *sql, tname[512];
5558 
5559     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
5560 		      tablePrivSpec3, array_size(tablePrivSpec3), NULL);
5561     if (ret != SQL_SUCCESS) {
5562 	return ret;
5563     }
5564     s = (STMT *) stmt;
5565     d = (DBC *) s->dbc;
5566     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
5567 	table = NULL;
5568 	goto doit;
5569     }
5570     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
5571 	schema[0] == '%') {
5572 	if ((!cat || catLen == 0 || !cat[0]) &&
5573 	    (!table || tableLen == 0 || !table[0])) {
5574 	    table = NULL;
5575 	    goto doit;
5576 	}
5577     }
5578 doit:
5579     if (!table) {
5580 	size = 1;
5581 	tname[0] = '%';
5582     } else {
5583 	if (tableLen == SQL_NTS) {
5584 	    size = sizeof (tname) - 1;
5585 	} else {
5586 	    size = min(sizeof (tname) - 1, tableLen);
5587 	}
5588 	strncpy(tname, (char *) table, size);
5589     }
5590     tname[size] = '\0';
5591     npatt = unescpat(tname);
5592 #if defined(_WIN32) || defined(_WIN64)
5593     if (npatt) {
5594 	sql = sqlite4_mprintf(0, "select %s as 'TABLE_QUALIFIER', "
5595 			      "%s as 'TABLE_OWNER', "
5596 			      "tbl_name as 'TABLE_NAME', "
5597 			      "'' as 'GRANTOR', "
5598 			      "'' as 'GRANTEE', "
5599 			      "'SELECT' AS 'PRIVILEGE', "
5600 			      "NULL as 'IS_GRANTABLE' "
5601 			      "from sqlite_master where "
5602 			      "(type = 'table' or type = 'view') "
5603 			      "and tbl_name like %Q "
5604 			      "UNION "
5605 			      "select %s as 'TABLE_QUALIFIER', "
5606 			      "%s as 'TABLE_OWNER', "
5607 			      "tbl_name as 'TABLE_NAME', "
5608 			      "'' as 'GRANTOR', "
5609 			      "'' as 'GRANTEE', "
5610 			      "'UPDATE' AS 'PRIVILEGE', "
5611 			      "NULL as 'IS_GRANTABLE' "
5612 			      "from sqlite_master where "
5613 			      "(type = 'table' or type = 'view') "
5614 			      "and tbl_name like %Q "
5615 			      "UNION "
5616 			      "select %s as 'TABLE_QUALIFIER', "
5617 			      "%s as 'TABLE_OWNER', "
5618 			      "tbl_name as 'TABLE_NAME', "
5619 			      "'' as 'GRANTOR', "
5620 			      "'' as 'GRANTEE', "
5621 			      "'DELETE' AS 'PRIVILEGE', "
5622 			      "NULL as 'IS_GRANTABLE' "
5623 			      "from sqlite_master where "
5624 			      "(type = 'table' or type = 'view') "
5625 			      "and tbl_name like %Q "
5626 			      "UNION "
5627 			      "select %s as 'TABLE_QUALIFIER', "
5628 			      "%s as 'TABLE_OWNER', "
5629 			      "tbl_name as 'TABLE_NAME', "
5630 			      "'' as 'GRANTOR', "
5631 			      "'' as 'GRANTEE', "
5632 			      "'INSERT' AS 'PRIVILEGE', "
5633 			      "NULL as 'IS_GRANTABLE' "
5634 			      "from sqlite_master where "
5635 			      "(type = 'table' or type = 'view') "
5636 			      "and tbl_name like %Q "
5637 			      "UNION "
5638 			      "select %s as 'TABLE_QUALIFIER', "
5639 			      "%s as 'TABLE_OWNER', "
5640 			      "tbl_name as 'TABLE_NAME', "
5641 			      "'' as 'GRANTOR', "
5642 			      "'' as 'GRANTEE', "
5643 			      "'REFERENCES' AS 'PRIVILEGE', "
5644 			      "NULL as 'IS_GRANTABLE' "
5645 			      "from sqlite_master where "
5646 			      "(type = 'table' or type = 'view') "
5647 			      "and tbl_name like %Q",
5648 			      d->xcelqrx ? "'main'" : "NULL",
5649 			      d->xcelqrx ? "''" : "NULL",
5650 			      tname,
5651 			      d->xcelqrx ? "'main'" : "NULL",
5652 			      d->xcelqrx ? "''" : "NULL",
5653 			      tname,
5654 			      d->xcelqrx ? "'main'" : "NULL",
5655 			      d->xcelqrx ? "''" : "NULL",
5656 			      tname,
5657 			      d->xcelqrx ? "'main'" : "NULL",
5658 			      d->xcelqrx ? "''" : "NULL",
5659 			      tname,
5660 			      d->xcelqrx ? "'main'" : "NULL",
5661 			      d->xcelqrx ? "''" : "NULL",
5662 			      tname);
5663     } else {
5664 	sql = sqlite4_mprintf(0, "select %s as 'TABLE_QUALIFIER', "
5665 			      "%s as 'TABLE_OWNER', "
5666 			      "tbl_name as 'TABLE_NAME', "
5667 			      "'' as 'GRANTOR', "
5668 			      "'' as 'GRANTEE', "
5669 			      "'SELECT' AS 'PRIVILEGE', "
5670 			      "NULL as 'IS_GRANTABLE' "
5671 			      "from sqlite_master where "
5672 			      "(type = 'table' or type = 'view') "
5673 			      "and lower(tbl_name) = lower(%Q) "
5674 			      "UNION "
5675 			      "select %s as 'TABLE_QUALIFIER', "
5676 			      "%s as 'TABLE_OWNER', "
5677 			      "tbl_name as 'TABLE_NAME', "
5678 			      "'' as 'GRANTOR', "
5679 			      "'' as 'GRANTEE', "
5680 			      "'UPDATE' AS 'PRIVILEGE', "
5681 			      "NULL as 'IS_GRANTABLE' "
5682 			      "from sqlite_master where "
5683 			      "(type = 'table' or type = 'view') "
5684 			      "and lower(tbl_name) = lower(%Q) "
5685 			      "UNION "
5686 			      "select %s as 'TABLE_QUALIFIER', "
5687 			      "%s as 'TABLE_OWNER', "
5688 			      "tbl_name as 'TABLE_NAME', "
5689 			      "'' as 'GRANTOR', "
5690 			      "'' as 'GRANTEE', "
5691 			      "'DELETE' AS 'PRIVILEGE', "
5692 			      "NULL as 'IS_GRANTABLE' "
5693 			      "from sqlite_master where "
5694 			      "(type = 'table' or type = 'view') "
5695 			      "and lower(tbl_name) = lower(%Q) "
5696 			      "UNION "
5697 			      "select %s as 'TABLE_QUALIFIER', "
5698 			      "%s as 'TABLE_OWNER', "
5699 			      "tbl_name as 'TABLE_NAME', "
5700 			      "'' as 'GRANTOR', "
5701 			      "'' as 'GRANTEE', "
5702 			      "'INSERT' AS 'PRIVILEGE', "
5703 			      "NULL as 'IS_GRANTABLE' "
5704 			      "from sqlite_master where "
5705 			      "(type = 'table' or type = 'view') "
5706 			      "and lower(tbl_name) = lower(%Q) "
5707 			      "UNION "
5708 			      "select %s as 'TABLE_QUALIFIER', "
5709 			      "%s as 'TABLE_OWNER', "
5710 			      "tbl_name as 'TABLE_NAME', "
5711 			      "'' as 'GRANTOR', "
5712 			      "'' as 'GRANTEE', "
5713 			      "'REFERENCES' AS 'PRIVILEGE', "
5714 			      "NULL as 'IS_GRANTABLE' "
5715 			      "from sqlite_master where "
5716 			      "(type = 'table' or type = 'view') "
5717 			      "and lower(tbl_name) = lower(%Q)",
5718 			      d->xcelqrx ? "'main'" : "NULL",
5719 			      d->xcelqrx ? "''" : "NULL",
5720 			      tname,
5721 			      d->xcelqrx ? "'main'" : "NULL",
5722 			      d->xcelqrx ? "''" : "NULL",
5723 			      tname,
5724 			      d->xcelqrx ? "'main'" : "NULL",
5725 			      d->xcelqrx ? "''" : "NULL",
5726 			      tname,
5727 			      d->xcelqrx ? "'main'" : "NULL",
5728 			      d->xcelqrx ? "''" : "NULL",
5729 			      tname,
5730 			      d->xcelqrx ? "'main'" : "NULL",
5731 			      d->xcelqrx ? "''" : "NULL",
5732 			      tname);
5733     }
5734 #else
5735     if (npatt) {
5736 	sql = sqlite4_mprintf(0, "select NULL as 'TABLE_QUALIFIER', "
5737 			      "NULL as 'TABLE_OWNER', "
5738 			      "tbl_name as 'TABLE_NAME', "
5739 			      "'' as 'GRANTOR', "
5740 			      "'' as 'GRANTEE', "
5741 			      "'SELECT' AS 'PRIVILEGE', "
5742 			      "NULL as 'IS_GRANTABLE' "
5743 			      "from sqlite_master where "
5744 			      "(type = 'table' or type = 'view') "
5745 			      "and tbl_name like %Q "
5746 			      "UNION "
5747 			      "select NULL as 'TABLE_QUALIFIER', "
5748 			      "NULL as 'TABLE_OWNER', "
5749 			      "tbl_name as 'TABLE_NAME', "
5750 			      "'' as 'GRANTOR', "
5751 			      "'' as 'GRANTEE', "
5752 			      "'UPDATE' AS 'PRIVILEGE', "
5753 			      "NULL as 'IS_GRANTABLE' "
5754 			      "from sqlite_master where "
5755 			      "(type = 'table' or type = 'view') "
5756 			      "and tbl_name like %Q "
5757 			      "UNION "
5758 			      "select NULL as 'TABLE_QUALIFIER', "
5759 			      "NULL as 'TABLE_OWNER', "
5760 			      "tbl_name as 'TABLE_NAME', "
5761 			      "'' as 'GRANTOR', "
5762 			      "'' as 'GRANTEE', "
5763 			      "'DELETE' AS 'PRIVILEGE', "
5764 			      "NULL as 'IS_GRANTABLE' "
5765 			      "from sqlite_master where "
5766 			      "(type = 'table' or type = 'view') "
5767 			      "and tbl_name like %Q "
5768 			      "UNION "
5769 			      "select NULL as 'TABLE_QUALIFIER', "
5770 			      "NULL as 'TABLE_OWNER', "
5771 			      "tbl_name as 'TABLE_NAME', "
5772 			      "'' as 'GRANTOR', "
5773 			      "'' as 'GRANTEE', "
5774 			      "'INSERT' AS 'PRIVILEGE', "
5775 			      "NULL as 'IS_GRANTABLE' "
5776 			      "from sqlite_master where "
5777 			      "(type = 'table' or type = 'view') "
5778 			      "and tbl_name like %Q "
5779 			      "UNION "
5780 			      "select NULL as 'TABLE_QUALIFIER', "
5781 			      "NULL as 'TABLE_OWNER', "
5782 			      "tbl_name as 'TABLE_NAME', "
5783 			      "'' as 'GRANTOR', "
5784 			      "'' as 'GRANTEE', "
5785 			      "'REFERENCES' AS 'PRIVILEGE', "
5786 			      "NULL as 'IS_GRANTABLE' "
5787 			      "from sqlite_master where "
5788 			      "(type = 'table' or type = 'view') "
5789 			      "and tbl_name like %Q",
5790 			      tname, tname, tname, tname, tname);
5791     } else {
5792 	sql = sqlite4_mprintf(0, "select NULL as 'TABLE_QUALIFIER', "
5793 			      "NULL as 'TABLE_OWNER', "
5794 			      "tbl_name as 'TABLE_NAME', "
5795 			      "'' as 'GRANTOR', "
5796 			      "'' as 'GRANTEE', "
5797 			      "'SELECT' AS 'PRIVILEGE', "
5798 			      "NULL as 'IS_GRANTABLE' "
5799 			      "from sqlite_master where "
5800 			      "(type = 'table' or type = 'view') "
5801 			      "and lower(tbl_name) = lower(%Q) "
5802 			      "UNION "
5803 			      "select NULL as 'TABLE_QUALIFIER', "
5804 			      "NULL as 'TABLE_OWNER', "
5805 			      "tbl_name as 'TABLE_NAME', "
5806 			      "'' as 'GRANTOR', "
5807 			      "'' as 'GRANTEE', "
5808 			      "'UPDATE' AS 'PRIVILEGE', "
5809 			      "NULL as 'IS_GRANTABLE' "
5810 			      "from sqlite_master where "
5811 			      "(type = 'table' or type = 'view') "
5812 			      "and lower(tbl_name) = lower(%Q) "
5813 			      "UNION "
5814 			      "select NULL as 'TABLE_QUALIFIER', "
5815 			      "NULL as 'TABLE_OWNER', "
5816 			      "tbl_name as 'TABLE_NAME', "
5817 			      "'' as 'GRANTOR', "
5818 			      "'' as 'GRANTEE', "
5819 			      "'DELETE' AS 'PRIVILEGE', "
5820 			      "NULL as 'IS_GRANTABLE' "
5821 			      "from sqlite_master where "
5822 			      "(type = 'table' or type = 'view') "
5823 			      "and lower(tbl_name) = lower(%Q) "
5824 			      "UNION "
5825 			      "select NULL as 'TABLE_QUALIFIER', "
5826 			      "NULL as 'TABLE_OWNER', "
5827 			      "tbl_name as 'TABLE_NAME', "
5828 			      "'' as 'GRANTOR', "
5829 			      "'' as 'GRANTEE', "
5830 			      "'INSERT' AS 'PRIVILEGE', "
5831 			      "NULL as 'IS_GRANTABLE' "
5832 			      "from sqlite_master where "
5833 			      "(type = 'table' or type = 'view') "
5834 			      "and lower(tbl_name) = lower(%Q) "
5835 			      "UNION "
5836 			      "select NULL as 'TABLE_QUALIFIER', "
5837 			      "NULL as 'TABLE_OWNER', "
5838 			      "tbl_name as 'TABLE_NAME', "
5839 			      "'' as 'GRANTOR', "
5840 			      "'' as 'GRANTEE', "
5841 			      "'REFERENCES' AS 'PRIVILEGE', "
5842 			      "NULL as 'IS_GRANTABLE' "
5843 			      "from sqlite_master where "
5844 			      "(type = 'table' or type = 'view') "
5845 			      "and lower(tbl_name) = lower(%Q)",
5846 			      tname, tname, tname, tname, tname);
5847     }
5848 #endif
5849     if (!sql) {
5850 	return nomem(s);
5851     }
5852     ret = starttran(s);
5853     if (ret != SQL_SUCCESS) {
5854 	sqlite4_free(0, sql);
5855 	return ret;
5856     }
5857     dbtraceapi(d, "sqlite4_get_table", sql);
5858     rc = sqlite4_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
5859     sqlite4_free(0, sql);
5860     if (rc == SQLITE4_OK) {
5861 	if (ncols != s->ncols) {
5862 	    freeresult(s, 0);
5863 	    s->nrows = 0;
5864 	} else {
5865 	    s->rowfree = freerows;
5866 	}
5867     } else {
5868 	s->nrows = 0;
5869 	s->rows = NULL;
5870 	s->rowfree = NULL;
5871     }
5872     if (errp) {
5873 	sqlite4_free(0, errp);
5874 	errp = NULL;
5875     }
5876     s->rowp = s->rowprs = -1;
5877     return SQL_SUCCESS;
5878 }
5879 
5880 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
5881 /**
5882  * Retrieve privileges on tables and/or views.
5883  * @param stmt statement handle
5884  * @param catalog catalog name/pattern or NULL
5885  * @param catalogLen length of catalog name/pattern or SQL_NTS
5886  * @param schema schema name/pattern or NULL
5887  * @param schemaLen length of schema name/pattern or SQL_NTS
5888  * @param table table name/pattern or NULL
5889  * @param tableLen length of table name/pattern or SQL_NTS
5890  * @result ODBC error code
5891  */
5892 
5893 SQLRETURN SQL_API
SQLTablePrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5894 SQLTablePrivileges(SQLHSTMT stmt,
5895 		   SQLCHAR *catalog, SQLSMALLINT catalogLen,
5896 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
5897 		   SQLCHAR *table, SQLSMALLINT tableLen)
5898 {
5899 #if defined(_WIN32) || defined(_WIN64)
5900     char *c = NULL, *s = NULL, *t = NULL;
5901 #endif
5902     SQLRETURN ret;
5903 
5904     HSTMT_LOCK(stmt);
5905 #if defined(_WIN32) || defined(_WIN64)
5906     if (!((STMT *) stmt)->oemcp[0]) {
5907 	ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
5908 				 table, tableLen);
5909 	goto done2;
5910     }
5911     if (catalog) {
5912 	c = wmb_to_utf_c((char *) catalog, catalogLen);
5913 	if (!c) {
5914 	    ret = nomem((STMT *) stmt);
5915 	    goto done;
5916 	}
5917     }
5918     if (schema) {
5919 	s = wmb_to_utf_c((char *) schema, schemaLen);
5920 	if (!s) {
5921 	    ret = nomem((STMT *) stmt);
5922 	    goto done;
5923 	}
5924     }
5925     if (table) {
5926 	t = wmb_to_utf_c((char *) table, tableLen);
5927 	if (!t) {
5928 	    ret = nomem((STMT *) stmt);
5929 	    goto done;
5930 	}
5931     }
5932     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
5933 			     (SQLCHAR *) s, SQL_NTS,
5934 			     (SQLCHAR *) t, SQL_NTS);
5935 #else
5936     ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
5937 			     table, tableLen);
5938 #endif
5939 #if defined(_WIN32) || defined(_WIN64)
5940 done:
5941     uc_free(t);
5942     uc_free(s);
5943     uc_free(c);
5944 done2:
5945     ;
5946 #endif
5947     HSTMT_UNLOCK(stmt);
5948     return ret;
5949 }
5950 #endif
5951 
5952 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
5953 #ifdef WINTERFACE
5954 /**
5955  * Retrieve privileges on tables and/or views (UNICODE version).
5956  * @param stmt statement handle
5957  * @param catalog catalog name/pattern or NULL
5958  * @param catalogLen length of catalog name/pattern or SQL_NTS
5959  * @param schema schema name/pattern or NULL
5960  * @param schemaLen length of schema name/pattern or SQL_NTS
5961  * @param table table name/pattern or NULL
5962  * @param tableLen length of table name/pattern or SQL_NTS
5963  * @result ODBC error code
5964  */
5965 
5966 SQLRETURN SQL_API
SQLTablePrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)5967 SQLTablePrivilegesW(SQLHSTMT stmt,
5968 		    SQLWCHAR *catalog, SQLSMALLINT catalogLen,
5969 		    SQLWCHAR *schema, SQLSMALLINT schemaLen,
5970 		    SQLWCHAR *table, SQLSMALLINT tableLen)
5971 {
5972     char *c = NULL, *s = NULL, *t = NULL;
5973     SQLRETURN ret;
5974 
5975     HSTMT_LOCK(stmt);
5976     if (catalog) {
5977 	c = uc_to_utf_c(catalog, catalogLen);
5978 	if (!c) {
5979 	    ret = nomem((STMT *) stmt);
5980 	    goto done;
5981 	}
5982     }
5983     if (schema) {
5984 	s = uc_to_utf_c(schema, schemaLen);
5985 	if (!s) {
5986 	    ret = nomem((STMT *) stmt);
5987 	    goto done;
5988 	}
5989     }
5990     if (table) {
5991 	t = uc_to_utf_c(table, tableLen);
5992 	if (!t) {
5993 	    ret = nomem((STMT *) stmt);
5994 	    goto done;
5995 	}
5996     }
5997     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
5998 			     (SQLCHAR *) s, SQL_NTS,
5999 			     (SQLCHAR *) t, SQL_NTS);
6000 done:
6001     uc_free(t);
6002     uc_free(s);
6003     uc_free(c);
6004     HSTMT_UNLOCK(stmt);
6005     return ret;
6006 }
6007 #endif
6008 #endif
6009 
6010 /**
6011  * Columns for result set of SQLColumnPrivileges().
6012  */
6013 
6014 static COL colPrivSpec2[] = {
6015     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6016     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
6017     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
6018     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6019     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
6020     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
6021     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
6022 };
6023 
6024 static COL colPrivSpec3[] = {
6025     { "SYSTEM", "COLPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
6026     { "SYSTEM", "COLPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
6027     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
6028     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6029     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
6030     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
6031     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
6032 };
6033 
6034 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
6035 /**
6036  * Retrieve privileges on columns.
6037  * @param stmt statement handle
6038  * @param catalog catalog name/pattern or NULL
6039  * @param catalogLen length of catalog name/pattern or SQL_NTS
6040  * @param schema schema name/pattern or NULL
6041  * @param schemaLen length of schema name/pattern or SQL_NTS
6042  * @param table table name/pattern or NULL
6043  * @param tableLen length of table name/pattern or SQL_NTS
6044  * @param column column name or NULL
6045  * @param columnLen length of column name or SQL_NTS
6046  * @result ODBC error code
6047  */
6048 
6049 SQLRETURN SQL_API
SQLColumnPrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * column,SQLSMALLINT columnLen)6050 SQLColumnPrivileges(SQLHSTMT stmt,
6051 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
6052 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
6053 		    SQLCHAR *table, SQLSMALLINT tableLen,
6054 		    SQLCHAR *column, SQLSMALLINT columnLen)
6055 {
6056     SQLRETURN ret;
6057 
6058     HSTMT_LOCK(stmt);
6059     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
6060 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
6061     HSTMT_UNLOCK(stmt);
6062     return ret;
6063 }
6064 #endif
6065 
6066 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
6067 #ifdef WINTERFACE
6068 /**
6069  * Retrieve privileges on columns (UNICODE version).
6070  * @param stmt statement handle
6071  * @param catalog catalog name/pattern or NULL
6072  * @param catalogLen length of catalog name/pattern or SQL_NTS
6073  * @param schema schema name/pattern or NULL
6074  * @param schemaLen length of schema name/pattern or SQL_NTS
6075  * @param table table name/pattern or NULL
6076  * @param tableLen length of table name/pattern or SQL_NTS
6077  * @param column column name or NULL
6078  * @param columnLen length of column name or SQL_NTS
6079  * @result ODBC error code
6080  */
6081 
6082 SQLRETURN SQL_API
SQLColumnPrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * column,SQLSMALLINT columnLen)6083 SQLColumnPrivilegesW(SQLHSTMT stmt,
6084 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
6085 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
6086 		     SQLWCHAR *table, SQLSMALLINT tableLen,
6087 		     SQLWCHAR *column, SQLSMALLINT columnLen)
6088 {
6089     SQLRETURN ret;
6090 
6091     HSTMT_LOCK(stmt);
6092     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
6093 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
6094     HSTMT_UNLOCK(stmt);
6095     return ret;
6096 }
6097 #endif
6098 #endif
6099 
6100 /**
6101  * Columns for result set of SQLPrimaryKeys().
6102  */
6103 
6104 static COL pkeySpec2[] = {
6105     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6106     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
6107     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
6108     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6109     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
6110     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
6111 };
6112 
6113 static COL pkeySpec3[] = {
6114     { "SYSTEM", "PRIMARYKEY", "TABLE_CAT", SCOL_VARCHAR, 50 },
6115     { "SYSTEM", "PRIMARYKEY", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
6116     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
6117     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6118     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
6119     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
6120 };
6121 
6122 /**
6123  * Internal retrieve information about indexed columns.
6124  * @param stmt statement handle
6125  * @param cat catalog name/pattern or NULL
6126  * @param catLen length of catalog name/pattern or SQL_NTS
6127  * @param schema schema name/pattern or NULL
6128  * @param schemaLen length of schema name/pattern or SQL_NTS
6129  * @param table table name/pattern or NULL
6130  * @param tableLen length of table name/pattern or SQL_NTS
6131  * @result ODBC error code
6132  */
6133 
6134 static SQLRETURN
drvprimarykeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)6135 drvprimarykeys(SQLHSTMT stmt,
6136 	       SQLCHAR *cat, SQLSMALLINT catLen,
6137 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
6138 	       SQLCHAR *table, SQLSMALLINT tableLen)
6139 {
6140     STMT *s;
6141     DBC *d;
6142     SQLRETURN sret;
6143     int i, asize, ret, nrows, ncols, nrows2 = 0, ncols2 = 0;
6144     int namec = -1, uniquec = -1, namec2 = -1, uniquec2 = -1, offs, seq = 1;
6145     PTRDIFF_T size;
6146     char **rowp = NULL, **rowp2 = NULL, *errp = NULL, *sql, tname[512];
6147 
6148     sret = mkresultset(stmt, pkeySpec2, array_size(pkeySpec2),
6149 		       pkeySpec3, array_size(pkeySpec3), &asize);
6150     if (sret != SQL_SUCCESS) {
6151 	return sret;
6152     }
6153     s = (STMT *) stmt;
6154     d = (DBC *) s->dbc;
6155     if (!table || table[0] == '\0' || table[0] == '%') {
6156 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
6157 	return SQL_ERROR;
6158     }
6159     if (tableLen == SQL_NTS) {
6160 	size = sizeof (tname) - 1;
6161     } else {
6162 	size = min(sizeof (tname) - 1, tableLen);
6163     }
6164     strncpy(tname, (char *) table, size);
6165     tname[size] = '\0';
6166     unescpat(tname);
6167     sql = sqlite4_mprintf(0, "PRAGMA table_info(%Q)", tname);
6168     if (!sql) {
6169 	return nomem(s);
6170     }
6171     sret = starttran(s);
6172     if (sret != SQL_SUCCESS) {
6173 	sqlite4_free(0, sql);
6174 	return sret;
6175     }
6176     dbtraceapi(d, "sqlite4_get_table", sql);
6177     ret = sqlite4_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
6178     sqlite4_free(0, sql);
6179     if (ret != SQLITE4_OK) {
6180 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6181 		errp ? errp : "unknown error", ret);
6182 	if (errp) {
6183 	    sqlite4_free(0, errp);
6184 	    errp = NULL;
6185 	}
6186 	return SQL_ERROR;
6187     }
6188     if (errp) {
6189 	sqlite4_free(0, errp);
6190 	errp = NULL;
6191     }
6192     size = 0;
6193     if (ncols * nrows > 0) {
6194 	int typec;
6195 
6196 	namec = findcol(rowp, ncols, "name");
6197 	uniquec = findcol(rowp, ncols, "pk");
6198 	typec = findcol(rowp, ncols, "type");
6199 	if (namec >= 0 && uniquec >= 0 && typec >= 0) {
6200 	    for (i = 1; i <= nrows; i++) {
6201 		if (*rowp[i * ncols + uniquec] != '0') {
6202 		    size++;
6203 		}
6204 	    }
6205 	}
6206     }
6207     if (size == 0) {
6208 	sql = sqlite4_mprintf(0, "PRAGMA index_list(%Q)", tname);
6209 	if (!sql) {
6210 	    freerows(rowp);
6211 	    return nomem(s);
6212 	}
6213 	dbtraceapi(d, "sqlite4_get_table", sql);
6214 	ret = sqlite4_get_table(d->sqlite, sql, &rowp2, &nrows2, &ncols2,
6215 				&errp);
6216 	sqlite4_free(0, sql);
6217 	if (ret != SQLITE4_OK) {
6218 	    freerows(rowp);
6219 	    freerows(rowp2);
6220 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6221 		    errp ? errp : "unknown error", ret);
6222 	    if (errp) {
6223 		sqlite4_free(0, errp);
6224 		errp = NULL;
6225 	    }
6226 	    return SQL_ERROR;
6227 	}
6228 	if (errp) {
6229 	    sqlite4_free(0, errp);
6230 	    errp = NULL;
6231 	}
6232     }
6233     if (ncols2 * nrows2 > 0) {
6234 	namec2 = findcol(rowp2, ncols2, "name");
6235 	uniquec2 = findcol(rowp2, ncols2, "unique");
6236 	if (namec2 >= 0 && uniquec2 >=  0) {
6237 	    for (i = 1; i <= nrows2; i++) {
6238 		int nnrows, nncols, nlen = 0;
6239 		char **rowpp;
6240 
6241 		if (rowp2[i * ncols2 + namec2]) {
6242 		    nlen = strlen(rowp2[i * ncols2 + namec2]);
6243 		}
6244 		if (nlen < 17 ||
6245 		    strncmp(rowp2[i * ncols2 + namec2],
6246 			    "sqlite_autoindex_", 17)) {
6247 		    continue;
6248 		}
6249 		if (*rowp2[i * ncols2 + uniquec2] != '0') {
6250 		    ret = SQLITE4_ERROR;
6251 		    sql = sqlite4_mprintf(0, "PRAGMA index_info(%Q)",
6252 					  rowp2[i * ncols2 + namec2]);
6253 		    if (sql) {
6254 			dbtraceapi(d, "sqlite4_get_table", sql);
6255 			ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
6256 						&nnrows, &nncols, NULL);
6257 			sqlite4_free(0, sql);
6258 		    }
6259 		    if (ret == SQLITE4_OK) {
6260 			size += nnrows;
6261 			freerows(rowpp);
6262 		    }
6263 		}
6264 	    }
6265 	}
6266     }
6267     if (size == 0) {
6268 	freerows(rowp);
6269 	freerows(rowp2);
6270 	return SQL_SUCCESS;
6271     }
6272     s->nrows = size;
6273     size = (size + 1) * asize;
6274     s->rows = xmalloc((size + 1) * sizeof (char *));
6275     if (!s->rows) {
6276 	s->nrows = 0;
6277 	freerows(rowp);
6278 	freerows(rowp2);
6279 	return nomem(s);
6280     }
6281     s->rows[0] = (char *) size;
6282     s->rows += 1;
6283     memset(s->rows, 0, sizeof (char *) * size);
6284     s->rowfree = freerows;
6285     offs = s->ncols;
6286     if (rowp) {
6287 	for (i = 1; i <= nrows; i++) {
6288 	    if (*rowp[i * ncols + uniquec] != '0') {
6289 		char buf[32];
6290 
6291 #if defined(_WIN32) || defined(_WIN64)
6292 		s->rows[offs + 0] = xstrdup(d->xcelqrx ? "main" : "");
6293 		s->rows[offs + 1] = xstrdup("");
6294 #else
6295 		s->rows[offs + 0] = xstrdup("");
6296 		s->rows[offs + 1] = xstrdup("");
6297 #endif
6298 		s->rows[offs + 2] = xstrdup(tname);
6299 		s->rows[offs + 3] = xstrdup(rowp[i * ncols + namec]);
6300 		sprintf(buf, "%d", seq++);
6301 		s->rows[offs + 4] = xstrdup(buf);
6302 		offs += s->ncols;
6303 	    }
6304 	}
6305     }
6306     if (rowp2) {
6307 	for (i = 1; i <= nrows2; i++) {
6308 	    int nnrows, nncols, nlen = 0;
6309 	    char **rowpp;
6310 
6311 	    if (rowp2[i * ncols2 + namec2]) {
6312 		nlen = strlen(rowp2[i * ncols2 + namec2]);
6313 	    }
6314 	    if (nlen < 17 ||
6315 		strncmp(rowp2[i * ncols2 + namec2], "sqlite_autoindex_", 17)) {
6316 		continue;
6317 	    }
6318 	    if (*rowp2[i * ncols2 + uniquec2] != '0') {
6319 		int k;
6320 
6321 		ret = SQLITE4_ERROR;
6322 		sql = sqlite4_mprintf(0, "PRAGMA index_info(%Q)",
6323 				      rowp2[i * ncols2 + namec2]);
6324 		if (sql) {
6325 		    dbtraceapi(d, "sqlite4_get_table", sql);
6326 		    ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
6327 					    &nnrows, &nncols, NULL);
6328 		    sqlite4_free(0, sql);
6329 		}
6330 		if (ret != SQLITE4_OK) {
6331 		    continue;
6332 		}
6333 		for (k = 0; nnrows && k < nncols; k++) {
6334 		    if (strcmp(rowpp[k], "name") == 0) {
6335 			int m;
6336 
6337 			for (m = 1; m <= nnrows; m++) {
6338 			    int roffs = offs + (m - 1) * s->ncols;
6339 
6340 #if defined(_WIN32) || defined(_WIN64)
6341 			    s->rows[roffs + 0] =
6342 				xstrdup(d->xcelqrx ? "main" : "");
6343 			    s->rows[roffs + 1] = xstrdup("");
6344 #else
6345 			    s->rows[roffs + 0] = xstrdup("");
6346 			    s->rows[roffs + 1] = xstrdup("");
6347 #endif
6348 			    s->rows[roffs + 2] = xstrdup(tname);
6349 			    s->rows[roffs + 3] =
6350 				xstrdup(rowpp[m * nncols + k]);
6351 			    s->rows[roffs + 5] =
6352 				xstrdup(rowp2[i * ncols2 + namec2]);
6353 			}
6354 		    } else if (strcmp(rowpp[k], "seqno") == 0) {
6355 			int m;
6356 
6357 			for (m = 1; m <= nnrows; m++) {
6358 			    int roffs = offs + (m - 1) * s->ncols;
6359 			    int pos = m - 1;
6360 			    char buf[32];
6361 
6362 			    sscanf(rowpp[m * nncols + k], "%d", &pos);
6363 			    sprintf(buf, "%d", pos + 1);
6364 			    s->rows[roffs + 4] = xstrdup(buf);
6365 			}
6366 		    }
6367 		}
6368 		offs += nnrows * s->ncols;
6369 		freerows(rowpp);
6370 	    }
6371 	}
6372     }
6373     freerows(rowp);
6374     freerows(rowp2);
6375     return SQL_SUCCESS;
6376 }
6377 
6378 #ifndef WINTERFACE
6379 /**
6380  * Retrieve information about indexed columns.
6381  * @param stmt statement handle
6382  * @param cat catalog name/pattern or NULL
6383  * @param catLen length of catalog name/pattern or SQL_NTS
6384  * @param schema schema name/pattern or NULL
6385  * @param schemaLen length of schema name/pattern or SQL_NTS
6386  * @param table table name/pattern or NULL
6387  * @param tableLen length of table name/pattern or SQL_NTS
6388  * @result ODBC error code
6389  */
6390 
6391 SQLRETURN SQL_API
SQLPrimaryKeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)6392 SQLPrimaryKeys(SQLHSTMT stmt,
6393 	       SQLCHAR *cat, SQLSMALLINT catLen,
6394 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
6395 	       SQLCHAR *table, SQLSMALLINT tableLen)
6396 {
6397 #if defined(_WIN32) || defined(_WIN64)
6398     char *c = NULL, *s = NULL, *t = NULL;
6399 #endif
6400     SQLRETURN ret;
6401 
6402     HSTMT_LOCK(stmt);
6403 #if defined(_WIN32) || defined(_WIN64)
6404     if (!((STMT *) stmt)->oemcp[0]) {
6405 	ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
6406 			     table, tableLen);
6407 	goto done2;
6408     }
6409     if (cat) {
6410 	c = wmb_to_utf_c((char *) cat, catLen);
6411 	if (!c) {
6412 	    ret = nomem((STMT *) stmt);
6413 	    goto done;
6414 	}
6415     }
6416     if (schema) {
6417 	s = wmb_to_utf_c((char *) schema, schemaLen);
6418 	if (!s) {
6419 	    ret = nomem((STMT *) stmt);
6420 	    goto done;
6421 	}
6422     }
6423     if (table) {
6424 	t = wmb_to_utf_c((char *) table, tableLen);
6425 	if (!t) {
6426 	    ret = nomem((STMT *) stmt);
6427 	    goto done;
6428 	}
6429     }
6430     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
6431 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
6432 #else
6433     ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
6434 			 table, tableLen);
6435 #endif
6436 #if defined(_WIN32) || defined(_WIN64)
6437 done:
6438     uc_free(t);
6439     uc_free(s);
6440     uc_free(c);
6441 done2:
6442     ;
6443 #endif
6444     HSTMT_UNLOCK(stmt);
6445     return ret;
6446 }
6447 #endif
6448 
6449 #ifdef WINTERFACE
6450 /**
6451  * Retrieve information about indexed columns (UNICODE version).
6452  * @param stmt statement handle
6453  * @param cat catalog name/pattern or NULL
6454  * @param catLen length of catalog name/pattern or SQL_NTS
6455  * @param schema schema name/pattern or NULL
6456  * @param schemaLen length of schema name/pattern or SQL_NTS
6457  * @param table table name/pattern or NULL
6458  * @param tableLen length of table name/pattern or SQL_NTS
6459  * @result ODBC error code
6460  */
6461 
6462 SQLRETURN SQL_API
SQLPrimaryKeysW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)6463 SQLPrimaryKeysW(SQLHSTMT stmt,
6464 		SQLWCHAR *cat, SQLSMALLINT catLen,
6465 		SQLWCHAR *schema, SQLSMALLINT schemaLen,
6466 		SQLWCHAR *table, SQLSMALLINT tableLen)
6467 {
6468     char *c = NULL, *s = NULL, *t = NULL;
6469     SQLRETURN ret;
6470 
6471     HSTMT_LOCK(stmt);
6472     if (cat) {
6473 	c = uc_to_utf_c(cat, catLen);
6474 	if (!c) {
6475 	    ret = nomem((STMT *) stmt);
6476 	    goto done;
6477 	}
6478     }
6479     if (schema) {
6480 	s = uc_to_utf_c(schema, schemaLen);
6481 	if (!s) {
6482 	    ret = nomem((STMT *) stmt);
6483 	    goto done;
6484 	}
6485     }
6486     if (table) {
6487 	t = uc_to_utf_c(table, tableLen);
6488 	if (!t) {
6489 	    ret = nomem((STMT *) stmt);
6490 	    goto done;
6491 	}
6492     }
6493     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
6494 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
6495 done:
6496     uc_free(t);
6497     uc_free(s);
6498     uc_free(c);
6499     HSTMT_UNLOCK(stmt);
6500     return ret;
6501 }
6502 #endif
6503 
6504 /**
6505  * Columns for result set of SQLSpecialColumns().
6506  */
6507 
6508 static COL scolSpec2[] = {
6509     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
6510     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6511     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
6512     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
6513     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
6514     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
6515     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
6516     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
6517     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
6518 };
6519 
6520 static COL scolSpec3[] = {
6521     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
6522     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6523     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
6524     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
6525     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
6526     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
6527     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
6528     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
6529     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
6530 };
6531 
6532 /**
6533  * Internal retrieve information about indexed columns.
6534  * @param stmt statement handle
6535  * @param id type of information, e.g. best row id
6536  * @param cat catalog name/pattern or NULL
6537  * @param catLen length of catalog name/pattern or SQL_NTS
6538  * @param schema schema name/pattern or NULL
6539  * @param schemaLen length of schema name/pattern or SQL_NTS
6540  * @param table table name/pattern or NULL
6541  * @param tableLen length of table name/pattern or SQL_NTS
6542  * @param scope
6543  * @param nullable
6544  * @result ODBC error code
6545  */
6546 
6547 static SQLRETURN
drvspecialcolumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6548 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
6549 		  SQLCHAR *cat, SQLSMALLINT catLen,
6550 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
6551 		  SQLCHAR *table, SQLSMALLINT tableLen,
6552 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
6553 {
6554     STMT *s;
6555     DBC *d;
6556     SQLRETURN sret;
6557     int i, asize, ret, nrows, ncols, nnnrows, nnncols, offs;
6558     PTRDIFF_T size;
6559     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
6560     int notnullcc = -1, mkrowid = 0;
6561     char *errp = NULL, *sql, tname[512];
6562     char **rowp = NULL, **rowppp = NULL;
6563 
6564     sret = mkresultset(stmt, scolSpec2, array_size(scolSpec2),
6565 		       scolSpec3, array_size(scolSpec3), &asize);
6566     if (sret != SQL_SUCCESS) {
6567 	return sret;
6568     }
6569     s = (STMT *) stmt;
6570     d = (DBC *) s->dbc;
6571     if (!table || table[0] == '\0' || table[0] == '%') {
6572 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
6573 	return SQL_ERROR;
6574     }
6575     if (tableLen == SQL_NTS) {
6576 	size = sizeof (tname) - 1;
6577     } else {
6578 	size = min(sizeof (tname) - 1, tableLen);
6579     }
6580     strncpy(tname, (char *) table, size);
6581     tname[size] = '\0';
6582     unescpat(tname);
6583     if (id != SQL_BEST_ROWID) {
6584 	return SQL_SUCCESS;
6585     }
6586     sql = sqlite4_mprintf(0, "PRAGMA index_list(%Q)", tname);
6587     if (!sql) {
6588 	return nomem(s);
6589     }
6590     sret = starttran(s);
6591     if (sret != SQL_SUCCESS) {
6592 	sqlite4_free(0, sql);
6593 	return sret;
6594     }
6595     dbtraceapi(d, "sqlite4_get_table", sql);
6596     ret = sqlite4_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
6597     sqlite4_free(0, sql);
6598     if (ret != SQLITE4_OK) {
6599 doerr:
6600 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6601 		errp ? errp : "unknown error", ret);
6602 	if (errp) {
6603 	    sqlite4_free(0, errp);
6604 	    errp = NULL;
6605 	}
6606 	return SQL_ERROR;
6607     }
6608     if (errp) {
6609 	sqlite4_free(0, errp);
6610 	errp = NULL;
6611     }
6612     size = 0; /* number result rows */
6613     if (ncols * nrows <= 0) {
6614 	goto nodata_but_rowid;
6615     }
6616     sql = sqlite4_mprintf(0, "PRAGMA table_info(%Q)", tname);
6617     if (!sql) {
6618 	return nomem(s);
6619     }
6620     dbtraceapi(d, "sqlite4_get_table", sql);
6621     ret = sqlite4_get_table(d->sqlite, sql, &rowppp, &nnnrows, &nnncols,
6622 			    &errp);
6623     sqlite4_free(0, sql);
6624     if (ret != SQLITE4_OK) {
6625 	freerows(rowp);
6626 	goto doerr;
6627     }
6628     if (errp) {
6629 	sqlite4_free(0, errp);
6630 	errp = NULL;
6631     }
6632     namec = findcol(rowp, ncols, "name");
6633     uniquec = findcol(rowp, ncols, "unique");
6634     if (namec < 0 || uniquec < 0) {
6635 	goto nodata_but_rowid;
6636     }
6637     namecc = findcol(rowppp, nnncols, "name");
6638     typecc = findcol(rowppp, nnncols, "type");
6639     notnullcc = findcol(rowppp, nnncols, "notnull");
6640     for (i = 1; i <= nrows; i++) {
6641 	int nnrows, nncols;
6642 	char **rowpp = NULL;
6643 
6644 	if (*rowp[i * ncols + uniquec] != '0') {
6645 	    ret = SQLITE4_ERROR;
6646 	    sql = sqlite4_mprintf(0, "PRAGMA index_info(%Q)",
6647 				  rowp[i * ncols + namec]);
6648 	    if (sql) {
6649 		dbtraceapi(d, "sqlite4_get_table", sql);
6650 		ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
6651 					&nnrows, &nncols, NULL);
6652 		sqlite4_free(0, sql);
6653 	    }
6654 	    if (ret == SQLITE4_OK) {
6655 		size += nnrows;
6656 		freerows(rowpp);
6657 	    }
6658 	}
6659     }
6660 nodata_but_rowid:
6661     if (size == 0) {
6662 	size = 1;
6663 	mkrowid = 1;
6664     }
6665     s->nrows = size;
6666     size = (size + 1) * asize;
6667     s->rows = xmalloc((size + 1) * sizeof (char *));
6668     if (!s->rows) {
6669 	s->nrows = 0;
6670 	freerows(rowp);
6671 	freerows(rowppp);
6672 	return nomem(s);
6673     }
6674     s->rows[0] = (char *) size;
6675     s->rows += 1;
6676     memset(s->rows, 0, sizeof (char *) * size);
6677     s->rowfree = freerows;
6678     if (mkrowid) {
6679 	s->nrows = 0;
6680 	goto mkrowid;
6681     }
6682     offs = 0;
6683     for (i = 1; i <= nrows; i++) {
6684 	int nnrows, nncols;
6685 	char **rowpp = NULL;
6686 
6687 	if (*rowp[i * ncols + uniquec] != '0') {
6688 	    int k;
6689 
6690 	    ret = SQLITE4_ERROR;
6691 	    sql = sqlite4_mprintf(0, "PRAGMA index_info(%Q)",
6692 				  rowp[i * ncols + namec]);
6693 	    if (sql) {
6694 		dbtraceapi(d, "sqlite4_get_table", sql);
6695 		ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
6696 					&nnrows, &nncols, NULL);
6697 		sqlite4_free(0, sql);
6698 	    }
6699 	    if (ret != SQLITE4_OK) {
6700 		continue;
6701 	    }
6702 	    for (k = 0; nnrows && k < nncols; k++) {
6703 		if (strcmp(rowpp[k], "name") == 0) {
6704 		    int m;
6705 
6706 		    for (m = 1; m <= nnrows; m++) {
6707 			int roffs = (offs + m) * s->ncols;
6708 
6709 			s->rows[roffs + 0] =
6710 			    xstrdup(stringify(SQL_SCOPE_SESSION));
6711 			s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
6712 			s->rows[roffs + 4] = xstrdup("0");
6713 			s->rows[roffs + 7] =
6714 			    xstrdup(stringify(SQL_PC_NOT_PSEUDO));
6715 			if (namecc >= 0 && typecc >= 0) {
6716 			    int ii;
6717 
6718 			    for (ii = 1; ii <= nnnrows; ii++) {
6719 				if (strcmp(rowppp[ii * nnncols + namecc],
6720 					   rowpp[m * nncols + k]) == 0) {
6721 				    char *typen = rowppp[ii * nnncols + typecc];
6722 				    int sqltype, mm, dd, isnullable = 0;
6723 				    char buf[32];
6724 
6725 				    s->rows[roffs + 3] = xstrdup(typen);
6726 				    sqltype = mapsqltype(typen, NULL, *s->ov3,
6727 							 s->nowchar[0],
6728 							 s->dobigint);
6729 				    getmd(typen, sqltype, &mm, &dd);
6730 #ifdef SQL_LONGVARCHAR
6731 				    if (sqltype == SQL_VARCHAR && mm > 255) {
6732 					sqltype = SQL_LONGVARCHAR;
6733 				    }
6734 #endif
6735 #ifdef WINTERFACE
6736 #ifdef SQL_WLONGVARCHAR
6737 				    if (sqltype == SQL_WVARCHAR && mm > 255) {
6738 					sqltype = SQL_WLONGVARCHAR;
6739 				    }
6740 #endif
6741 #endif
6742 				    if (sqltype == SQL_VARBINARY && mm > 255) {
6743 					sqltype = SQL_LONGVARBINARY;
6744 				    }
6745 				    sprintf(buf, "%d", sqltype);
6746 				    s->rows[roffs + 2] = xstrdup(buf);
6747 				    sprintf(buf, "%d", mm);
6748 				    s->rows[roffs + 5] = xstrdup(buf);
6749 				    sprintf(buf, "%d", dd);
6750 				    s->rows[roffs + 6] = xstrdup(buf);
6751 				    if (notnullcc >= 0) {
6752 					char *inp =
6753 					   rowppp[ii * nnncols + notnullcc];
6754 
6755 					isnullable = inp[0] != '0';
6756 				    }
6757 				    sprintf(buf, "%d", isnullable);
6758 				    s->rows[roffs + 8] = xstrdup(buf);
6759 				}
6760 			    }
6761 			}
6762 		    }
6763 		}
6764 	    }
6765 	    offs += nnrows;
6766 	    freerows(rowpp);
6767 	}
6768     }
6769     if (nullable == SQL_NO_NULLS) {
6770 	for (i = 1; i < s->nrows; i++) {
6771 	    if (s->rows[i * s->ncols + 8][0] == '0') {
6772 		int m, i1 = i + 1;
6773 
6774 		for (m = 0; m < s->ncols; m++) {
6775 		    freep(&s->rows[i * s->ncols + m]);
6776 		}
6777 		size = s->ncols * sizeof (char *) * (s->nrows - i1);
6778 		if (size > 0) {
6779 		    memmove(s->rows + i * s->ncols,
6780 			    s->rows + i1 * s->ncols,
6781 			    size);
6782 		    memset(s->rows + s->nrows * s->ncols, 0,
6783 			   s->ncols * sizeof (char *));
6784 		}
6785 		s->nrows--;
6786 		--i;
6787 	    }
6788 	}
6789     }
6790 mkrowid:
6791     freerows(rowp);
6792     freerows(rowppp);
6793     if (s->nrows == 0) {
6794 	s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
6795 	s->rows[s->ncols + 1] = xstrdup("_ROWID_");
6796 	s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
6797 	s->rows[s->ncols + 3] = xstrdup("integer");
6798 	s->rows[s->ncols + 4] = xstrdup("0");
6799 	s->rows[s->ncols + 5] = xstrdup("10");
6800 	s->rows[s->ncols + 6] = xstrdup("9");
6801 	s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
6802 	s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
6803 	s->nrows = 1;
6804     }
6805     return SQL_SUCCESS;
6806 }
6807 
6808 #ifndef WINTERFACE
6809 /**
6810  * Retrieve information about indexed columns.
6811  * @param stmt statement handle
6812  * @param id type of information, e.g. best row id
6813  * @param cat catalog name/pattern or NULL
6814  * @param catLen length of catalog name/pattern or SQL_NTS
6815  * @param schema schema name/pattern or NULL
6816  * @param schemaLen length of schema name/pattern or SQL_NTS
6817  * @param table table name/pattern or NULL
6818  * @param tableLen length of table name/pattern or SQL_NTS
6819  * @param scope
6820  * @param nullable
6821  * @result ODBC error code
6822  */
6823 
6824 SQLRETURN SQL_API
SQLSpecialColumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6825 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
6826 		  SQLCHAR *cat, SQLSMALLINT catLen,
6827 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
6828 		  SQLCHAR *table, SQLSMALLINT tableLen,
6829 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
6830 {
6831 #if defined(_WIN32) || defined(_WIN64)
6832     char *c = NULL, *s = NULL, *t = NULL;
6833 #endif
6834     SQLRETURN ret;
6835 
6836     HSTMT_LOCK(stmt);
6837 #if defined(_WIN32) || defined(_WIN64)
6838     if (!((STMT *) stmt)->oemcp[0]) {
6839 	ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
6840 				table, tableLen, scope, nullable);
6841 	goto done2;
6842     }
6843     if (cat) {
6844 	c = wmb_to_utf_c((char *) cat, catLen);
6845 	if (!c) {
6846 	    ret = nomem((STMT *) stmt);
6847 	    goto done;
6848 	}
6849     }
6850     if (schema) {
6851 	s = wmb_to_utf_c((char *) schema, schemaLen);
6852 	if (!s) {
6853 	    ret = nomem((STMT *) stmt);
6854 	    goto done;
6855 	}
6856     }
6857     if (table) {
6858 	t = wmb_to_utf_c((char *) table, tableLen);
6859 	if (!t) {
6860 	    ret = nomem((STMT *) stmt);
6861 	    goto done;
6862 	}
6863     }
6864     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
6865 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
6866 			    scope, nullable);
6867 #else
6868     ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
6869 			    table, tableLen, scope, nullable);
6870 #endif
6871 #if defined(_WIN32) || defined(_WIN64)
6872 done:
6873     uc_free(t);
6874     uc_free(s);
6875     uc_free(c);
6876 done2:
6877     ;
6878 #endif
6879     HSTMT_UNLOCK(stmt);
6880     return ret;
6881 }
6882 #endif
6883 
6884 #ifdef WINTERFACE
6885 /**
6886  * Retrieve information about indexed columns (UNICODE version).
6887  * @param stmt statement handle
6888  * @param id type of information, e.g. best row id
6889  * @param cat catalog name/pattern or NULL
6890  * @param catLen length of catalog name/pattern or SQL_NTS
6891  * @param schema schema name/pattern or NULL
6892  * @param schemaLen length of schema name/pattern or SQL_NTS
6893  * @param table table name/pattern or NULL
6894  * @param tableLen length of table name/pattern or SQL_NTS
6895  * @param scope
6896  * @param nullable
6897  * @result ODBC error code
6898  */
6899 
6900 SQLRETURN SQL_API
SQLSpecialColumnsW(SQLHSTMT stmt,SQLUSMALLINT id,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)6901 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
6902 		   SQLWCHAR *cat, SQLSMALLINT catLen,
6903 		   SQLWCHAR *schema, SQLSMALLINT schemaLen,
6904 		   SQLWCHAR *table, SQLSMALLINT tableLen,
6905 		   SQLUSMALLINT scope, SQLUSMALLINT nullable)
6906 {
6907     char *c = NULL, *s = NULL, *t = NULL;
6908     SQLRETURN ret;
6909 
6910     HSTMT_LOCK(stmt);
6911     if (cat) {
6912 	c = uc_to_utf_c(cat, catLen);
6913 	if (!c) {
6914 	    ret = nomem((STMT *) stmt);
6915 	    goto done;
6916 	}
6917     }
6918     if (schema) {
6919 	s = uc_to_utf_c(schema, schemaLen);
6920 	if (!s) {
6921 	    ret = nomem((STMT *) stmt);
6922 	    goto done;
6923 	}
6924     }
6925     if (table) {
6926 	t = uc_to_utf_c(table, tableLen);
6927 	if (!t) {
6928 	    ret = nomem((STMT *) stmt);
6929 	    goto done;
6930 	}
6931     }
6932     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
6933 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
6934 			    scope, nullable);
6935 done:
6936     uc_free(t);
6937     uc_free(s);
6938     uc_free(c);
6939     HSTMT_UNLOCK(stmt);
6940     return ret;
6941 }
6942 #endif
6943 
6944 /**
6945  * Columns for result set of SQLForeignKeys().
6946  */
6947 
6948 static COL fkeySpec2[] = {
6949     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6950     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
6951     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
6952     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6953     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
6954     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
6955     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
6956     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6957     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
6958     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
6959     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
6960     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
6961     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
6962     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
6963 };
6964 
6965 static COL fkeySpec3[] = {
6966     { "SYSTEM", "FOREIGNKEY", "PKTABLE_CAT", SCOL_VARCHAR, 50 },
6967     { "SYSTEM", "FOREIGNKEY", "PKTABLE_SCHEM", SCOL_VARCHAR, 50 },
6968     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
6969     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6970     { "SYSTEM", "FOREIGNKEY", "FKTABLE_CAT", SCOL_VARCHAR, 50 },
6971     { "SYSTEM", "FOREIGNKEY", "FKTABLE_SCHEM", SCOL_VARCHAR, 50 },
6972     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
6973     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
6974     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
6975     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
6976     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
6977     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
6978     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
6979     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
6980 };
6981 
6982 /**
6983  * Internal retrieve information about primary/foreign keys.
6984  * @param stmt statement handle
6985  * @param PKcatalog primary key catalog name/pattern or NULL
6986  * @param PKcatalogLen length of PKcatalog or SQL_NTS
6987  * @param PKschema primary key schema name/pattern or NULL
6988  * @param PKschemaLen length of PKschema or SQL_NTS
6989  * @param PKtable primary key table name/pattern or NULL
6990  * @param PKtableLen length of PKtable or SQL_NTS
6991  * @param FKcatalog foreign key catalog name/pattern or NULL
6992  * @param FKcatalogLen length of FKcatalog or SQL_NTS
6993  * @param FKschema foreign key schema name/pattern or NULL
6994  * @param FKschemaLen length of FKschema or SQL_NTS
6995  * @param FKtable foreign key table name/pattern or NULL
6996  * @param FKtableLen length of FKtable or SQL_NTS
6997  * @result ODBC error code
6998  */
6999 
7000 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)7001 drvforeignkeys(SQLHSTMT stmt,
7002 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7003 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
7004 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
7005 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7006 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
7007 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
7008 {
7009     STMT *s;
7010     DBC *d;
7011     SQLRETURN sret;
7012     int i, asize, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
7013     int onu, ond;
7014     PTRDIFF_T size;
7015     char **rowp, *errp = NULL, *sql, pname[512], fname[512];
7016 
7017     sret = mkresultset(stmt, fkeySpec2, array_size(fkeySpec2),
7018 		       fkeySpec3, array_size(fkeySpec3), &asize);
7019     if (sret != SQL_SUCCESS) {
7020 	return sret;
7021     }
7022     s = (STMT *) stmt;
7023     sret = starttran(s);
7024     if (sret != SQL_SUCCESS) {
7025 	return sret;
7026     }
7027     d = (DBC *) s->dbc;
7028     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
7029 	(!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
7030 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
7031 	return SQL_ERROR;
7032     }
7033     size = 0;
7034     if (PKtable) {
7035 	if (PKtableLen == SQL_NTS) {
7036 	    size = sizeof (pname) - 1;
7037 	} else {
7038 	    size = min(sizeof (pname) - 1, PKtableLen);
7039 	}
7040 	strncpy(pname, (char *) PKtable, size);
7041     }
7042     pname[size] = '\0';
7043     size = 0;
7044     if (FKtable) {
7045 
7046 	if (FKtableLen == SQL_NTS) {
7047 	    size = sizeof (fname) - 1;
7048 	} else {
7049 	    size = min(sizeof (fname) - 1, FKtableLen);
7050 	}
7051 	strncpy(fname, (char *) FKtable, size);
7052     }
7053     fname[size] = '\0';
7054     if (fname[0] != '\0') {
7055 	int plen;
7056 
7057 	ret = SQLITE4_ERROR;
7058 	sql = sqlite4_mprintf(0, "PRAGMA foreign_key_list(%Q)", fname);
7059 	if (sql) {
7060 	    dbtraceapi(d, "sqlite4_get_table", sql);
7061 	    ret = sqlite4_get_table(d->sqlite, sql, &rowp,
7062 				    &nrows, &ncols, &errp);
7063 	    sqlite4_free(0, sql);
7064 	}
7065 	if (ret != SQLITE4_OK) {
7066 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7067 		    errp ? errp : "unknown error", ret);
7068 	    if (errp) {
7069 		sqlite4_free(0, errp);
7070 		errp = NULL;
7071 	    }
7072 	    return SQL_ERROR;
7073 	}
7074 	if (errp) {
7075 	    sqlite4_free(0, errp);
7076 	    errp = NULL;
7077 	}
7078 	if (ncols * nrows <= 0) {
7079 nodata:
7080 	    freerows(rowp);
7081 	    return SQL_SUCCESS;
7082 	}
7083 	size = 0;
7084 	namec = findcol(rowp, ncols, "table");
7085 	seqc = findcol(rowp, ncols, "seq");
7086 	fromc = findcol(rowp, ncols, "from");
7087 	toc = findcol(rowp, ncols, "to");
7088 	onu = findcol(rowp, ncols, "on_update");
7089 	ond = findcol(rowp, ncols, "on_delete");
7090 	if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
7091 	    goto nodata;
7092 	}
7093 	plen = strlen(pname);
7094 	for (i = 1; i <= nrows; i++) {
7095 	    char *ptab = unquote(rowp[i * ncols + namec]);
7096 
7097 	    if (plen && ptab) {
7098 		int len = strlen(ptab);
7099 
7100 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
7101 		    continue;
7102 		}
7103 	    }
7104 	    size++;
7105 	}
7106 	if (size == 0) {
7107 	    goto nodata;
7108 	}
7109 	s->nrows = size;
7110 	size = (size + 1) * asize;
7111 	s->rows = xmalloc((size + 1) * sizeof (char *));
7112 	if (!s->rows) {
7113 	    s->nrows = 0;
7114 	    return nomem(s);
7115 	}
7116 	s->rows[0] = (char *) size;
7117 	s->rows += 1;
7118 	memset(s->rows, 0, sizeof (char *) * size);
7119 	s->rowfree = freerows;
7120 	offs = 0;
7121 	for (i = 1; i <= nrows; i++) {
7122 	    int pos = 0, roffs = (offs + 1) * s->ncols;
7123 	    char *ptab = rowp[i * ncols + namec];
7124 	    char buf[32];
7125 
7126 	    if (plen && ptab) {
7127 		int len = strlen(ptab);
7128 
7129 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
7130 		    continue;
7131 		}
7132 	    }
7133 #if defined(_WIN32) || defined(_WIN64)
7134 	    s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
7135 	    s->rows[roffs + 1] = xstrdup("");
7136 #else
7137 	    s->rows[roffs + 0] = xstrdup("");
7138 	    s->rows[roffs + 1] = xstrdup("");
7139 #endif
7140 	    s->rows[roffs + 2] = xstrdup(ptab);
7141 	    s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
7142 	    s->rows[roffs + 4] = xstrdup("");
7143 	    s->rows[roffs + 5] = xstrdup("");
7144 	    s->rows[roffs + 6] = xstrdup(fname);
7145 	    s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
7146 	    sscanf(rowp[i * ncols + seqc], "%d", &pos);
7147 	    sprintf(buf, "%d", pos + 1);
7148 	    s->rows[roffs + 8] = xstrdup(buf);
7149 	    if (onu < 0) {
7150 		s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7151 	    } else {
7152 		if (strcmp(rowp[i * ncols + onu], "SET NULL") == 0) {
7153 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
7154 		} else if (strcmp(rowp[i * ncols + onu], "SET DEFAULT") == 0) {
7155 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_DEFAULT));
7156 		} else if (strcmp(rowp[i * ncols + onu], "CASCADE") == 0) {
7157 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
7158 		} else if (strcmp(rowp[i * ncols + onu], "RESTRICT") == 0) {
7159 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
7160 		} else {
7161 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7162 		}
7163 	    }
7164 	    if (ond < 0) {
7165 		s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7166 	    } else {
7167 		if (strcmp(rowp[i * ncols + ond], "SET NULL") == 0) {
7168 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
7169 		} else if (strcmp(rowp[i * ncols + ond], "SET DEFAULT") == 0) {
7170 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_DEFAULT));
7171 		} else if (strcmp(rowp[i * ncols + ond], "CASCADE") == 0) {
7172 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
7173 		} else if (strcmp(rowp[i * ncols + ond], "RESTRICT") == 0) {
7174 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
7175 		} else {
7176 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7177 		}
7178 	    }
7179 	    s->rows[roffs + 11] = NULL;
7180 	    s->rows[roffs + 12] = NULL;
7181 	    s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
7182 	    offs++;
7183 	}
7184 	freerows(rowp);
7185     } else {
7186 	int nnrows, nncols, plen = strlen(pname);
7187 	char **rowpp;
7188 
7189 	sql = "select name from sqlite_master where type='table'";
7190 	dbtraceapi(d, "sqlite4_get_table", sql);
7191 	ret = sqlite4_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
7192 	if (ret != SQLITE4_OK) {
7193 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7194 		    errp ? errp : "unknown error", ret);
7195 	    if (errp) {
7196 		sqlite4_free(0, errp);
7197 		errp = NULL;
7198 	    }
7199 	    return SQL_ERROR;
7200 	}
7201 	if (errp) {
7202 	    sqlite4_free(0, errp);
7203 	    errp = NULL;
7204 	}
7205 	if (ncols * nrows <= 0) {
7206 	    goto nodata;
7207 	}
7208 	size = 0;
7209 	for (i = 1; i <= nrows; i++) {
7210 	    int k;
7211 
7212 	    if (!rowp[i]) {
7213 		continue;
7214 	    }
7215 	    rowpp = NULL;
7216 	    ret = SQLITE4_ERROR;
7217 	    sql = sqlite4_mprintf(0, "PRAGMA foreign_key_list(%Q)", rowp[i]);
7218 	    if (sql) {
7219 		dbtraceapi(d, "sqlite4_get_table", sql);
7220 		ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
7221 				      &nnrows, &nncols, NULL);
7222 		sqlite4_free(0, sql);
7223 	    }
7224 	    if (ret != SQLITE4_OK || nncols * nnrows <= 0) {
7225 		freerows(rowpp);
7226 		continue;
7227 	    }
7228 	    namec = findcol(rowpp, nncols, "table");
7229 	    seqc = findcol(rowpp, nncols, "seq");
7230 	    fromc = findcol(rowpp, nncols, "from");
7231 	    toc = findcol(rowpp, nncols, "to");
7232 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
7233 		freerows(rowpp);
7234 		continue;
7235 	    }
7236 	    for (k = 1; k <= nnrows; k++) {
7237 		char *ptab = unquote(rowpp[k * nncols + namec]);
7238 
7239 		if (plen && ptab) {
7240 		    int len = strlen(ptab);
7241 
7242 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
7243 			continue;
7244 		    }
7245 		}
7246 		size++;
7247 	    }
7248 	    freerows(rowpp);
7249 	}
7250 	if (size == 0) {
7251 	    goto nodata;
7252 	}
7253 	s->nrows = size;
7254 	size = (size + 1) * asize;
7255 	s->rows = xmalloc((size + 1) * sizeof (char *));
7256 	if (!s->rows) {
7257 	    s->nrows = 0;
7258 	    return nomem(s);
7259 	}
7260 	s->rows[0] = (char *) size;
7261 	s->rows += 1;
7262 	memset(s->rows, 0, sizeof (char *) * size);
7263 	s->rowfree = freerows;
7264 	offs = 0;
7265 	for (i = 1; i <= nrows; i++) {
7266 	    int k;
7267 
7268 	    if (!rowp[i]) {
7269 		continue;
7270 	    }
7271 	    rowpp = NULL;
7272 	    ret = SQLITE4_ERROR;
7273 	    sql = sqlite4_mprintf(0, "PRAGMA foreign_key_list(%Q)", rowp[i]);
7274 	    if (sql) {
7275 		dbtraceapi(d, "sqlite4_get_table", sql);
7276 		ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
7277 					&nnrows, &nncols, NULL);
7278 		sqlite4_free(0, sql);
7279 	    }
7280 	    if (ret != SQLITE4_OK || nncols * nnrows <= 0) {
7281 		freerows(rowpp);
7282 		continue;
7283 	    }
7284 	    namec = findcol(rowpp, nncols, "table");
7285 	    seqc = findcol(rowpp, nncols, "seq");
7286 	    fromc = findcol(rowpp, nncols, "from");
7287 	    toc = findcol(rowpp, nncols, "to");
7288 	    onu = findcol(rowpp, nncols, "on_update");
7289 	    ond = findcol(rowpp, nncols, "on_delete");
7290 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
7291 		freerows(rowpp);
7292 		continue;
7293 	    }
7294 	    for (k = 1; k <= nnrows; k++) {
7295 		int pos = 0, roffs = (offs + 1) * s->ncols;
7296 		char *ptab = unquote(rowpp[k * nncols + namec]);
7297 		char buf[32];
7298 
7299 		if (plen && ptab) {
7300 		    int len = strlen(ptab);
7301 
7302 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
7303 			continue;
7304 		    }
7305 		}
7306 #if defined(_WIN32) || defined(_WIN64)
7307 		s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
7308 		s->rows[roffs + 1] = xstrdup("");
7309 #else
7310 		s->rows[roffs + 0] = xstrdup("");
7311 		s->rows[roffs + 1] = xstrdup("");
7312 #endif
7313 		s->rows[roffs + 2] = xstrdup(ptab);
7314 		s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
7315 		s->rows[roffs + 4] = xstrdup("");
7316 		s->rows[roffs + 5] = xstrdup("");
7317 		s->rows[roffs + 6] = xstrdup(rowp[i]);
7318 		s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
7319 		sscanf(rowpp[k * nncols + seqc], "%d", &pos);
7320 		sprintf(buf, "%d", pos + 1);
7321 		s->rows[roffs + 8] = xstrdup(buf);
7322 		if (onu < 0) {
7323 		    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
7324 		} else {
7325 		    if (strcmp(rowpp[k * nncols + onu], "SET NULL") == 0) {
7326 			s->rows[roffs + 9] = xstrdup(stringify(SQL_SET_NULL));
7327 		    } else if (strcmp(rowpp[k * nncols + onu], "SET DEFAULT")
7328 			       == 0) {
7329 			s->rows[roffs + 9] =
7330 			    xstrdup(stringify(SQL_SET_DEFAULT));
7331 		    } else if (strcmp(rowpp[k * nncols + onu], "CASCADE")
7332 			       == 0) {
7333 			s->rows[roffs + 9] = xstrdup(stringify(SQL_CASCADE));
7334 		    } else if (strcmp(rowpp[k * nncols + onu], "RESTRICT")
7335 			       == 0) {
7336 			s->rows[roffs + 9] = xstrdup(stringify(SQL_RESTRICT));
7337 		    } else {
7338 			s->rows[roffs + 9] =
7339 			    xstrdup(stringify(SQL_NO_ACTION));
7340 		    }
7341 		}
7342 		if (ond < 0) {
7343 		    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
7344 		} else {
7345 		    if (strcmp(rowpp[k * nncols + ond], "SET NULL") == 0) {
7346 			s->rows[roffs + 10] = xstrdup(stringify(SQL_SET_NULL));
7347 		    } else if (strcmp(rowpp[k * nncols + ond], "SET DEFAULT")
7348 			       == 0) {
7349 			s->rows[roffs + 10] =
7350 			    xstrdup(stringify(SQL_SET_DEFAULT));
7351 		    } else if (strcmp(rowpp[k * nncols + ond], "CASCADE")
7352 			       == 0) {
7353 			s->rows[roffs + 10] = xstrdup(stringify(SQL_CASCADE));
7354 		    } else if (strcmp(rowpp[k * nncols + ond], "RESTRICT")
7355 			       == 0) {
7356 			s->rows[roffs + 10] = xstrdup(stringify(SQL_RESTRICT));
7357 		    } else {
7358 			s->rows[roffs + 10] =
7359 			    xstrdup(stringify(SQL_NO_ACTION));
7360 		    }
7361 		}
7362 		s->rows[roffs + 11] = NULL;
7363 		s->rows[roffs + 12] = NULL;
7364 		s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
7365 		offs++;
7366 	    }
7367 	    freerows(rowpp);
7368 	}
7369 	freerows(rowp);
7370     }
7371     return SQL_SUCCESS;
7372 }
7373 
7374 #ifndef WINTERFACE
7375 /**
7376  * Retrieve information about primary/foreign keys.
7377  * @param stmt statement handle
7378  * @param PKcatalog primary key catalog name/pattern or NULL
7379  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7380  * @param PKschema primary key schema name/pattern or NULL
7381  * @param PKschemaLen length of PKschema or SQL_NTS
7382  * @param PKtable primary key table name/pattern or NULL
7383  * @param PKtableLen length of PKtable or SQL_NTS
7384  * @param FKcatalog foreign key catalog name/pattern or NULL
7385  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7386  * @param FKschema foreign key schema name/pattern or NULL
7387  * @param FKschemaLen length of FKschema or SQL_NTS
7388  * @param FKtable foreign key table name/pattern or NULL
7389  * @param FKtableLen length of FKtable or SQL_NTS
7390  * @result ODBC error code
7391  */
7392 
7393 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)7394 SQLForeignKeys(SQLHSTMT stmt,
7395 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7396 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
7397 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
7398 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7399 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
7400 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
7401 {
7402 #if defined(_WIN32) || defined(_WIN64)
7403     char *pc = NULL, *ps = NULL, *pt = NULL;
7404     char *fc = NULL, *fs = NULL, *ft = NULL;
7405 #endif
7406     SQLRETURN ret;
7407 
7408     HSTMT_LOCK(stmt);
7409 #if defined(_WIN32) || defined(_WIN64)
7410     if (!((STMT *) stmt)->oemcp[0]) {
7411 	ret = drvforeignkeys(stmt,
7412 			     PKcatalog, PKcatalogLen,
7413 			     PKschema, PKschemaLen, PKtable, PKtableLen,
7414 			     FKcatalog, FKcatalogLen,
7415 			     FKschema, FKschemaLen,
7416 			     FKtable, FKtableLen);
7417 	goto done2;
7418     }
7419     if (PKcatalog) {
7420 	pc = wmb_to_utf_c((char *) PKcatalog, PKcatalogLen);
7421 	if (!pc) {
7422 	    ret = nomem((STMT *) stmt);
7423 	    goto done;
7424 	}
7425     }
7426     if (PKschema) {
7427 	ps = wmb_to_utf_c((char *) PKschema, PKschemaLen);
7428 	if (!ps) {
7429 	    ret = nomem((STMT *) stmt);
7430 	    goto done;
7431 	}
7432     }
7433     if (PKtable) {
7434 	pt = wmb_to_utf_c((char *) PKtable, PKtableLen);
7435 	if (!pt) {
7436 	    ret = nomem((STMT *) stmt);
7437 	    goto done;
7438 	}
7439     }
7440     if (FKcatalog) {
7441 	fc = wmb_to_utf_c((char *) FKcatalog, FKcatalogLen);
7442 	if (!fc) {
7443 	    ret = nomem((STMT *) stmt);
7444 	    goto done;
7445 	}
7446     }
7447     if (FKschema) {
7448 	fs = wmb_to_utf_c((char *) FKschema, FKschemaLen);
7449 	if (!fs) {
7450 	    ret = nomem((STMT *) stmt);
7451 	    goto done;
7452 	}
7453     }
7454     if (FKtable) {
7455 	ft = wmb_to_utf_c((char *) FKtable, FKtableLen);
7456 	if (!ft) {
7457 	    ret = nomem((STMT *) stmt);
7458 	    goto done;
7459 	}
7460     }
7461     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
7462 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
7463 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
7464 			 (SQLCHAR *) ft, SQL_NTS);
7465 #else
7466     ret = drvforeignkeys(stmt,
7467 			 PKcatalog, PKcatalogLen,
7468 			 PKschema, PKschemaLen, PKtable, PKtableLen,
7469 			 FKcatalog, FKcatalogLen,
7470 			 FKschema, FKschemaLen,
7471 			 FKtable, FKtableLen);
7472 #endif
7473 #if defined(_WIN32) || defined(_WIN64)
7474 done:
7475     uc_free(ft);
7476     uc_free(fs);
7477     uc_free(fc);
7478     uc_free(pt);
7479     uc_free(ps);
7480     uc_free(pc);
7481 done2:
7482     ;
7483 #endif
7484     HSTMT_UNLOCK(stmt);
7485     return ret;
7486 }
7487 #endif
7488 
7489 #ifdef WINTERFACE
7490 /**
7491  * Retrieve information about primary/foreign keys (UNICODE version).
7492  * @param stmt statement handle
7493  * @param PKcatalog primary key catalog name/pattern or NULL
7494  * @param PKcatalogLen length of PKcatalog or SQL_NTS
7495  * @param PKschema primary key schema name/pattern or NULL
7496  * @param PKschemaLen length of PKschema or SQL_NTS
7497  * @param PKtable primary key table name/pattern or NULL
7498  * @param PKtableLen length of PKtable or SQL_NTS
7499  * @param FKcatalog foreign key catalog name/pattern or NULL
7500  * @param FKcatalogLen length of FKcatalog or SQL_NTS
7501  * @param FKschema foreign key schema name/pattern or NULL
7502  * @param FKschemaLen length of FKschema or SQL_NTS
7503  * @param FKtable foreign key table name/pattern or NULL
7504  * @param FKtableLen length of FKtable or SQL_NTS
7505  * @result ODBC error code
7506  */
7507 
7508 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)7509 SQLForeignKeysW(SQLHSTMT stmt,
7510 		SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
7511 		SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
7512 		SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
7513 		SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
7514 		SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
7515 		SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
7516 {
7517     char *pc = NULL, *ps = NULL, *pt = NULL;
7518     char *fc = NULL, *fs = NULL, *ft = NULL;
7519     SQLRETURN ret;
7520 
7521     HSTMT_LOCK(stmt);
7522     if (PKcatalog) {
7523 	pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
7524 	if (!pc) {
7525 	    ret = nomem((STMT *) stmt);
7526 	    goto done;
7527 	}
7528     }
7529     if (PKschema) {
7530 	ps = uc_to_utf_c(PKschema, PKschemaLen);
7531 	if (!ps) {
7532 	    ret = nomem((STMT *) stmt);
7533 	    goto done;
7534 	}
7535     }
7536     if (PKtable) {
7537 	pt = uc_to_utf_c(PKtable, PKtableLen);
7538 	if (!pt) {
7539 	    ret = nomem((STMT *) stmt);
7540 	    goto done;
7541 	}
7542     }
7543     if (FKcatalog) {
7544 	fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
7545 	if (!fc) {
7546 	    ret = nomem((STMT *) stmt);
7547 	    goto done;
7548 	}
7549     }
7550     if (FKschema) {
7551 	fs = uc_to_utf_c(FKschema, FKschemaLen);
7552 	if (!fs) {
7553 	    ret = nomem((STMT *) stmt);
7554 	    goto done;
7555 	}
7556     }
7557     if (FKtable) {
7558 	ft = uc_to_utf_c(FKtable, FKtableLen);
7559 	if (!ft) {
7560 	    ret = nomem((STMT *) stmt);
7561 	    goto done;
7562 	}
7563     }
7564     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
7565 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
7566 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
7567 			 (SQLCHAR *) ft, SQL_NTS);
7568 done:
7569     uc_free(ft);
7570     uc_free(fs);
7571     uc_free(fc);
7572     uc_free(pt);
7573     uc_free(ps);
7574     uc_free(pc);
7575     HSTMT_UNLOCK(stmt);
7576     return ret;
7577 }
7578 #endif
7579 
7580 /**
7581  * Start transaction when autocommit off
7582  * @param s statement pointer
7583  * @result ODBC error code
7584  */
7585 
7586 static SQLRETURN
starttran(STMT * s)7587 starttran(STMT *s)
7588 {
7589     int ret = SQL_SUCCESS, rc;
7590     char *errp = NULL;
7591     DBC *d = (DBC *) s->dbc;
7592 
7593     if (!d->autocommit && !d->intrans && !d->trans_disable) {
7594 	rc = sqlite4_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL);
7595 	dbtracerc(d, rc, NULL);
7596 	if (rc != SQLITE4_OK) {
7597 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
7598 		    errp ? errp : "unknown error", rc);
7599 	    ret = SQL_ERROR;
7600 	} else {
7601 	    d->intrans = 1;
7602 	}
7603 	if (errp) {
7604 	    sqlite4_free(0, errp);
7605 	    errp = NULL;
7606 	}
7607     }
7608     return ret;
7609 }
7610 
7611 /**
7612  * Internal commit or rollback transaction.
7613  * @param d database connection pointer
7614  * @param comptype type of transaction's end, SQL_COMMIT or SQL_ROLLBACK
7615  * @param force force action regardless of DBC's autocommit state
7616  * @result ODBC error code
7617  */
7618 
7619 static SQLRETURN
endtran(DBC * d,SQLSMALLINT comptype,int force)7620 endtran(DBC *d, SQLSMALLINT comptype, int force)
7621 {
7622     int ret;
7623     char *sql, *errp = NULL;
7624 
7625     if (!d->sqlite) {
7626 	setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
7627 	return SQL_ERROR;
7628     }
7629     if ((!force && d->autocommit) || !d->intrans) {
7630 	return SQL_SUCCESS;
7631     }
7632     switch (comptype) {
7633     case SQL_COMMIT:
7634 	sql = "COMMIT TRANSACTION";
7635 	goto doit;
7636     case SQL_ROLLBACK:
7637 	sql = "ROLLBACK TRANSACTION";
7638     doit:
7639 	ret = sqlite4_exec(d->sqlite, sql, NULL, NULL);
7640 	dbtracerc(d, ret, NULL);
7641 	if (ret != SQLITE4_OK) {
7642 	    setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
7643 		     errp ? errp : "transaction failed");
7644 	    if (errp) {
7645 		sqlite4_free(0, errp);
7646 		errp = NULL;
7647 	    }
7648 	    return SQL_ERROR;
7649 	}
7650 	if (errp) {
7651 	    sqlite4_free(0, errp);
7652 	    errp = NULL;
7653 	}
7654 	d->intrans = 0;
7655 	return SQL_SUCCESS;
7656     }
7657     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
7658     return SQL_ERROR;
7659 }
7660 
7661 /**
7662  * Internal commit or rollback transaction.
7663  * @param type type of handle
7664  * @param handle HDBC, HENV, or HSTMT handle
7665  * @param comptype SQL_COMMIT or SQL_ROLLBACK
7666  * @result ODBC error code
7667  */
7668 
7669 static SQLRETURN
drvendtran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)7670 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
7671 {
7672     DBC *dbc = NULL;
7673     int fail = 0;
7674     SQLRETURN ret;
7675 #if defined(_WIN32) || defined(_WIN64)
7676     ENV *env;
7677 #endif
7678 
7679     switch (type) {
7680     case SQL_HANDLE_DBC:
7681 	HDBC_LOCK((SQLHDBC) handle);
7682 	if (handle == SQL_NULL_HDBC) {
7683 	    return SQL_INVALID_HANDLE;
7684 	}
7685 	dbc = (DBC *) handle;
7686 	ret = endtran(dbc, comptype, 0);
7687 	HDBC_UNLOCK((SQLHDBC) handle);
7688 	return ret;
7689     case SQL_HANDLE_ENV:
7690 	if (handle == SQL_NULL_HENV) {
7691 	    return SQL_INVALID_HANDLE;
7692 	}
7693 #if defined(_WIN32) || defined(_WIN64)
7694 	env = (ENV *) handle;
7695 	if (env->magic != ENV_MAGIC) {
7696 	    return SQL_INVALID_HANDLE;
7697 	}
7698 	EnterCriticalSection(&env->cs);
7699 #endif
7700 	dbc = ((ENV *) handle)->dbcs;
7701 	while (dbc) {
7702 	    HDBC_LOCK((SQLHDBC) dbc);
7703 	    ret = endtran(dbc, comptype, 0);
7704 	    HDBC_UNLOCK((SQLHDBC) dbc);
7705 	    if (ret != SQL_SUCCESS) {
7706 		fail++;
7707 	    }
7708 	    dbc = dbc->next;
7709 	}
7710 #if defined(_WIN32) || defined(_WIN64)
7711 	LeaveCriticalSection(&env->cs);
7712 #endif
7713 	return fail ? SQL_ERROR : SQL_SUCCESS;
7714     }
7715     return SQL_INVALID_HANDLE;
7716 }
7717 
7718 /**
7719  * Commit or rollback transaction.
7720  * @param type type of handle
7721  * @param handle HDBC, HENV, or HSTMT handle
7722  * @param comptype SQL_COMMIT or SQL_ROLLBACK
7723  * @result ODBC error code
7724  */
7725 
7726 SQLRETURN SQL_API
SQLEndTran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)7727 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
7728 {
7729     return drvendtran(type, handle, comptype);
7730 }
7731 
7732 /**
7733  * Commit or rollback transaction.
7734  * @param env environment handle or NULL
7735  * @param dbc database connection handle or NULL
7736  * @param type SQL_COMMIT or SQL_ROLLBACK
7737  * @result ODBC error code
7738  */
7739 
7740 SQLRETURN SQL_API
SQLTransact(SQLHENV env,SQLHDBC dbc,SQLUSMALLINT type)7741 SQLTransact(SQLHENV env, SQLHDBC dbc, SQLUSMALLINT type)
7742 {
7743     if (dbc != SQL_NULL_HDBC) {
7744 	return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
7745     }
7746     return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
7747 }
7748 
7749 /**
7750  * Function not implemented.
7751  */
7752 
7753 SQLRETURN SQL_API
SQLCopyDesc(SQLHDESC source,SQLHDESC target)7754 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
7755 {
7756     return SQL_ERROR;
7757 }
7758 
7759 #ifndef WINTERFACE
7760 /**
7761  * Translate SQL string.
7762  * @param stmt statement handle
7763  * @param sqlin input string
7764  * @param sqlinLen length of input string
7765  * @param sql output string
7766  * @param sqlMax max space in output string
7767  * @param sqlLen value return for length of output string
7768  * @result ODBC error code
7769  */
7770 
7771 SQLRETURN SQL_API
SQLNativeSql(SQLHSTMT stmt,SQLCHAR * sqlin,SQLINTEGER sqlinLen,SQLCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)7772 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
7773 	     SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
7774 {
7775     int outLen = 0;
7776     SQLRETURN ret = SQL_SUCCESS;
7777 
7778     HSTMT_LOCK(stmt);
7779     if (sqlinLen == SQL_NTS) {
7780 	sqlinLen = strlen((char *) sqlin);
7781     }
7782     if (sql) {
7783 	if (sqlMax > 0) {
7784 	    strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
7785 	    sqlin[sqlMax - 1] = '\0';
7786 	    outLen = min(sqlMax - 1, sqlinLen);
7787 	}
7788     } else {
7789 	outLen = sqlinLen;
7790     }
7791     if (sqlLen) {
7792 	*sqlLen = outLen;
7793     }
7794     if (sql && outLen < sqlinLen) {
7795 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
7796 	ret = SQL_SUCCESS_WITH_INFO;
7797     }
7798     HSTMT_UNLOCK(stmt);
7799     return ret;
7800 }
7801 #endif
7802 
7803 #ifdef WINTERFACE
7804 /**
7805  * Translate SQL string (UNICODE version).
7806  * @param stmt statement handle
7807  * @param sqlin input string
7808  * @param sqlinLen length of input string
7809  * @param sql output string
7810  * @param sqlMax max space in output string
7811  * @param sqlLen value return for length of output string
7812  * @result ODBC error code
7813  */
7814 
7815 SQLRETURN SQL_API
SQLNativeSqlW(SQLHSTMT stmt,SQLWCHAR * sqlin,SQLINTEGER sqlinLen,SQLWCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)7816 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
7817 	      SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
7818 {
7819     int outLen = 0;
7820     SQLRETURN ret = SQL_SUCCESS;
7821 
7822     HSTMT_LOCK(stmt);
7823     if (sqlinLen == SQL_NTS) {
7824 	sqlinLen = uc_strlen(sqlin);
7825     }
7826     if (sql) {
7827 	if (sqlMax > 0) {
7828 	    uc_strncpy(sql, sqlin, sqlMax - 1);
7829 	    sqlin[sqlMax - 1] = 0;
7830 	    outLen = min(sqlMax  - 1, sqlinLen);
7831 	}
7832     } else {
7833 	outLen = sqlinLen;
7834     }
7835     if (sqlLen) {
7836 	*sqlLen = outLen;
7837     }
7838     if (sql && outLen < sqlinLen) {
7839 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
7840 	ret = SQL_SUCCESS_WITH_INFO;
7841     }
7842     HSTMT_UNLOCK(stmt);
7843     return ret;
7844 }
7845 #endif
7846 
7847 /**
7848  * Columns for result set of SQLProcedures().
7849  */
7850 
7851 static COL procSpec2[] = {
7852     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
7853     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
7854     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7855     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
7856     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
7857     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
7858     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
7859     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
7860 };
7861 
7862 static COL procSpec3[] = {
7863     { "SYSTEM", "PROCEDURE", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
7864     { "SYSTEM", "PROCEDURE", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
7865     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7866     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
7867     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
7868     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
7869     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
7870     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
7871 };
7872 
7873 #ifndef WINTERFACE
7874 /**
7875  * Retrieve information about stored procedures.
7876  * @param stmt statement handle
7877  * @param catalog catalog name/pattern or NULL
7878  * @param catalogLen length of catalog or SQL_NTS
7879  * @param schema schema name/pattern or NULL
7880  * @param schemaLen length of schema or SQL_NTS
7881  * @param proc procedure name/pattern or NULL
7882  * @param procLen length of proc or SQL_NTS
7883  * @result ODBC error code
7884  */
7885 
7886 SQLRETURN SQL_API
SQLProcedures(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen)7887 SQLProcedures(SQLHSTMT stmt,
7888 	      SQLCHAR *catalog, SQLSMALLINT catalogLen,
7889 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
7890 	      SQLCHAR *proc, SQLSMALLINT procLen)
7891 {
7892     SQLRETURN ret;
7893 
7894     HSTMT_LOCK(stmt);
7895     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
7896 		      procSpec3, array_size(procSpec3), NULL);
7897     HSTMT_UNLOCK(stmt);
7898     return ret;
7899 }
7900 #endif
7901 
7902 #ifdef WINTERFACE
7903 /**
7904  * Retrieve information about stored procedures (UNICODE version).
7905  * @param stmt statement handle
7906  * @param catalog catalog name/pattern or NULL
7907  * @param catalogLen length of catalog or SQL_NTS
7908  * @param schema schema name/pattern or NULL
7909  * @param schemaLen length of schema or SQL_NTS
7910  * @param proc procedure name/pattern or NULL
7911  * @param procLen length of proc or SQL_NTS
7912  * @result ODBC error code
7913  */
7914 
7915 SQLRETURN SQL_API
SQLProceduresW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen)7916 SQLProceduresW(SQLHSTMT stmt,
7917 	       SQLWCHAR *catalog, SQLSMALLINT catalogLen,
7918 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
7919 	       SQLWCHAR *proc, SQLSMALLINT procLen)
7920 {
7921     SQLRETURN ret;
7922 
7923     HSTMT_LOCK(stmt);
7924     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
7925 		      procSpec3, array_size(procSpec3), NULL);
7926     HSTMT_UNLOCK(stmt);
7927     return ret;
7928 }
7929 #endif
7930 
7931 /**
7932  * Columns for result set of SQLProcedureColumns().
7933  */
7934 
7935 static COL procColSpec2[] = {
7936     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
7937     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
7938     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7939     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
7940     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
7941     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
7942     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
7943     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
7944     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
7945     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
7946     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
7947     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
7948     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
7949     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
7950     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
7951     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
7952     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
7953     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
7954     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
7955 };
7956 
7957 static COL procColSpec3[] = {
7958     { "SYSTEM", "PROCCOL", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
7959     { "SYSTEM", "PROCCOL", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
7960     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
7961     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
7962     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
7963     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
7964     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
7965     { "SYSTEM", "PROCCOL", "COLUMN_SIZE", SQL_INTEGER, 10 },
7966     { "SYSTEM", "PROCCOL", "BUFFER_LENGTH", SQL_INTEGER, 10 },
7967     { "SYSTEM", "PROCCOL", "DECIMAL_DIGITS", SQL_SMALLINT, 5 },
7968     { "SYSTEM", "PROCCOL", "NUM_PREC_RADIX", SQL_SMALLINT, 5 },
7969     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
7970     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
7971     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
7972     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
7973     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
7974     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
7975     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
7976     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
7977 };
7978 
7979 #ifndef WINTERFACE
7980 /**
7981  * Retrieve information about columns in result set of stored procedures.
7982  * @param stmt statement handle
7983  * @param catalog catalog name/pattern or NULL
7984  * @param catalogLen length of catalog or SQL_NTS
7985  * @param schema schema name/pattern or NULL
7986  * @param schemaLen length of schema or SQL_NTS
7987  * @param proc procedure name/pattern or NULL
7988  * @param procLen length of proc or SQL_NTS
7989  * @param column column name/pattern or NULL
7990  * @param columnLen length of column or SQL_NTS
7991  * @result ODBC error code
7992  */
7993 
7994 SQLRETURN SQL_API
SQLProcedureColumns(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen,SQLCHAR * column,SQLSMALLINT columnLen)7995 SQLProcedureColumns(SQLHSTMT stmt,
7996 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
7997 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
7998 		    SQLCHAR *proc, SQLSMALLINT procLen,
7999 		    SQLCHAR *column, SQLSMALLINT columnLen)
8000 {
8001     SQLRETURN ret;
8002 
8003     HSTMT_LOCK(stmt);
8004     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
8005 		      procColSpec3, array_size(procColSpec3), NULL);
8006     HSTMT_UNLOCK(stmt);
8007     return ret;
8008 }
8009 #endif
8010 
8011 #ifdef WINTERFACE
8012 /**
8013  * Retrieve information about columns in result
8014  * set of stored procedures (UNICODE version).
8015  * @param stmt statement handle
8016  * @param catalog catalog name/pattern or NULL
8017  * @param catalogLen length of catalog or SQL_NTS
8018  * @param schema schema name/pattern or NULL
8019  * @param schemaLen length of schema or SQL_NTS
8020  * @param proc procedure name/pattern or NULL
8021  * @param procLen length of proc or SQL_NTS
8022  * @param column column name/pattern or NULL
8023  * @param columnLen length of column or SQL_NTS
8024  * @result ODBC error code
8025  */
8026 
8027 SQLRETURN SQL_API
SQLProcedureColumnsW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen,SQLWCHAR * column,SQLSMALLINT columnLen)8028 SQLProcedureColumnsW(SQLHSTMT stmt,
8029 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
8030 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
8031 		     SQLWCHAR *proc, SQLSMALLINT procLen,
8032 		     SQLWCHAR *column, SQLSMALLINT columnLen)
8033 {
8034     SQLRETURN ret;
8035 
8036     HSTMT_LOCK(stmt);
8037     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
8038 		      procColSpec3, array_size(procColSpec3), NULL);
8039     HSTMT_UNLOCK(stmt);
8040     return ret;
8041 }
8042 #endif
8043 
8044 /**
8045  * Get information of HENV.
8046  * @param env environment handle
8047  * @param attr attribute to be retrieved
8048  * @param val output buffer
8049  * @param len length of output buffer
8050  * @param lenp output length
8051  * @result ODBC error code
8052  */
8053 
8054 SQLRETURN SQL_API
SQLGetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len,SQLINTEGER * lenp)8055 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
8056 	      SQLINTEGER len, SQLINTEGER *lenp)
8057 {
8058     ENV *e;
8059     SQLRETURN ret = SQL_ERROR;
8060 
8061     if (env == SQL_NULL_HENV) {
8062 	return SQL_INVALID_HANDLE;
8063     }
8064     e = (ENV *) env;
8065     if (!e || e->magic != ENV_MAGIC) {
8066 	return SQL_INVALID_HANDLE;
8067     }
8068 #if defined(_WIN32) || defined(_WIN64)
8069     EnterCriticalSection(&e->cs);
8070 #endif
8071     switch (attr) {
8072     case SQL_ATTR_CONNECTION_POOLING:
8073 	if (val) {
8074 	    *((SQLINTEGER *) val) = e->pool ?
8075 		SQL_CP_ONE_PER_DRIVER : SQL_CP_OFF;
8076 	}
8077 	if (lenp) {
8078 	    *lenp = sizeof (SQLINTEGER);
8079 	}
8080 	ret = SQL_SUCCESS;
8081 	break;
8082     case SQL_ATTR_CP_MATCH:
8083 	*((SQLINTEGER *) val) = SQL_CP_RELAXED_MATCH;
8084 	if (lenp) {
8085 	    *lenp = sizeof (SQLINTEGER);
8086 	}
8087 	ret = SQL_SUCCESS;
8088 	break;
8089     case SQL_ATTR_OUTPUT_NTS:
8090 	if (val) {
8091 	    *((SQLINTEGER *) val) = SQL_TRUE;
8092 	}
8093 	if (lenp) {
8094 	    *lenp = sizeof (SQLINTEGER);
8095 	}
8096 	ret = SQL_SUCCESS;
8097 	break;
8098     case SQL_ATTR_ODBC_VERSION:
8099 	if (val) {
8100 	    *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
8101 	}
8102 	if (lenp) {
8103 	    *lenp = sizeof (SQLINTEGER);
8104 	}
8105 	ret = SQL_SUCCESS;
8106 	break;
8107     }
8108 #if defined(_WIN32) || defined(_WIN64)
8109     LeaveCriticalSection(&e->cs);
8110 #endif
8111     return ret;
8112 }
8113 
8114 /**
8115  * Set information in HENV.
8116  * @param env environment handle
8117  * @param attr attribute to be retrieved
8118  * @param val parameter buffer
8119  * @param len length of parameter
8120  * @result ODBC error code
8121  */
8122 
8123 SQLRETURN SQL_API
SQLSetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)8124 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
8125 {
8126     ENV *e;
8127     SQLRETURN ret = SQL_ERROR;
8128 
8129     if (env == SQL_NULL_HENV) {
8130 	return SQL_INVALID_HANDLE;
8131     }
8132     e = (ENV *) env;
8133     if (!e || e->magic != ENV_MAGIC) {
8134 	return SQL_INVALID_HANDLE;
8135     }
8136 #if defined(_WIN32) || defined(_WIN64)
8137     EnterCriticalSection(&e->cs);
8138 #endif
8139     switch (attr) {
8140     case SQL_ATTR_CONNECTION_POOLING:
8141 	if (val == (SQLPOINTER) SQL_CP_ONE_PER_DRIVER) {
8142 	    e->pool = 1;
8143 	    ret = SQL_SUCCESS;
8144 	} else if (val == (SQLPOINTER) SQL_CP_OFF) {
8145 	    e->pool = 0;
8146 	    ret = SQL_SUCCESS;
8147 	}
8148 	break;
8149     case SQL_ATTR_CP_MATCH:
8150 	ret = SQL_SUCCESS;
8151 	break;
8152     case SQL_ATTR_OUTPUT_NTS:
8153 	if (val == (SQLPOINTER) SQL_TRUE) {
8154 	    ret = SQL_SUCCESS;
8155 	}
8156 	break;
8157     case SQL_ATTR_ODBC_VERSION:
8158 	if (!val) {
8159 	    break;
8160 	}
8161 	if (val == (SQLPOINTER) SQL_OV_ODBC2) {
8162 	    e->ov3 = 0;
8163 	    ret = SQL_SUCCESS;
8164 	} else if (val == (SQLPOINTER) SQL_OV_ODBC3) {
8165 	    e->ov3 = 1;
8166 	    ret = SQL_SUCCESS;
8167 	}
8168 	break;
8169     }
8170 #if defined(_WIN32) || defined(_WIN64)
8171     LeaveCriticalSection(&e->cs);
8172 #endif
8173     return ret;
8174 }
8175 
8176 /**
8177  * Internal get error message given handle (HENV, HDBC, or HSTMT).
8178  * @param htype handle type
8179  * @param handle HENV, HDBC, or HSTMT
8180  * @param recno
8181  * @param sqlstate output buffer for SQL state
8182  * @param nativeerr output buffer of native error code
8183  * @param msg output buffer for error message
8184  * @param buflen length of output buffer
8185  * @param msglen output length
8186  * @result ODBC error code
8187  */
8188 
8189 static SQLRETURN
drvgetdiagrec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8190 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8191 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
8192 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8193 {
8194     DBC *d = NULL;
8195     STMT *s = NULL;
8196     int len, naterr;
8197     char *logmsg, *sqlst;
8198     SQLRETURN ret = SQL_ERROR;
8199 
8200     if (handle == SQL_NULL_HANDLE) {
8201 	return SQL_INVALID_HANDLE;
8202     }
8203     if (sqlstate) {
8204 	sqlstate[0] = '\0';
8205     }
8206     if (msg && buflen > 0) {
8207 	msg[0] = '\0';
8208     }
8209     if (msglen) {
8210 	*msglen = 0;
8211     }
8212     if (nativeerr) {
8213 	*nativeerr = 0;
8214     }
8215     switch (htype) {
8216     case SQL_HANDLE_ENV:
8217     case SQL_HANDLE_DESC:
8218 	return SQL_NO_DATA;
8219     case SQL_HANDLE_DBC:
8220 	HDBC_LOCK((SQLHDBC) handle);
8221 	d = (DBC *) handle;
8222 	logmsg = (char *) d->logmsg;
8223 	sqlst = d->sqlstate;
8224 	naterr = d->naterr;
8225 	break;
8226     case SQL_HANDLE_STMT:
8227 	HSTMT_LOCK((SQLHSTMT) handle);
8228 	s = (STMT *) handle;
8229 	logmsg = (char *) s->logmsg;
8230 	sqlst = s->sqlstate;
8231 	naterr = s->naterr;
8232 	break;
8233     default:
8234 	return SQL_INVALID_HANDLE;
8235     }
8236     if (buflen < 0) {
8237 	goto done;
8238     }
8239     if (recno > 1) {
8240 	ret = SQL_NO_DATA;
8241 	goto done;
8242     }
8243     len = strlen(logmsg);
8244     if (len == 0) {
8245 	ret = SQL_NO_DATA;
8246 	goto done;
8247     }
8248     if (nativeerr) {
8249 	*nativeerr = naterr;
8250     }
8251     if (sqlstate) {
8252 	strcpy((char *) sqlstate, sqlst);
8253     }
8254     if (msglen) {
8255 	*msglen = len;
8256     }
8257     if (len >= buflen) {
8258 	if (msg && buflen > 0) {
8259 	    strncpy((char *) msg, logmsg, buflen);
8260 	    msg[buflen - 1] = '\0';
8261 	    logmsg[0] = '\0';
8262 	}
8263     } else if (msg) {
8264 	strcpy((char *) msg, logmsg);
8265 	logmsg[0] = '\0';
8266     }
8267     ret = SQL_SUCCESS;
8268 done:
8269     switch (htype) {
8270     case SQL_HANDLE_DBC:
8271 	HDBC_UNLOCK((SQLHDBC) handle);
8272 	break;
8273     case SQL_HANDLE_STMT:
8274 	HSTMT_UNLOCK((SQLHSTMT) handle);
8275 	break;
8276     }
8277     return ret;
8278 }
8279 
8280 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
8281 /**
8282  * Get error message given handle (HENV, HDBC, or HSTMT).
8283  * @param htype handle type
8284  * @param handle HENV, HDBC, or HSTMT
8285  * @param recno
8286  * @param sqlstate output buffer for SQL state
8287  * @param nativeerr output buffer of native error code
8288  * @param msg output buffer for error message
8289  * @param buflen length of output buffer
8290  * @param msglen output length
8291  * @result ODBC error code
8292  */
8293 
8294 SQLRETURN SQL_API
SQLGetDiagRec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8295 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8296 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
8297 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8298 {
8299     return drvgetdiagrec(htype, handle, recno, sqlstate,
8300 			 nativeerr, msg, buflen, msglen);
8301 }
8302 #endif
8303 
8304 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
8305 #ifdef WINTERFACE
8306 /**
8307  * Get error message given handle (HENV, HDBC, or HSTMT)
8308  * (UNICODE version).
8309  * @param htype handle type
8310  * @param handle HENV, HDBC, or HSTMT
8311  * @param recno
8312  * @param sqlstate output buffer for SQL state
8313  * @param nativeerr output buffer of native error code
8314  * @param msg output buffer for error message
8315  * @param buflen length of output buffer
8316  * @param msglen output length
8317  * @result ODBC error code
8318  */
8319 
8320 SQLRETURN SQL_API
SQLGetDiagRecW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLWCHAR * sqlstate,SQLINTEGER * nativeerr,SQLWCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)8321 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8322 	      SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
8323 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
8324 {
8325     char state[16];
8326     SQLSMALLINT len;
8327     SQLRETURN ret;
8328 
8329     ret = drvgetdiagrec(htype, handle, recno, (SQLCHAR *) state,
8330 			nativeerr, (SQLCHAR *) msg, buflen, &len);
8331     if (ret == SQL_SUCCESS) {
8332 	if (sqlstate) {
8333 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlstate,
8334 			    6 * sizeof (SQLWCHAR));
8335 	}
8336 	if (msg) {
8337 	    if (len > 0) {
8338 		SQLWCHAR *m = NULL;
8339 
8340 		m = uc_from_utf((unsigned char *) msg, len);
8341 		if (m) {
8342 		    if (buflen) {
8343 			buflen /= sizeof (SQLWCHAR);
8344 			uc_strncpy(msg, m, buflen);
8345 			m[len] = 0;
8346 			len = min(buflen, uc_strlen(m));
8347 		    } else {
8348 			len = uc_strlen(m);
8349 		    }
8350 		    uc_free(m);
8351 		} else {
8352 		    len = 0;
8353 		}
8354 	    }
8355 	    if (len <= 0) {
8356 		len = 0;
8357 		if (buflen > 0) {
8358 		    msg[0] = 0;
8359 		}
8360 	    }
8361 	} else {
8362 	    /* estimated length !!! */
8363 	    len *= sizeof (SQLWCHAR);
8364 	}
8365 	if (msglen) {
8366 	    *msglen = len;
8367 	}
8368     } else if (ret == SQL_NO_DATA) {
8369 	if (sqlstate) {
8370 	    sqlstate[0] = 0;
8371 	}
8372 	if (msg) {
8373 	    if (buflen > 0) {
8374 		msg[0] = 0;
8375 	    }
8376 	}
8377 	if (msglen) {
8378 	    *msglen = 0;
8379 	}
8380     }
8381     return ret;
8382 }
8383 #endif
8384 #endif
8385 
8386 /**
8387  * Get error record given handle (HDBC or HSTMT).
8388  * @param htype handle type
8389  * @param handle HDBC or HSTMT
8390  * @param recno diag record number for which info to be retrieved
8391  * @param id diag id for which info to be retrieved
8392  * @param info output buffer for error message
8393  * @param buflen length of output buffer
8394  * @param stringlen output length
8395  * @result ODBC error code
8396  */
8397 
8398 static SQLRETURN
drvgetdiagfield(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8399 drvgetdiagfield(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8400 		SQLSMALLINT id, SQLPOINTER info,
8401 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8402 {
8403     DBC *d = NULL;
8404     STMT *s = NULL;
8405     int len, naterr, strbuf = 1;
8406     char *logmsg, *sqlst, *clrmsg = NULL;
8407     SQLRETURN ret = SQL_ERROR;
8408 
8409     if (handle == SQL_NULL_HANDLE) {
8410 	return SQL_INVALID_HANDLE;
8411     }
8412     if (stringlen) {
8413 	*stringlen = 0;
8414     }
8415     switch (htype) {
8416     case SQL_HANDLE_ENV:
8417     case SQL_HANDLE_DESC:
8418 	return SQL_NO_DATA;
8419     case SQL_HANDLE_DBC:
8420 	HDBC_LOCK((SQLHDBC) handle);
8421 	d = (DBC *) handle;
8422 	logmsg = (char *) d->logmsg;
8423 	sqlst = d->sqlstate;
8424 	naterr = d->naterr;
8425 	break;
8426     case SQL_HANDLE_STMT:
8427 	HSTMT_LOCK((SQLHSTMT) handle);
8428 	s = (STMT *) handle;
8429 	d = (DBC *) s->dbc;
8430 	logmsg = (char *) s->logmsg;
8431 	sqlst = s->sqlstate;
8432 	naterr = s->naterr;
8433 	break;
8434     default:
8435 	return SQL_INVALID_HANDLE;
8436     }
8437     if (buflen < 0) {
8438 	switch (buflen) {
8439 	case SQL_IS_POINTER:
8440 	case SQL_IS_UINTEGER:
8441 	case SQL_IS_INTEGER:
8442 	case SQL_IS_USMALLINT:
8443 	case SQL_IS_SMALLINT:
8444 	    strbuf = 0;
8445 	    break;
8446 	default:
8447 	    ret = SQL_ERROR;
8448 	    goto done;
8449 	}
8450     }
8451     if (recno > 1) {
8452 	ret = SQL_NO_DATA;
8453 	goto done;
8454     }
8455     switch (id) {
8456     case SQL_DIAG_CLASS_ORIGIN:
8457 	logmsg = "ISO 9075";
8458 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
8459 	    logmsg = "ODBC 3.0";
8460 	}
8461 	break;
8462     case SQL_DIAG_SUBCLASS_ORIGIN:
8463 	logmsg = "ISO 9075";
8464 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
8465 	    logmsg = "ODBC 3.0";
8466 	} else if (sqlst[0] == 'H' && sqlst[1] == 'Y') {
8467 	    logmsg = "ODBC 3.0";
8468 	} else if (sqlst[0] == '2' || sqlst[0] == '0' || sqlst[0] == '4') {
8469 	    logmsg = "ODBC 3.0";
8470 	}
8471 	break;
8472     case SQL_DIAG_CONNECTION_NAME:
8473     case SQL_DIAG_SERVER_NAME:
8474 	logmsg = d->dsn ? d->dsn : "No DSN";
8475 	break;
8476     case SQL_DIAG_SQLSTATE:
8477 	logmsg = sqlst;
8478 	break;
8479     case SQL_DIAG_MESSAGE_TEXT:
8480 	if (info) {
8481 	    clrmsg = logmsg;
8482 	}
8483 	break;
8484     case SQL_DIAG_NUMBER:
8485 	naterr = 1;
8486 	/* fall through */
8487     case SQL_DIAG_NATIVE:
8488 	len = strlen(logmsg);
8489 	if (len == 0) {
8490 	    ret = SQL_NO_DATA;
8491 	    goto done;
8492 	}
8493 	if (info) {
8494 	    *((SQLINTEGER *) info) = naterr;
8495 	}
8496 	ret = SQL_SUCCESS;
8497 	goto done;
8498     case SQL_DIAG_DYNAMIC_FUNCTION:
8499 	logmsg = "";
8500 	break;
8501     case SQL_DIAG_CURSOR_ROW_COUNT:
8502 	if (htype == SQL_HANDLE_STMT) {
8503 	    SQLULEN count;
8504 
8505 	    count = (s->isselect == 1 || s->isselect == -1) ? s->nrows : 0;
8506 	    *((SQLULEN *) info) = count;
8507 	    ret = SQL_SUCCESS;
8508 	}
8509 	goto done;
8510     case SQL_DIAG_ROW_COUNT:
8511 	if (htype == SQL_HANDLE_STMT) {
8512 	    SQLULEN count;
8513 
8514 	    count = s->isselect ? 0 : s->nrows;
8515 	    *((SQLULEN *) info) = count;
8516 	    ret = SQL_SUCCESS;
8517 	}
8518 	goto done;
8519     default:
8520 	goto done;
8521     }
8522     if (info && buflen > 0) {
8523 	((char *) info)[0] = '\0';
8524     }
8525     len = strlen(logmsg);
8526     if (len == 0) {
8527 	ret = SQL_NO_DATA;
8528 	goto done;
8529     }
8530     if (stringlen) {
8531 	*stringlen = len;
8532     }
8533     if (strbuf) {
8534 	if (len >= buflen) {
8535 	    if (info && buflen > 0) {
8536 		if (stringlen) {
8537 		    *stringlen = buflen - 1;
8538 		}
8539 		strncpy((char *) info, logmsg, buflen);
8540 		((char *) info)[buflen - 1] = '\0';
8541 	    }
8542 	} else if (info) {
8543 	    strcpy((char *) info, logmsg);
8544 	}
8545     }
8546     if (clrmsg) {
8547 	*clrmsg = '\0';
8548     }
8549     ret = SQL_SUCCESS;
8550 done:
8551     switch (htype) {
8552     case SQL_HANDLE_DBC:
8553 	HDBC_UNLOCK((SQLHDBC) handle);
8554 	break;
8555     case SQL_HANDLE_STMT:
8556 	HSTMT_UNLOCK((SQLHSTMT) handle);
8557 	break;
8558     }
8559     return ret;
8560 }
8561 
8562 #ifndef WINTERFACE
8563 /**
8564  * Get error record given handle (HDBC or HSTMT).
8565  * @param htype handle type
8566  * @param handle HDBC or HSTMT
8567  * @param recno diag record number for which info to be retrieved
8568  * @param id diag id for which info to be retrieved
8569  * @param info output buffer for error message
8570  * @param buflen length of output buffer
8571  * @param stringlen output length
8572  * @result ODBC error code
8573  */
8574 
8575 SQLRETURN SQL_API
SQLGetDiagField(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8576 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8577 		SQLSMALLINT id, SQLPOINTER info,
8578 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8579 {
8580     return drvgetdiagfield(htype, handle, recno, id, info, buflen, stringlen);
8581 }
8582 #endif
8583 
8584 #ifdef WINTERFACE
8585 /**
8586  * Get error record given handle (HDBC or HSTMT).
8587  * @param htype handle type
8588  * @param handle HDBC or HSTMT
8589  * @param recno diag record number for which info to be retrieved
8590  * @param id diag id for which info to be retrieved
8591  * @param info output buffer for error message
8592  * @param buflen length of output buffer
8593  * @param stringlen output length
8594  * @result ODBC error code
8595  */
8596 
8597 SQLRETURN SQL_API
SQLGetDiagFieldW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)8598 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
8599 		 SQLSMALLINT id, SQLPOINTER info,
8600 		 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
8601 {
8602     SQLSMALLINT len;
8603     SQLRETURN ret;
8604 
8605     ret = drvgetdiagfield(htype, handle, recno, id, info, buflen, &len);
8606     if (ret == SQL_SUCCESS) {
8607 	if (info) {
8608 	    switch (id) {
8609 	    case SQL_DIAG_CLASS_ORIGIN:
8610 	    case SQL_DIAG_SUBCLASS_ORIGIN:
8611 	    case SQL_DIAG_CONNECTION_NAME:
8612 	    case SQL_DIAG_SERVER_NAME:
8613 	    case SQL_DIAG_SQLSTATE:
8614 	    case SQL_DIAG_MESSAGE_TEXT:
8615 	    case SQL_DIAG_DYNAMIC_FUNCTION:
8616 		if (len > 0) {
8617 		    SQLWCHAR *m = NULL;
8618 
8619 		    m = uc_from_utf((unsigned char *) info, len);
8620 		    if (m) {
8621 			if (buflen) {
8622 			    buflen /= sizeof (SQLWCHAR);
8623 			    uc_strncpy(info, m, buflen);
8624 			    m[len] = 0;
8625 			    len = min(buflen, uc_strlen(m));
8626 			} else {
8627 			    len = uc_strlen(m);
8628 			}
8629 			uc_free(m);
8630 			len *= sizeof (SQLWCHAR);
8631 		    } else {
8632 			len = 0;
8633 		    }
8634 		}
8635 		if (len <= 0) {
8636 		    len = 0;
8637 		    if (buflen > 0) {
8638 			((SQLWCHAR *) info)[0] = 0;
8639 		    }
8640 		}
8641 	    }
8642 	} else {
8643 	    switch (id) {
8644 	    case SQL_DIAG_CLASS_ORIGIN:
8645 	    case SQL_DIAG_SUBCLASS_ORIGIN:
8646 	    case SQL_DIAG_CONNECTION_NAME:
8647 	    case SQL_DIAG_SERVER_NAME:
8648 	    case SQL_DIAG_SQLSTATE:
8649 	    case SQL_DIAG_MESSAGE_TEXT:
8650 	    case SQL_DIAG_DYNAMIC_FUNCTION:
8651 		len *= sizeof (SQLWCHAR);
8652 		break;
8653 	    }
8654 	}
8655 	if (stringlen) {
8656 	    *stringlen = len;
8657 	}
8658     }
8659     return ret;
8660 }
8661 #endif
8662 
8663 /**
8664  * Internal get option of HSTMT.
8665  * @param stmt statement handle
8666  * @param attr attribute to be retrieved
8667  * @param val output buffer
8668  * @param bufmax length of output buffer
8669  * @param buflen output length
8670  * @result ODBC error code
8671  */
8672 
8673 static SQLRETURN
drvgetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)8674 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8675 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
8676 {
8677     STMT *s = (STMT *) stmt;
8678     SQLULEN *uval = (SQLULEN *) val;
8679     SQLINTEGER dummy;
8680     char dummybuf[16];
8681 
8682     if (!buflen) {
8683 	buflen = &dummy;
8684     }
8685     if (!uval) {
8686 	uval = (SQLPOINTER) dummybuf;
8687     }
8688     switch (attr) {
8689     case SQL_QUERY_TIMEOUT:
8690 	*uval = 0;
8691 	*buflen = sizeof (SQLULEN);
8692 	return SQL_SUCCESS;
8693     case SQL_ATTR_CURSOR_TYPE:
8694 	*uval = s->curtype;
8695 	*buflen = sizeof (SQLULEN);
8696 	return SQL_SUCCESS;
8697     case SQL_ATTR_CURSOR_SCROLLABLE:
8698 	*uval = (s->curtype != SQL_CURSOR_FORWARD_ONLY) ?
8699 	    SQL_SCROLLABLE : SQL_NONSCROLLABLE;
8700 	*buflen = sizeof (SQLULEN);
8701 	return SQL_SUCCESS;
8702 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
8703     case SQL_ATTR_CURSOR_SENSITIVITY:
8704 	*uval = SQL_UNSPECIFIED;
8705 	*buflen = sizeof (SQLULEN);
8706 	return SQL_SUCCESS;
8707 #endif
8708     case SQL_ATTR_ROW_NUMBER:
8709 	if (s->s4stmt) {
8710 	    *uval = (s->s4stmt_rownum < 0) ?
8711 		    SQL_ROW_NUMBER_UNKNOWN : (s->s4stmt_rownum + 1);
8712 	} else {
8713 	    *uval = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
8714 	}
8715 	*buflen = sizeof (SQLULEN);
8716 	return SQL_SUCCESS;
8717     case SQL_ATTR_ASYNC_ENABLE:
8718 	*uval = SQL_ASYNC_ENABLE_OFF;
8719 	*buflen = sizeof (SQLULEN);
8720 	return SQL_SUCCESS;
8721     case SQL_CONCURRENCY:
8722 	*uval = SQL_CONCUR_LOCK;
8723 	*buflen = sizeof (SQLULEN);
8724 	return SQL_SUCCESS;
8725     case SQL_ATTR_RETRIEVE_DATA:
8726 	*uval = s->retr_data;
8727 	*buflen = sizeof (SQLULEN);
8728 	return SQL_SUCCESS;
8729     case SQL_ROWSET_SIZE:
8730     case SQL_ATTR_ROW_ARRAY_SIZE:
8731 	*uval = s->rowset_size;
8732 	*buflen = sizeof (SQLULEN);
8733 	return SQL_SUCCESS;
8734     /* Needed for some driver managers, but dummies for now */
8735     case SQL_ATTR_IMP_ROW_DESC:
8736     case SQL_ATTR_APP_ROW_DESC:
8737     case SQL_ATTR_IMP_PARAM_DESC:
8738     case SQL_ATTR_APP_PARAM_DESC:
8739 	*((SQLHDESC *) uval) = (SQLHDESC) DEAD_MAGIC;
8740 	*buflen = sizeof (SQLHDESC);
8741 	return SQL_SUCCESS;
8742     case SQL_ATTR_ROW_STATUS_PTR:
8743 	*((SQLUSMALLINT **) uval) = s->row_status;
8744 	*buflen = sizeof (SQLUSMALLINT *);
8745 	return SQL_SUCCESS;
8746     case SQL_ATTR_ROWS_FETCHED_PTR:
8747 	*((SQLULEN **) uval) = s->row_count;
8748 	*buflen = sizeof (SQLULEN *);
8749 	return SQL_SUCCESS;
8750     case SQL_ATTR_USE_BOOKMARKS: {
8751 	STMT *s = (STMT *) stmt;
8752 
8753 	*(SQLUINTEGER *) uval = s->bkmrk;
8754 	*buflen = sizeof (SQLUINTEGER);
8755 	return SQL_SUCCESS;
8756     }
8757     case SQL_ATTR_FETCH_BOOKMARK_PTR:
8758 	*(SQLPOINTER *) uval = s->bkmrkptr;
8759 	*buflen = sizeof (SQLPOINTER);
8760 	return SQL_SUCCESS;
8761     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
8762 	*((SQLULEN **) uval) = s->parm_bind_offs;
8763 	*buflen = sizeof (SQLULEN *);
8764 	return SQL_SUCCESS;
8765     case SQL_ATTR_PARAM_BIND_TYPE:
8766 	*((SQLULEN *) uval) = s->parm_bind_type;
8767 	*buflen = sizeof (SQLULEN);
8768 	return SQL_SUCCESS;
8769     case SQL_ATTR_PARAM_OPERATION_PTR:
8770 	*((SQLUSMALLINT **) uval) = s->parm_oper;
8771 	*buflen = sizeof (SQLUSMALLINT *);
8772 	return SQL_SUCCESS;
8773     case SQL_ATTR_PARAM_STATUS_PTR:
8774 	*((SQLUSMALLINT **) uval) = s->parm_status;
8775 	*buflen = sizeof (SQLUSMALLINT *);
8776 	return SQL_SUCCESS;
8777     case SQL_ATTR_PARAMS_PROCESSED_PTR:
8778 	*((SQLULEN **) uval) = s->parm_proc;
8779 	*buflen = sizeof (SQLULEN *);
8780 	return SQL_SUCCESS;
8781     case SQL_ATTR_PARAMSET_SIZE:
8782 	*((SQLULEN *) uval) = s->paramset_size;
8783 	*buflen = sizeof (SQLULEN);
8784 	return SQL_SUCCESS;
8785     case SQL_ATTR_ROW_BIND_TYPE:
8786 	*(SQLULEN *) uval = s->bind_type;
8787 	*buflen = sizeof (SQLULEN);
8788 	return SQL_SUCCESS;
8789     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
8790 	*((SQLULEN **) uval) = s->bind_offs;
8791 	*buflen = sizeof (SQLULEN *);
8792 	return SQL_SUCCESS;
8793     case SQL_ATTR_MAX_ROWS:
8794 	*((SQLULEN *) uval) = s->max_rows;
8795 	*buflen = sizeof (SQLULEN);
8796 	return SQL_SUCCESS;
8797     case SQL_ATTR_MAX_LENGTH:
8798 	*((SQLULEN *) uval) = 1000000000;
8799 	*buflen = sizeof (SQLULEN);
8800 	return SQL_SUCCESS;
8801 #ifdef SQL_ATTR_METADATA_ID
8802     case SQL_ATTR_METADATA_ID:
8803 	*((SQLULEN *) uval) = SQL_FALSE;
8804 	*buflen = sizeof (SQLULEN);
8805 	return SQL_SUCCESS;
8806 #endif
8807     }
8808     return drvunimplstmt(stmt);
8809 }
8810 
8811 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
8812 /**
8813  * Get option of HSTMT.
8814  * @param stmt statement handle
8815  * @param attr attribute to be retrieved
8816  * @param val output buffer
8817  * @param bufmax length of output buffer
8818  * @param buflen output length
8819  * @result ODBC error code
8820  */
8821 
8822 SQLRETURN SQL_API
SQLGetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)8823 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8824 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
8825 {
8826     SQLRETURN ret;
8827 
8828     HSTMT_LOCK(stmt);
8829     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
8830     HSTMT_UNLOCK(stmt);
8831     return ret;
8832 }
8833 #endif
8834 
8835 #ifdef WINTERFACE
8836 /**
8837  * Get option of HSTMT (UNICODE version).
8838  * @param stmt statement handle
8839  * @param attr attribute to be retrieved
8840  * @param val output buffer
8841  * @param bufmax length of output buffer
8842  * @param buflen output length
8843  * @result ODBC error code
8844  */
8845 
8846 SQLRETURN SQL_API
SQLGetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)8847 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8848 		SQLINTEGER bufmax, SQLINTEGER *buflen)
8849 {
8850     SQLRETURN ret;
8851 
8852     HSTMT_LOCK(stmt);
8853     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
8854     HSTMT_UNLOCK(stmt);
8855     return ret;
8856 }
8857 #endif
8858 
8859 /**
8860  * Internal set option on HSTMT.
8861  * @param stmt statement handle
8862  * @param attr attribute to be set
8863  * @param val input buffer (attribute value)
8864  * @param buflen length of input buffer
8865  * @result ODBC error code
8866  */
8867 
8868 static SQLRETURN
drvsetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)8869 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
8870 	       SQLINTEGER buflen)
8871 {
8872     STMT *s = (STMT *) stmt;
8873 #if defined(SQL_BIGINT) && defined(__WORDSIZE) && (__WORDSIZE == 64)
8874     SQLBIGINT uval;
8875 
8876     uval = (SQLBIGINT) val;
8877 #else
8878     SQLULEN uval;
8879 
8880     uval = (SQLULEN) val;
8881 #endif
8882     switch (attr) {
8883     case SQL_ATTR_CURSOR_TYPE:
8884 	if (val == (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY) {
8885 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
8886 	} else {
8887 	    s->curtype = SQL_CURSOR_STATIC;
8888 	}
8889 	if (val != (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY &&
8890 	    val != (SQLPOINTER) SQL_CURSOR_STATIC) {
8891 	    goto e01s02;
8892 	}
8893 	return SQL_SUCCESS;
8894     case SQL_ATTR_CURSOR_SCROLLABLE:
8895 	if (val == (SQLPOINTER) SQL_NONSCROLLABLE) {
8896 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
8897 	} else {
8898 	    s->curtype = SQL_CURSOR_STATIC;
8899 	}
8900 	return SQL_SUCCESS;
8901     case SQL_ATTR_ASYNC_ENABLE:
8902 	if (val != (SQLPOINTER) SQL_ASYNC_ENABLE_OFF) {
8903     e01s02:
8904 	    setstat(s, -1, "option value changed", "01S02");
8905 	    return SQL_SUCCESS_WITH_INFO;
8906 	}
8907 	return SQL_SUCCESS;
8908     case SQL_CONCURRENCY:
8909 	if (val != (SQLPOINTER) SQL_CONCUR_LOCK) {
8910 	    goto e01s02;
8911 	}
8912 	return SQL_SUCCESS;
8913 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
8914     case SQL_ATTR_CURSOR_SENSITIVITY:
8915 	if (val != (SQLPOINTER) SQL_UNSPECIFIED) {
8916 	    goto e01s02;
8917 	}
8918 	return SQL_SUCCESS;
8919 #endif
8920     case SQL_ATTR_QUERY_TIMEOUT:
8921 	return SQL_SUCCESS;
8922     case SQL_ATTR_RETRIEVE_DATA:
8923 	if (val != (SQLPOINTER) SQL_RD_ON &&
8924 	    val != (SQLPOINTER) SQL_RD_OFF) {
8925 	    goto e01s02;
8926 	}
8927 	s->retr_data = uval;
8928 	return SQL_SUCCESS;
8929     case SQL_ROWSET_SIZE:
8930     case SQL_ATTR_ROW_ARRAY_SIZE:
8931 	if (uval < 1) {
8932 	    setstat(s, -1, "invalid rowset size", "HY000");
8933 	    return SQL_ERROR;
8934 	} else {
8935 	    SQLUSMALLINT *rst = &s->row_status1;
8936 
8937 	    if (uval > 1) {
8938 		rst = xmalloc(sizeof (SQLUSMALLINT) * uval);
8939 		if (!rst) {
8940 		    return nomem(s);
8941 		}
8942 	    }
8943 	    if (s->row_status0 != &s->row_status1) {
8944 		freep(&s->row_status0);
8945 	    }
8946 	    s->row_status0 = rst;
8947 	    s->rowset_size = uval;
8948 	}
8949 	return SQL_SUCCESS;
8950     case SQL_ATTR_ROW_STATUS_PTR:
8951 	s->row_status = (SQLUSMALLINT *) val;
8952 	return SQL_SUCCESS;
8953     case SQL_ATTR_ROWS_FETCHED_PTR:
8954 	s->row_count = (SQLULEN *) val;
8955 	return SQL_SUCCESS;
8956     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
8957 	s->parm_bind_offs = (SQLULEN *) val;
8958 	return SQL_SUCCESS;
8959     case SQL_ATTR_PARAM_BIND_TYPE:
8960 	s->parm_bind_type = uval;
8961 	return SQL_SUCCESS;
8962     case SQL_ATTR_PARAM_OPERATION_PTR:
8963 	s->parm_oper = (SQLUSMALLINT *) val;
8964 	return SQL_SUCCESS;
8965     case SQL_ATTR_PARAM_STATUS_PTR:
8966 	s->parm_status = (SQLUSMALLINT *) val;
8967 	return SQL_SUCCESS;
8968     case SQL_ATTR_PARAMS_PROCESSED_PTR:
8969 	s->parm_proc = (SQLULEN *) val;
8970 	return SQL_SUCCESS;
8971     case SQL_ATTR_PARAMSET_SIZE:
8972 	if (uval < 1) {
8973 	    goto e01s02;
8974 	}
8975 	s->paramset_size = uval;
8976 	s->paramset_count = 0;
8977 	return SQL_SUCCESS;
8978     case SQL_ATTR_ROW_BIND_TYPE:
8979 	s->bind_type = uval;
8980 	return SQL_SUCCESS;
8981     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
8982 	s->bind_offs = (SQLULEN *) val;
8983 	return SQL_SUCCESS;
8984     case SQL_ATTR_USE_BOOKMARKS:
8985 	if (val != (SQLPOINTER) SQL_UB_OFF &&
8986 	    val != (SQLPOINTER) SQL_UB_ON &&
8987 	    val != (SQLPOINTER) SQL_UB_VARIABLE) {
8988 	    goto e01s02;
8989 	}
8990 	if (*s->ov3 && val == (SQLPOINTER) SQL_UB_VARIABLE) {
8991 	    s->bkmrk = SQL_UB_VARIABLE;
8992 	    return SQL_SUCCESS;
8993 	}
8994 	if (val == (SQLPOINTER) SQL_UB_VARIABLE) {
8995 	    s->bkmrk = SQL_UB_ON;
8996 	    goto e01s02;
8997 	}
8998 	s->bkmrk = (val == (SQLPOINTER) SQL_UB_ON) ? SQL_UB_ON : SQL_UB_OFF;
8999 	return SQL_SUCCESS;
9000     case SQL_ATTR_FETCH_BOOKMARK_PTR:
9001 	s->bkmrkptr = (SQLINTEGER *) val;
9002 	return SQL_SUCCESS;
9003     case SQL_ATTR_MAX_ROWS:
9004 	s->max_rows = uval;
9005 	return SQL_SUCCESS;
9006     case SQL_ATTR_MAX_LENGTH:
9007 	if (val != (SQLPOINTER) 1000000000) {
9008 	    goto e01s02;
9009 	}
9010 	return SQL_SUCCESS;
9011 #ifdef SQL_ATTR_METADATA_ID
9012     case SQL_ATTR_METADATA_ID:
9013 	if (val != (SQLPOINTER) SQL_FALSE) {
9014 	    goto e01s02;
9015 	}
9016 	return SQL_SUCCESS;
9017 #endif
9018     }
9019     return drvunimplstmt(stmt);
9020 }
9021 
9022 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
9023 /**
9024  * Set option on HSTMT.
9025  * @param stmt statement handle
9026  * @param attr attribute to be set
9027  * @param val input buffer (attribute value)
9028  * @param buflen length of input buffer
9029  * @result ODBC error code
9030  */
9031 
9032 SQLRETURN SQL_API
SQLSetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)9033 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9034 	       SQLINTEGER buflen)
9035 {
9036     SQLRETURN ret;
9037 
9038     HSTMT_LOCK(stmt);
9039     ret = drvsetstmtattr(stmt, attr, val, buflen);
9040     HSTMT_UNLOCK(stmt);
9041     return ret;
9042 }
9043 #endif
9044 
9045 #ifdef WINTERFACE
9046 /**
9047  * Set option on HSTMT (UNICODE version).
9048  * @param stmt statement handle
9049  * @param attr attribute to be set
9050  * @param val input buffer (attribute value)
9051  * @param buflen length of input buffer
9052  * @result ODBC error code
9053  */
9054 
9055 SQLRETURN SQL_API
SQLSetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)9056 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
9057 		SQLINTEGER buflen)
9058 {
9059     SQLRETURN ret;
9060 
9061     HSTMT_LOCK(stmt);
9062     ret = drvsetstmtattr(stmt, attr, val, buflen);
9063     HSTMT_UNLOCK(stmt);
9064     return ret;
9065 }
9066 #endif
9067 
9068 /**
9069  * Internal get option of HSTMT.
9070  * @param stmt statement handle
9071  * @param opt option to be retrieved
9072  * @param param output buffer
9073  * @result ODBC error code
9074  */
9075 
9076 static SQLRETURN
drvgetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)9077 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
9078 {
9079     STMT *s = (STMT *) stmt;
9080     SQLUINTEGER *ret = (SQLUINTEGER *) param;
9081 
9082     switch (opt) {
9083     case SQL_QUERY_TIMEOUT:
9084 	*ret = 0;
9085 	return SQL_SUCCESS;
9086     case SQL_CURSOR_TYPE:
9087 	*ret = s->curtype;
9088 	return SQL_SUCCESS;
9089     case SQL_ROW_NUMBER:
9090 	if (s->s4stmt) {
9091 	    *ret = (s->s4stmt_rownum < 0) ?
9092 		   SQL_ROW_NUMBER_UNKNOWN : (s->s4stmt_rownum + 1);
9093 	} else {
9094 	    *ret = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
9095 	}
9096 	return SQL_SUCCESS;
9097     case SQL_ASYNC_ENABLE:
9098 	*ret = SQL_ASYNC_ENABLE_OFF;
9099 	return SQL_SUCCESS;
9100     case SQL_CONCURRENCY:
9101 	*ret = SQL_CONCUR_LOCK;
9102 	return SQL_SUCCESS;
9103     case SQL_ATTR_RETRIEVE_DATA:
9104 	*ret = s->retr_data;
9105 	return SQL_SUCCESS;
9106     case SQL_ROWSET_SIZE:
9107     case SQL_ATTR_ROW_ARRAY_SIZE:
9108 	*ret = s->rowset_size;
9109 	return SQL_SUCCESS;
9110     case SQL_ATTR_MAX_ROWS:
9111 	*ret = s->max_rows;
9112 	return SQL_SUCCESS;
9113     case SQL_ATTR_MAX_LENGTH:
9114 	*ret = 1000000000;
9115 	return SQL_SUCCESS;
9116     }
9117     return drvunimplstmt(stmt);
9118 }
9119 
9120 /**
9121  * Get option of HSTMT.
9122  * @param stmt statement handle
9123  * @param opt option to be retrieved
9124  * @param param output buffer
9125  * @result ODBC error code
9126  */
9127 
9128 SQLRETURN SQL_API
SQLGetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)9129 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
9130 {
9131     SQLRETURN ret;
9132 
9133     HSTMT_LOCK(stmt);
9134     ret = drvgetstmtoption(stmt, opt, param);
9135     HSTMT_UNLOCK(stmt);
9136     return ret;
9137 }
9138 
9139 #ifdef WINTERFACE
9140 /**
9141  * Get option of HSTMT (UNICODE version).
9142  * @param stmt statement handle
9143  * @param opt option to be retrieved
9144  * @param param output buffer
9145  * @result ODBC error code
9146  */
9147 
9148 SQLRETURN SQL_API
SQLGetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)9149 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
9150 {
9151     SQLRETURN ret;
9152 
9153     HSTMT_LOCK(stmt);
9154     ret = drvgetstmtoption(stmt, opt, param);
9155     HSTMT_UNLOCK(stmt);
9156     return ret;
9157 }
9158 #endif
9159 
9160 /**
9161  * Internal set option on HSTMT.
9162  * @param stmt statement handle
9163  * @param opt option to be set
9164  * @param param input buffer (option value)
9165  * @result ODBC error code
9166  */
9167 
9168 static SQLRETURN
drvsetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLUINTEGER param)9169 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
9170 {
9171     STMT *s = (STMT *) stmt;
9172 
9173     switch (opt) {
9174     case SQL_CURSOR_TYPE:
9175 	if (param == SQL_CURSOR_FORWARD_ONLY) {
9176 	    s->curtype = param;
9177 	} else {
9178 	    s->curtype = SQL_CURSOR_STATIC;
9179 	}
9180 	if (param != SQL_CURSOR_FORWARD_ONLY &&
9181 	    param != SQL_CURSOR_STATIC) {
9182 	    goto e01s02;
9183 	}
9184 	return SQL_SUCCESS;
9185     case SQL_ASYNC_ENABLE:
9186 	if (param != SQL_ASYNC_ENABLE_OFF) {
9187 	    goto e01s02;
9188 	}
9189 	return SQL_SUCCESS;
9190     case SQL_CONCURRENCY:
9191 	if (param != SQL_CONCUR_LOCK) {
9192 	    goto e01s02;
9193 	}
9194 	return SQL_SUCCESS;
9195     case SQL_QUERY_TIMEOUT:
9196 	return SQL_SUCCESS;
9197     case SQL_RETRIEVE_DATA:
9198 	if (param != SQL_RD_ON && param != SQL_RD_OFF) {
9199     e01s02:
9200 	    setstat(s, -1, "option value changed", "01S02");
9201 	    return SQL_SUCCESS_WITH_INFO;
9202 	}
9203 	s->retr_data = (int) param;
9204 	return SQL_SUCCESS;
9205     case SQL_ROWSET_SIZE:
9206     case SQL_ATTR_ROW_ARRAY_SIZE:
9207 	if (param < 1) {
9208 	    setstat(s, -1, "invalid rowset size", "HY000");
9209 	    return SQL_ERROR;
9210 	} else {
9211 	    SQLUSMALLINT *rst = &s->row_status1;
9212 
9213 	    if (param > 1) {
9214 		rst = xmalloc(sizeof (SQLUSMALLINT) * param);
9215 		if (!rst) {
9216 		    return nomem(s);
9217 		}
9218 	    }
9219 	    if (s->row_status0 != &s->row_status1) {
9220 		freep(&s->row_status0);
9221 	    }
9222 	    s->row_status0 = rst;
9223 	    s->rowset_size = param;
9224 	}
9225 	return SQL_SUCCESS;
9226     case SQL_ATTR_MAX_ROWS:
9227 	s->max_rows = param;
9228 	return SQL_SUCCESS;
9229     case SQL_ATTR_MAX_LENGTH:
9230 	if (param != 1000000000) {
9231 	    goto e01s02;
9232 	}
9233 	return SQL_SUCCESS;
9234     }
9235     return drvunimplstmt(stmt);
9236 }
9237 
9238 /**
9239  * Set option on HSTMT.
9240  * @param stmt statement handle
9241  * @param opt option to be set
9242  * @param param input buffer (option value)
9243  * @result ODBC error code
9244  */
9245 
9246 SQLRETURN SQL_API
SQLSetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)9247 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt,
9248 		 SETSTMTOPTION_LAST_ARG_TYPE param)
9249 {
9250     SQLRETURN ret;
9251 
9252     HSTMT_LOCK(stmt);
9253     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
9254     HSTMT_UNLOCK(stmt);
9255     return ret;
9256 }
9257 
9258 #ifdef WINTERFACE
9259 /**
9260  * Set option on HSTMT (UNICODE version).
9261  * @param stmt statement handle
9262  * @param opt option to be set
9263  * @param param input buffer (option value)
9264  * @result ODBC error code
9265  */
9266 
9267 SQLRETURN SQL_API
SQLSetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)9268 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt,
9269 		  SETSTMTOPTION_LAST_ARG_TYPE param)
9270 {
9271     SQLRETURN ret;
9272 
9273     HSTMT_LOCK(stmt);
9274     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
9275     HSTMT_UNLOCK(stmt);
9276     return ret;
9277 }
9278 #endif
9279 
9280 /**
9281  * Check for unbound result columns.
9282  * @param s statement handle
9283  * @result ODBC error code
9284  */
9285 
9286 static SQLRETURN
chkunbound(STMT * s)9287 chkunbound(STMT *s)
9288 {
9289     int i;
9290 
9291     if (!s->bindcols || s->nbindcols < s->ncols) {
9292 unbound:
9293 	setstat(s, -1, "unbound columns", (*s->ov3) ? "HY000" : "S1000");
9294 	return SQL_ERROR;
9295     }
9296     for (i = 0; i < s->ncols; i++) {
9297 	BINDCOL *b = &s->bindcols[i];
9298 
9299 	if (b->type == SQL_UNKNOWN_TYPE || !b->valp) {
9300 	    goto unbound;
9301 	}
9302     }
9303     return SQL_SUCCESS;
9304 }
9305 
9306 /**
9307  * Internal handler to setup parameters for positional updates
9308  * from bound user buffers.
9309  * @param s statement handle
9310  * @param stmt SQLite4 statement pointer
9311  * @param i result set column index
9312  * @param si SQLite4 parameter index
9313  * @param rsi result set row index
9314  * @result ODBC error code
9315  */
9316 
9317 static SQLRETURN
setposbind(STMT * s,sqlite4_stmt * stmt,int i,int si,int rsi)9318 setposbind(STMT *s, sqlite4_stmt *stmt, int i, int si, int rsi)
9319 {
9320     DBC *d = (DBC *) s->dbc;
9321     SQLPOINTER dp = 0;
9322     SQLLEN *lp = 0;
9323     BINDCOL *b = &s->bindcols[i];
9324     COL *c = &s->cols[i];
9325     int frac;
9326     char strbuf[128], *cp;
9327 
9328     if (b->valp) {
9329 	if (s->bind_type != SQL_BIND_BY_COLUMN) {
9330 	    dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
9331 	} else {
9332 	    dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
9333 	}
9334 	if (s->bind_offs) {
9335 	    dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
9336 	}
9337     }
9338     if (b->lenp) {
9339 	if (s->bind_type != SQL_BIND_BY_COLUMN) {
9340 	    lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
9341 	} else {
9342 	    lp = b->lenp + rsi;
9343 	}
9344 	if (s->bind_offs) {
9345 	    lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
9346 	}
9347     }
9348     if (!dp || !lp) {
9349 	setstat(s, -1, "unbound column in positional update",
9350 		(*s->ov3) ? "HY000" : "S1000");
9351 	return SQL_ERROR;
9352     }
9353     if (*lp == SQL_NULL_DATA) {
9354 	sqlite4_bind_null(stmt, si);
9355 	if (d->trace) {
9356 	    fprintf(d->trace, "-- parameter %d: NULL\n", si);
9357 	    fflush(d->trace);
9358 	}
9359 	return SQL_SUCCESS;
9360     }
9361     switch (b->type) {
9362     case SQL_C_UTINYINT:
9363     case SQL_C_TINYINT:
9364     case SQL_C_STINYINT:
9365 	sqlite4_bind_int(stmt, si, *(SQLCHAR *) dp);
9366 	if (d->trace) {
9367 	    fprintf(d->trace, "-- parameter %d: %d\n", si, *(SQLCHAR *) dp);
9368 	    fflush(d->trace);
9369 	}
9370 	break;
9371 #ifdef SQL_BIT
9372     case SQL_C_BIT:
9373 	sqlite4_bind_int(stmt, si, (*(SQLCHAR *) dp) ? 1 : 0);
9374 	if (d->trace) {
9375 	    fprintf(d->trace, "-- parameter %d: %d\n", si,
9376 		    (*(SQLCHAR *) dp) ? 1 : 0);
9377 	    fflush(d->trace);
9378 	}
9379 	break;
9380 #endif
9381     case SQL_C_USHORT:
9382 	sqlite4_bind_int(stmt, si, *(SQLUSMALLINT *) dp);
9383 	if (d->trace) {
9384 	    fprintf(d->trace, "-- parameter %d: %d\n", si,
9385 		    *(SQLUSMALLINT *) dp);
9386 	    fflush(d->trace);
9387 	}
9388 	break;
9389     case SQL_C_SHORT:
9390     case SQL_C_SSHORT:
9391 	sqlite4_bind_int(stmt, si, *(SQLSMALLINT *) dp);
9392 	if (d->trace) {
9393 	    fprintf(d->trace, "-- parameter %d: %d\n", si,
9394 		    *(SQLSMALLINT *) dp);
9395 	    fflush(d->trace);
9396 	}
9397 	break;
9398     case SQL_C_ULONG:
9399 	sqlite4_bind_int(stmt, si, *(SQLUINTEGER *) dp);
9400 	if (d->trace) {
9401 	    fprintf(d->trace, "-- parameter %d: %ld\n", si,
9402 		    (long) *(SQLUINTEGER *) dp);
9403 	    fflush(d->trace);
9404 	}
9405 	break;
9406     case SQL_C_LONG:
9407     case SQL_C_SLONG:
9408 	sqlite4_bind_int(stmt, si, *(SQLINTEGER *) dp);
9409 	if (d->trace) {
9410 	    fprintf(d->trace, "-- parameter %d: %ld\n", si,
9411 		    (long) *(SQLINTEGER *) dp);
9412 	    fflush(d->trace);
9413 	}
9414 	break;
9415 #ifdef SQL_BIGINT
9416     case SQL_C_UBIGINT:
9417     case SQL_C_SBIGINT:
9418 	sqlite4_bind_int64(stmt, si, *(SQLBIGINT *) dp);
9419 	if (d->trace) {
9420 	    fprintf(d->trace,
9421 #ifdef _WIN32
9422 		    "-- parameter %d: %I64d\n",
9423 #else
9424 		    "-- parameter %d: %lld\n",
9425 #endif
9426 		    si, (sqlite4_int64) *(SQLBIGINT *) dp);
9427 	    fflush(d->trace);
9428 	}
9429 	break;
9430 #endif
9431     case SQL_C_FLOAT:
9432 	sqlite4_bind_double(stmt, si, *(float *) dp);
9433 	if (d->trace) {
9434 	    fprintf(d->trace, "-- parameter %d: %g\n", si,
9435 		    *(float *) dp);
9436 	    fflush(d->trace);
9437 	}
9438 	break;
9439     case SQL_C_DOUBLE:
9440 	sqlite4_bind_double(stmt, si, *(double *) dp);
9441 	if (d->trace) {
9442 	    fprintf(d->trace, "-- parameter %d: %g\n", si,
9443 		    *(double *) dp);
9444 	    fflush(d->trace);
9445 	}
9446 	break;
9447     case SQL_C_BINARY:
9448 	sqlite4_bind_blob(stmt, si, (char *) dp, *lp, SQLITE4_STATIC, 0);
9449 	if (d->trace) {
9450 	    fprintf(d->trace, "-- parameter %d: [BLOB]\n", si);
9451 	    fflush(d->trace);
9452 	}
9453 	break;
9454 #ifdef WCHARSUPPORT
9455     case SQL_C_WCHAR:
9456 	cp = uc_to_utf((SQLWCHAR *) dp, *lp);
9457 	if (!cp) {
9458 	    return nomem(s);
9459 	}
9460 	sqlite4_bind_text(stmt, si, cp, -1, SQLITE4_TRANSIENT, 0);
9461 	if (d->trace) {
9462 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, cp);
9463 	    fflush(d->trace);
9464 	}
9465 	uc_free(cp);
9466 	break;
9467 #endif
9468     case SQL_C_CHAR:
9469 #if defined(_WIN32) || defined(_WIN64)
9470 	if (*s->oemcp) {
9471 	    cp = wmb_to_utf((char *) dp, *lp);
9472 	    if (!cp) {
9473 		return nomem(s);
9474 	    }
9475 	    sqlite4_bind_text(stmt, si, cp, -1, SQLITE4_TRANSIENT, 0);
9476 	    if (d->trace) {
9477 		fprintf(d->trace, "-- parameter %d: '%s'\n", si, cp);
9478 		fflush(d->trace);
9479 	    }
9480 	    uc_free(cp);
9481 	} else
9482 #endif
9483 	{
9484 	    if (*lp == SQL_NTS) {
9485 		sqlite4_bind_text(stmt, si, (char *) dp, -1,
9486 				  SQLITE4_STATIC, 0);
9487 		if (d->trace) {
9488 		    fprintf(d->trace, "-- parameter %d: '%s'\n", si,
9489 			    (char *) dp);
9490 		    fflush(d->trace);
9491 		}
9492 	    } else {
9493 		sqlite4_bind_text(stmt, si, (char *) dp, *lp,
9494 				  SQLITE4_STATIC, 0);
9495 		if (d->trace) {
9496 		    fprintf(d->trace, "-- parameter %d: '%*s'\n", si,
9497 			    (int) *lp, (char *) dp);
9498 		    fflush(d->trace);
9499 		}
9500 	    }
9501 	}
9502 	break;
9503 #ifdef SQL_C_TYPE_DATE
9504     case SQL_C_TYPE_DATE:
9505 #endif
9506     case SQL_C_DATE:
9507 	sprintf(strbuf, "%04d-%02d-%02d",
9508 		((DATE_STRUCT *) dp)->year,
9509 		((DATE_STRUCT *) dp)->month,
9510 		((DATE_STRUCT *) dp)->day);
9511 	sqlite4_bind_text(stmt, si, strbuf, -1, SQLITE4_TRANSIENT, 0);
9512 	if (d->trace) {
9513 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, strbuf);
9514 	    fflush(d->trace);
9515 	}
9516 	break;
9517 #ifdef SQL_C_TYPE_TIME
9518     case SQL_C_TYPE_TIME:
9519 #endif
9520     case SQL_C_TIME:
9521 	sprintf(strbuf, "%02d:%02d:%02d",
9522 		((TIME_STRUCT *) dp)->hour,
9523 		((TIME_STRUCT *) dp)->minute,
9524 		((TIME_STRUCT *) dp)->second);
9525 	sqlite4_bind_text(stmt, si, strbuf, -1, SQLITE4_TRANSIENT, 0);
9526 	if (d->trace) {
9527 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, strbuf);
9528 	    fflush(d->trace);
9529 	}
9530 	break;
9531 #ifdef SQL_C_TYPE_TIMESTAMP
9532     case SQL_C_TYPE_TIMESTAMP:
9533 #endif
9534     case SQL_C_TIMESTAMP:
9535 	frac = (int) ((TIMESTAMP_STRUCT *) dp)->fraction;
9536 	frac /= 1000000;
9537 	frac = frac % 1000;
9538 	if (frac < 0) {
9539 	    frac = 0;
9540 	}
9541 	if (c->prec && c->prec <= 16) {
9542 	    sprintf(strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
9543 		    ((TIMESTAMP_STRUCT *) dp)->year,
9544 		    ((TIMESTAMP_STRUCT *) dp)->month,
9545 		    ((TIMESTAMP_STRUCT *) dp)->day,
9546 		    ((TIMESTAMP_STRUCT *) dp)->hour,
9547 		    ((TIMESTAMP_STRUCT *) dp)->minute);
9548 	} else if (c->prec && c->prec <= 19) {
9549 	    sprintf(strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
9550 		    ((TIMESTAMP_STRUCT *) dp)->year,
9551 		    ((TIMESTAMP_STRUCT *) dp)->month,
9552 		    ((TIMESTAMP_STRUCT *) dp)->day,
9553 		    ((TIMESTAMP_STRUCT *) dp)->hour,
9554 		    ((TIMESTAMP_STRUCT *) dp)->minute,
9555 		    ((TIMESTAMP_STRUCT *) dp)->second);
9556 	} else {
9557 	    sprintf(strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
9558 		    ((TIMESTAMP_STRUCT *) dp)->year,
9559 		    ((TIMESTAMP_STRUCT *) dp)->month,
9560 		    ((TIMESTAMP_STRUCT *) dp)->day,
9561 		    ((TIMESTAMP_STRUCT *) dp)->hour,
9562 		    ((TIMESTAMP_STRUCT *) dp)->minute,
9563 		    ((TIMESTAMP_STRUCT *) dp)->second,
9564 		    frac);
9565 	}
9566 	sqlite4_bind_text(stmt, si, strbuf, -1, SQLITE4_TRANSIENT, 0);
9567 	if (d->trace) {
9568 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, strbuf);
9569 	    fflush(d->trace);
9570 	}
9571 	break;
9572     default:
9573 	setstat(s, -1, "unsupported column type in positional update",
9574 		(*s->ov3) ? "HY000" : "S1000");
9575 	return SQL_ERROR;
9576     }
9577     return SQL_SUCCESS;
9578 }
9579 
9580 /**
9581  * Internal handler to setup parameters for positional updates
9582  * from driver side result set.
9583  * @param s statement handle
9584  * @param stmt SQLite4 statement pointer
9585  * @param i result set column index
9586  * @param si SQLite4 parameter index
9587  * @param rsi result set row index
9588  * @result ODBC error code
9589  */
9590 
9591 static SQLRETURN
setposibind(STMT * s,sqlite4_stmt * stmt,int i,int si,int rsi)9592 setposibind(STMT *s, sqlite4_stmt *stmt, int i, int si, int rsi)
9593 {
9594     DBC *d = (DBC *) s->dbc;
9595     char **data;
9596     int pos;
9597 
9598     pos = s->rowprs;
9599     if (pos < 0) {
9600 	setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
9601 	return SQL_ERROR;
9602     }
9603     pos += rsi;
9604     data = s->rows + s->ncols + (pos * s->ncols) + i;
9605     if (*data == NULL) {
9606 	sqlite4_bind_null(stmt, si);
9607 	if (d->trace) {
9608 	    fprintf(d->trace, "-- parameter %d: NULL\n", si);
9609 	    fflush(d->trace);
9610 	}
9611     } else {
9612 	sqlite4_bind_text(stmt, si, *data, -1, SQLITE4_STATIC, 0);
9613 	if (d->trace) {
9614 	    fprintf(d->trace, "-- parameter %d: '%s'\n", si, *data);
9615 	    fflush(d->trace);
9616 	}
9617     }
9618     return SQL_SUCCESS;
9619 }
9620 
9621 /**
9622  * Internal handler to refresh user buffers from driver side result set.
9623  * @param s statement handle
9624  * @param rsi result set row index
9625  * @result ODBC error code
9626  */
9627 
9628 static SQLRETURN
setposrefr(STMT * s,int rsi)9629 setposrefr(STMT *s, int rsi)
9630 {
9631     int i, withinfo = 0;
9632     SQLRETURN ret = SQL_SUCCESS;
9633 
9634     for (i = 0; s->bindcols && i < s->ncols; i++) {
9635 	BINDCOL *b = &s->bindcols[i];
9636 	SQLPOINTER dp = 0;
9637 	SQLLEN *lp = 0;
9638 
9639 	b->offs = 0;
9640 	if (b->valp) {
9641 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
9642 		dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
9643 	    } else {
9644 		dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
9645 	    }
9646 	    if (s->bind_offs) {
9647 		dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
9648 	    }
9649 	}
9650 	if (b->lenp) {
9651 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
9652 		lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
9653 	    } else {
9654 		lp = b->lenp + rsi;
9655 	    }
9656 	    if (s->bind_offs) {
9657 		lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
9658 	    }
9659 	}
9660 	if (dp || lp) {
9661 	    int rowp = s->rowp;
9662 
9663 	    s->rowp = s->rowprs + rsi;
9664 	    ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp,
9665 			     b->max, lp, 0);
9666 	    s->rowp = rowp;
9667 	    if (!SQL_SUCCEEDED(ret)) {
9668 		s->row_status0[rsi] = SQL_ROW_ERROR;
9669 		break;
9670 	    }
9671 	    if (ret != SQL_SUCCESS) {
9672 		withinfo = 1;
9673 #ifdef SQL_ROW_SUCCESS_WITH_INFO
9674 		s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
9675 #endif
9676 	    }
9677 	}
9678     }
9679     if (SQL_SUCCEEDED(ret)) {
9680 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
9681     }
9682     return ret;
9683 }
9684 
9685 /**
9686  * Internal set position on result in HSTMT.
9687  * @param stmt statement handle
9688  * @param row row to be positioned
9689  * @param op operation code
9690  * @param lock locking type
9691  * @result ODBC error code
9692  */
9693 
9694 static SQLRETURN
drvsetpos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)9695 drvsetpos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
9696 {
9697     STMT *s = (STMT *) stmt;
9698     DBC *d = (DBC *) s->dbc;
9699     int rowp, i, k, rc;
9700     dstr *sql = 0;
9701     int sqlleft;
9702     sqlite4_stmt *s4stmt = NULL;
9703     SQLRETURN ret;
9704 
9705     if (lock != SQL_LOCK_NO_CHANGE) {
9706 	setstat(s, -1, "unsupported locking mode",
9707 		(*s->ov3) ? "HY000" : "S1000");
9708 	return SQL_ERROR;
9709     }
9710     if (s->isselect != 1 || s->curtype != SQL_CURSOR_STATIC) {
9711 	setstat(s, -1, "incompatible statement",
9712 		(*s->ov3) ? "HY000" : "S1000");
9713 	return SQL_ERROR;
9714     }
9715     if (op == SQL_ADD) {
9716 	if (s->one_tbl <= 0) {
9717 	    setstat(s, -1, "incompatible rowset",
9718 		    (*s->ov3) ? "HY000" : "S1000");
9719 	    return SQL_ERROR;
9720 	}
9721 	if (row == 0 || row > s->rowset_size + 1) {
9722 	    goto rowoor;
9723 	}
9724 	ret = chkunbound(s);
9725 	if (ret != SQL_SUCCESS) {
9726 	    return ret;
9727 	}
9728 	sql = dsappend(sql, "INSERT INTO ");
9729 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
9730 	    sql = dsappendq(sql, s->dyncols[0].db);
9731 	    sql = dsappend(sql, ".");
9732 	}
9733 	sql = dsappendq(sql, s->dyncols[0].table);
9734 	for (i = 0; i < s->ncols; i++) {
9735 	    sql = dsappend(sql, (i > 0) ? "," : "(");
9736 	    sql = dsappendq(sql, s->dyncols[i].column);
9737 	}
9738 	sql = dsappend(sql, ") VALUES ");
9739 	for (i = 0; i < s->ncols; i++) {
9740 	    sql = dsappend(sql, (i > 0) ? ",?" : "(?");
9741 	}
9742 	sql = dsappend(sql, ")");
9743 	if (dserr(sql)) {
9744 	    dsfree(sql);
9745 	    return nomem(s);
9746 	}
9747 	dbtraceapi(d, "sqlite4_prepare", dsval(sql));
9748 	s4stmt = NULL;
9749 	rc = sqlite4_prepare(d->sqlite, dsval(sql), -1, &s4stmt, &sqlleft);
9750 	dbtracerc(d, rc, NULL);
9751 	dsfree(sql);
9752 	if (rc != SQLITE4_OK) {
9753 istmterr:
9754 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
9755 		    sqlite4_errmsg(d->sqlite), rc);
9756 	    if (s4stmt) {
9757 		dbtraceapi(d, "sqlite4_finalize", NULL);
9758 		sqlite4_finalize(s4stmt);
9759 	    }
9760 	    return SQL_ERROR;
9761 	}
9762 	for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
9763 	    ret = setposbind(s, s4stmt, i, k, row - 1);
9764 	    if (ret != SQL_SUCCESS) {
9765 		dbtraceapi(d, "sqlite4_finalize", NULL);
9766 		sqlite4_finalize(s4stmt);
9767 		return ret;
9768 	    }
9769 	    k++;
9770 	}
9771 	rc = sqlite4_step(s4stmt);
9772 	if (rc != SQLITE4_DONE) {
9773 	    goto istmterr;
9774 	}
9775 	sqlite4_finalize(s4stmt);
9776 	if (sqlite4_changes(d->sqlite) > 0 && row <= s->rowset_size) {
9777 	    if (s->row_status0) {
9778 		s->row_status0[row - 1] = SQL_ROW_ADDED;
9779 	    }
9780 	    if (s->row_status) {
9781 		s->row_status[row - 1] = SQL_ROW_ADDED;
9782 	    }
9783 	}
9784 	return SQL_SUCCESS;
9785     } else if (op == SQL_UPDATE || op == SQL_DELETE) {
9786 	if (s->one_tbl <= 0 || s->has_pk <= 0) {
9787 	    setstat(s, -1, "incompatible rowset",
9788 		    (*s->ov3) ? "HY000" : "S1000");
9789 	    return SQL_ERROR;
9790 	}
9791 	if (row == 0) {
9792 	    ret = SQL_SUCCESS;
9793 	    for (i = 1; i <= s->rowset_size; i++) {
9794 		ret = drvsetpos(stmt, i, op, lock);
9795 		if (!SQL_SUCCEEDED(ret)) {
9796 		    break;
9797 		}
9798 	    }
9799 	    return ret;
9800 	}
9801 	if (row > s->rowset_size) {
9802 	    goto rowoor;
9803 	}
9804     }
9805     if (op != SQL_POSITION && op != SQL_REFRESH &&
9806 	op != SQL_DELETE && op != SQL_UPDATE) {
9807 	return drvunimplstmt(stmt);
9808     }
9809     if (op == SQL_POSITION) {
9810 	rowp = s->rowp + row - 1;
9811 	if (!s->rows || row == 0 || rowp < -1 || rowp >= s->nrows) {
9812 rowoor:
9813 	    setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
9814 	    return SQL_ERROR;
9815 	}
9816 	s->rowp = rowp;
9817     } else if (op == SQL_REFRESH) {
9818 	if (row > s->rowset_size) {
9819 	    goto rowoor;
9820 	}
9821 	if (row == 0) {
9822 	    ret = SQL_SUCCESS;
9823 	    for (i = 0; i < s->rowset_size; i++) {
9824 		ret = setposrefr(s, i);
9825 		if (!SQL_SUCCEEDED(ret)) {
9826 		    break;
9827 		}
9828 	    }
9829 	    return ret;
9830 	}
9831 	return setposrefr(s, row - 1);
9832     } else if (op == SQL_DELETE) {
9833 	sql = dsappend(sql, "DELETE FROM ");
9834 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
9835 	    sql = dsappendq(sql, s->dyncols[0].db);
9836 	    sql = dsappend(sql, ".");
9837 	}
9838 	sql = dsappendq(sql, s->dyncols[0].table);
9839 	for (i = k = 0; i < s->ncols; i++) {
9840 	    if (s->dyncols[i].ispk <= 0) {
9841 		continue;
9842 	    }
9843 	    sql = dsappend(sql, (k > 0) ? " AND " : " WHERE ");
9844 	    sql = dsappendq(sql, s->dyncols[i].column);
9845 	    sql = dsappend(sql, " = ?");
9846 	    k++;
9847 	}
9848 	if (dserr(sql)) {
9849 	    dsfree(sql);
9850 	    return nomem(s);
9851 	}
9852 	dbtraceapi(d, "sqlite4_prepare", dsval(sql));
9853 	s4stmt = NULL;
9854 	rc = sqlite4_prepare(d->sqlite, dsval(sql), -1, &s4stmt, &sqlleft);
9855 	dbtracerc(d, rc, NULL);
9856 	dsfree(sql);
9857 	if (rc != SQLITE4_OK) {
9858 dstmterr:
9859 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
9860 		    sqlite4_errmsg(d->sqlite), rc);
9861 	    if (s4stmt) {
9862 		dbtraceapi(d, "sqlite4_finalize", NULL);
9863 		sqlite4_finalize(s4stmt);
9864 	    }
9865 	    return SQL_ERROR;
9866 	}
9867 	for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
9868 	    if (s->dyncols[i].ispk <= 0) {
9869 		continue;
9870 	    }
9871 	    ret = setposibind(s, s4stmt, i, k, row - 1);
9872 	    if (ret != SQL_SUCCESS) {
9873 		dbtraceapi(d, "sqlite4_finalize", NULL);
9874 		sqlite4_finalize(s4stmt);
9875 		return ret;
9876 	    }
9877 	    k++;
9878 	}
9879 	rc = sqlite4_step(s4stmt);
9880 	if (rc != SQLITE4_DONE) {
9881 	    goto dstmterr;
9882 	}
9883 	sqlite4_finalize(s4stmt);
9884 	if (sqlite4_changes(d->sqlite) > 0) {
9885 	    if (s->row_status0) {
9886 		s->row_status0[row - 1] = SQL_ROW_DELETED;
9887 	    }
9888 	    if (s->row_status) {
9889 		s->row_status[row - 1] = SQL_ROW_DELETED;
9890 	    }
9891 	}
9892 	return SQL_SUCCESS;
9893     } else if (op == SQL_UPDATE) {
9894 	ret = chkunbound(s);
9895 	if (ret != SQL_SUCCESS) {
9896 	    return ret;
9897 	}
9898 	sql = dsappend(sql, "UPDATE ");
9899 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
9900 	    sql = dsappendq(sql, s->dyncols[0].db);
9901 	    sql = dsappend(sql, ".");
9902 	}
9903 	sql = dsappendq(sql, s->dyncols[0].table);
9904 	for (i = 0; i < s->ncols; i++) {
9905 	    sql = dsappend(sql, (i > 0) ? ", " : " SET ");
9906 	    sql = dsappendq(sql, s->dyncols[i].column);
9907 	    sql = dsappend(sql, " = ?");
9908 	}
9909 	for (i = k = 0; i < s->ncols; i++) {
9910 	    if (s->dyncols[i].ispk <= 0) {
9911 		continue;
9912 	    }
9913 	    sql = dsappend(sql, (k > 0) ? " AND " : " WHERE ");
9914 	    sql = dsappendq(sql, s->dyncols[i].column);
9915 	    sql = dsappend(sql, " = ?");
9916 	    k++;
9917 	}
9918 	if (dserr(sql)) {
9919 	    dsfree(sql);
9920 	    return nomem(s);
9921 	}
9922 	dbtraceapi(d, "sqlite4_prepare", dsval(sql));
9923 	s4stmt = NULL;
9924 	rc = sqlite4_prepare(d->sqlite, dsval(sql), -1, &s4stmt, &sqlleft);
9925 	dbtracerc(d, rc, NULL);
9926 	dsfree(sql);
9927 	if (rc != SQLITE4_OK) {
9928 ustmterr:
9929 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
9930 		    sqlite4_errmsg(d->sqlite), rc);
9931 	    if (s4stmt) {
9932 		dbtraceapi(d, "sqlite4_finalize", NULL);
9933 		sqlite4_finalize(s4stmt);
9934 	    }
9935 	    return SQL_ERROR;
9936 	}
9937 	for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
9938 	    ret = setposbind(s, s4stmt, i, k, row - 1);
9939 	    if (ret != SQL_SUCCESS) {
9940 		dbtraceapi(d, "sqlite4_finalize", NULL);
9941 		sqlite4_finalize(s4stmt);
9942 		return ret;
9943 	    }
9944 	    k++;
9945 	}
9946 	for (i = 0; s->bindcols && i < s->ncols; i++) {
9947 	    if (s->dyncols[i].ispk <= 0) {
9948 		continue;
9949 	    }
9950 	    ret = setposibind(s, s4stmt, i, k, row - 1);
9951 	    if (ret != SQL_SUCCESS) {
9952 		dbtraceapi(d, "sqlite4_finalize", NULL);
9953 		sqlite4_finalize(s4stmt);
9954 		return ret;
9955 	    }
9956 	    k++;
9957 	}
9958 	rc = sqlite4_step(s4stmt);
9959 	if (rc != SQLITE4_DONE) {
9960 	    goto ustmterr;
9961 	}
9962 	sqlite4_finalize(s4stmt);
9963 	if (sqlite4_changes(d->sqlite) > 0) {
9964 	    if (s->row_status0) {
9965 		s->row_status0[row - 1] = SQL_ROW_UPDATED;
9966 	    }
9967 	    if (s->row_status) {
9968 		s->row_status[row - 1] = SQL_ROW_UPDATED;
9969 	    }
9970 	}
9971 	return SQL_SUCCESS;
9972     }
9973     return SQL_SUCCESS;
9974 }
9975 
9976 /**
9977  * Set position on result in HSTMT.
9978  * @param stmt statement handle
9979  * @param row row to be positioned
9980  * @param op operation code
9981  * @param lock locking type
9982  * @result ODBC error code
9983  */
9984 
9985 SQLRETURN SQL_API
SQLSetPos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)9986 SQLSetPos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
9987 {
9988     SQLRETURN ret;
9989 
9990     HSTMT_LOCK(stmt);
9991     ret = drvsetpos(stmt, row, op, lock);
9992     HSTMT_UNLOCK(stmt);
9993     return ret;
9994 }
9995 
9996 /**
9997  * Internal perform bulk operation on HSTMT.
9998  * @param stmt statement handle
9999  * @param op operation to be performed
10000  * @result ODBC error code
10001  */
10002 
10003 static SQLRETURN
drvbulkoperations(SQLHSTMT stmt,SQLSMALLINT op)10004 drvbulkoperations(SQLHSTMT stmt, SQLSMALLINT op)
10005 {
10006     STMT *s = (STMT *) stmt;
10007     DBC *d = (DBC *) s->dbc;
10008     int row, i, k, rc;
10009     dstr *sql = 0;
10010     int sqlleft;
10011     sqlite4_stmt *s4stmt = NULL;
10012     SQLRETURN ret;
10013 
10014     if (s->isselect != 1 || s->curtype != SQL_CURSOR_STATIC) {
10015 	setstat(s, -1, "incompatible statement",
10016 		(*s->ov3) ? "HY000" : "S1000");
10017 	return SQL_ERROR;
10018     }
10019     if (op == SQL_ADD) {
10020 	if (s->one_tbl <= 0) {
10021 	    setstat(s, -1, "incompatible rowset",
10022 		    (*s->ov3) ? "HY000" : "S1000");
10023 	    return SQL_ERROR;
10024 	}
10025 	ret = chkunbound(s);
10026 	if (ret != SQL_SUCCESS) {
10027 	    return ret;
10028 	}
10029 	sql = dsappend(sql, "INSERT INTO ");
10030 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10031 	    sql = dsappendq(sql, s->dyncols[0].db);
10032 	    sql = dsappend(sql, ".");
10033 	}
10034 	sql = dsappendq(sql, s->dyncols[0].table);
10035 	for (i = 0; i < s->ncols; i++) {
10036 	    sql = dsappend(sql, (i > 0) ? "," : "(");
10037 	    sql = dsappendq(sql, s->dyncols[i].column);
10038 	}
10039 	sql = dsappend(sql, ") VALUES ");
10040 	for (i = 0; i < s->ncols; i++) {
10041 	    sql = dsappend(sql, (i > 0) ? ",?" : "(?");
10042 	}
10043 	sql = dsappend(sql, ")");
10044 	if (dserr(sql)) {
10045 	    dsfree(sql);
10046 	    return nomem(s);
10047 	}
10048 	dbtraceapi(d, "sqlite4_prepare", dsval(sql));
10049 	s4stmt = NULL;
10050 	rc = sqlite4_prepare(d->sqlite, dsval(sql), -1, &s4stmt, &sqlleft);
10051 	dbtracerc(d, rc, NULL);
10052 	dsfree(sql);
10053 	if (rc != SQLITE4_OK) {
10054 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10055 		    sqlite4_errmsg(d->sqlite), rc);
10056 	    if (s4stmt) {
10057 		dbtraceapi(d, "sqlite4_finalize", NULL);
10058 		sqlite4_finalize(s4stmt);
10059 	    }
10060 	    return SQL_ERROR;
10061 	}
10062 	for (row = 0; row < s->rowset_size; row++) {
10063 	    for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10064 		ret = setposbind(s, s4stmt, i, k, row);
10065 		if (ret != SQL_SUCCESS) {
10066 istmterr:
10067 		    if (s->row_status0) {
10068 			s->row_status0[row] = SQL_ROW_ERROR;
10069 		    }
10070 		    if (s->row_status) {
10071 			s->row_status[row] = SQL_ROW_ERROR;
10072 		    }
10073 		    dbtraceapi(d, "sqlite4_finalize", NULL);
10074 		    sqlite4_finalize(s4stmt);
10075 		    return ret;
10076 		}
10077 		k++;
10078 	    }
10079 	    rc = sqlite4_step(s4stmt);
10080 	    if (rc != SQLITE4_DONE) {
10081 		setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10082 			sqlite4_errmsg(d->sqlite), rc);
10083 		ret = SQL_ERROR;
10084 		goto istmterr;
10085 	    }
10086 	    if (sqlite4_changes(d->sqlite) > 0) {
10087 		if (s->row_status0) {
10088 		    s->row_status0[row] = SQL_ROW_ADDED;
10089 		}
10090 		if (s->row_status) {
10091 		    s->row_status[row] = SQL_ROW_ADDED;
10092 		}
10093 	    }
10094 	    if (s->bkmrk == SQL_UB_VARIABLE &&
10095 		s->bkmrkcol.type == SQL_C_VARBOOKMARK &&
10096 		s->bkmrkcol.valp) {
10097 		SQLPOINTER *val;
10098 
10099 		if (s->bind_type != SQL_BIND_BY_COLUMN) {
10100 		    val = (SQLPOINTER)
10101 			((char *) s->bkmrkcol.valp + s->bind_type * row);
10102 		} else {
10103 		    val = (SQLPOINTER)
10104 			((char *) s->bkmrkcol.valp + s->bkmrkcol.max * row);
10105 		}
10106 		if (s->bind_offs) {
10107 		    val = (SQLPOINTER) ((char *) val + *s->bind_offs);
10108 		}
10109 #if 0
10110 		*(sqlite4_int64 *) val = sqlite4_last_insert_rowid(d->sqlite);
10111 #else
10112 		*(sqlite4_int64 *) val = 0;
10113 #endif
10114 		if (s->bkmrkcol.lenp) {
10115 		    SQLLEN *ival;
10116 
10117 		    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10118 			ival = (SQLLEN *)
10119 			    ((char *) s->bkmrkcol.lenp + s->bind_type * row);
10120 		    } else {
10121 			ival = &s->bkmrkcol.lenp[row];
10122 		    }
10123 		    if (s->bind_offs) {
10124 			ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
10125 		    }
10126 		    *ival = sizeof (sqlite4_int64);
10127 		}
10128 	    }
10129 	    dbtraceapi(d, "sqlite4_reset", NULL);
10130 	    sqlite4_reset(s4stmt);
10131 	}
10132 	dbtraceapi(d, "sqlite4_finalize", NULL);
10133 	sqlite4_finalize(s4stmt);
10134 	return SQL_SUCCESS;
10135     } else if (op == SQL_DELETE_BY_BOOKMARK) {
10136 	if (s->has_rowid < 0 ||
10137 	    s->bkmrk != SQL_UB_VARIABLE ||
10138 	    s->bkmrkcol.type != SQL_C_VARBOOKMARK ||
10139 	    !s->bkmrkcol.valp) {
10140 	    setstat(s, -1, "incompatible rowset",
10141 		    (*s->ov3) ? "HY000" : "S1000");
10142 	    return SQL_ERROR;
10143 	}
10144 	sql = dsappend(sql, "DELETE FROM ");
10145 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10146 	    sql = dsappendq(sql, s->dyncols[0].db);
10147 	    sql = dsappend(sql, ".");
10148 	}
10149 	sql = dsappendq(sql, s->dyncols[0].table);
10150 	sql = dsappend(sql, " WHERE ");
10151 	sql = dsappendq(sql, s->dyncols[0].column);
10152 	sql = dsappend(sql, " = ?");
10153 	if (dserr(sql)) {
10154 	    dsfree(sql);
10155 	    return nomem(s);
10156 	}
10157 	dbtraceapi(d, "sqlite4_prepare", dsval(sql));
10158 	s4stmt = NULL;
10159 	rc = sqlite4_prepare(d->sqlite, dsval(sql), -1, &s4stmt, &sqlleft);
10160 	dbtracerc(d, rc, NULL);
10161 	dsfree(sql);
10162 	if (rc != SQLITE4_OK) {
10163 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10164 		    sqlite4_errmsg(d->sqlite), rc);
10165 	    if (s4stmt) {
10166 		dbtraceapi(d, "sqlite4_finalize", NULL);
10167 		sqlite4_finalize(s4stmt);
10168 	    }
10169 	    return SQL_ERROR;
10170 	}
10171 	for (row = 0; row < s->rowset_size; row++) {
10172 	    SQLPOINTER *val;
10173 	    sqlite4_int64 rowid;
10174 
10175 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10176 		val = (SQLPOINTER)
10177 		    ((char *) s->bkmrkcol.valp + s->bind_type * row);
10178 	    } else {
10179 		val = (SQLPOINTER)
10180 		    ((char *) s->bkmrkcol.valp + s->bkmrkcol.max * row);
10181 	    }
10182 	    if (s->bind_offs) {
10183 		val = (SQLPOINTER) ((char *) val + *s->bind_offs);
10184 	    }
10185 	    if (s->bkmrkcol.lenp) {
10186 		SQLLEN *ival;
10187 
10188 		if (s->bind_type != SQL_BIND_BY_COLUMN) {
10189 		    ival = (SQLLEN *)
10190 			((char *) s->bkmrkcol.lenp + s->bind_type * row);
10191 		} else {
10192 		    ival = &s->bkmrkcol.lenp[row];
10193 		}
10194 		if (s->bind_offs) {
10195 		    ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
10196 		}
10197 		if (*ival != sizeof (sqlite4_int64)) {
10198 		    continue;
10199 		}
10200 	    }
10201 	    rowid = *(sqlite4_int64 *) val;
10202 	    sqlite4_bind_int64(s4stmt, 1, rowid);
10203 	    if (d->trace) {
10204 		fprintf(d->trace,
10205 #ifdef _WIN32
10206 			"-- parameter 1: %I64d\n",
10207 #else
10208 			"-- parameter 1: %lld\n",
10209 #endif
10210 			rowid);
10211 		fflush(d->trace);
10212 	    }
10213 	    rc = sqlite4_step(s4stmt);
10214 	    if (rc != SQLITE4_DONE) {
10215 		setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10216 			sqlite4_errmsg(d->sqlite), rc);
10217 		if (s->row_status0) {
10218 		    s->row_status0[row] = SQL_ROW_ERROR;
10219 		}
10220 		if (s->row_status) {
10221 		    s->row_status[row] = SQL_ROW_ERROR;
10222 		}
10223 		dbtraceapi(d, "sqlite4_finalize", NULL);
10224 		sqlite4_finalize(s4stmt);
10225 		return SQL_ERROR;
10226 	    }
10227 	    if (sqlite4_changes(d->sqlite) > 0) {
10228 		if (s->row_status0) {
10229 		    s->row_status0[row] = SQL_ROW_DELETED;
10230 		}
10231 		if (s->row_status) {
10232 		    s->row_status[row] = SQL_ROW_DELETED;
10233 		}
10234 	    }
10235 	    dbtraceapi(d, "sqlite4_reset", NULL);
10236 	    sqlite4_reset(s4stmt);
10237 	}
10238 	dbtraceapi(d, "sqlite4_finalize", NULL);
10239 	sqlite4_finalize(s4stmt);
10240 	return SQL_SUCCESS;
10241     } else if (op == SQL_UPDATE_BY_BOOKMARK) {
10242 	if (s->has_rowid < 0 ||
10243 	    s->bkmrk != SQL_UB_VARIABLE ||
10244 	    s->bkmrkcol.type != SQL_C_VARBOOKMARK ||
10245 	    !s->bkmrkcol.valp) {
10246 	    setstat(s, -1, "incompatible rowset",
10247 		    (*s->ov3) ? "HY000" : "S1000");
10248 	    return SQL_ERROR;
10249 	}
10250 	ret = chkunbound(s);
10251 	if (ret != SQL_SUCCESS) {
10252 	    return ret;
10253 	}
10254 	sql = dsappend(sql, "UPDATE ");
10255 	if (s->dyncols[0].db && s->dyncols[0].db[0]) {
10256 	    sql = dsappendq(sql, s->dyncols[0].db);
10257 	    sql = dsappend(sql, ".");
10258 	}
10259 	sql = dsappendq(sql, s->dyncols[0].table);
10260 	for (i = 0, k = 0; i < s->ncols; i++) {
10261 	    sql = dsappend(sql, (k > 0) ? ", " : " SET ");
10262 	    sql = dsappendq(sql, s->dyncols[i].column);
10263 	    sql = dsappend(sql, " = ?");
10264 	    k++;
10265 	}
10266 	sql = dsappend(sql, " WHERE ");
10267 	sql = dsappendq(sql, s->dyncols[s->has_rowid].column);
10268 	sql = dsappend(sql, " = ?");
10269 	if (dserr(sql)) {
10270 	    dsfree(sql);
10271 	    return nomem(s);
10272 	}
10273 	dbtraceapi(d, "sqlite4_prepare", dsval(sql));
10274 	s4stmt = NULL;
10275 	rc = sqlite4_prepare(d->sqlite, dsval(sql), -1, &s4stmt, &sqlleft);
10276 	dbtracerc(d, rc, NULL);
10277 	dsfree(sql);
10278 	if (rc != SQLITE4_OK) {
10279 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10280 		    sqlite4_errmsg(d->sqlite), rc);
10281 	    if (s4stmt) {
10282 		dbtraceapi(d, "sqlite4_finalize", NULL);
10283 		sqlite4_finalize(s4stmt);
10284 	    }
10285 	    return SQL_ERROR;
10286 	}
10287 	for (row = 0; row < s->rowset_size; row++) {
10288 	    SQLPOINTER *val;
10289 	    sqlite4_int64 rowid;
10290 
10291 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
10292 		val = (SQLPOINTER)
10293 		    ((char *) s->bkmrkcol.valp + s->bind_type * row);
10294 	    } else {
10295 		val = (SQLPOINTER)
10296 		    ((char *) s->bkmrkcol.valp + s->bkmrkcol.max * row);
10297 	    }
10298 	    if (s->bind_offs) {
10299 		val = (SQLPOINTER) ((char *) val + *s->bind_offs);
10300 	    }
10301 	    if (s->bkmrkcol.lenp) {
10302 		SQLLEN *ival;
10303 
10304 		if (s->bind_type != SQL_BIND_BY_COLUMN) {
10305 		    ival = (SQLLEN *)
10306 			((char *) s->bkmrkcol.lenp + s->bind_type * row);
10307 		} else {
10308 		    ival = &s->bkmrkcol.lenp[row];
10309 		}
10310 		if (s->bind_offs) {
10311 		    ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
10312 		}
10313 		if (*ival != sizeof (sqlite4_int64)) {
10314 		    continue;
10315 		}
10316 	    }
10317 	    for (i = 0, k = 1; s->bindcols && i < s->ncols; i++) {
10318 		ret = setposbind(s, s4stmt, i, k, row);
10319 		if (ret != SQL_SUCCESS) {
10320 ustmterr:
10321 		    if (s->row_status0) {
10322 			s->row_status0[row] = SQL_ROW_ERROR;
10323 		    }
10324 		    if (s->row_status) {
10325 			s->row_status[row] = SQL_ROW_ERROR;
10326 		    }
10327 		    dbtraceapi(d, "sqlite4_finalize", NULL);
10328 		    sqlite4_finalize(s4stmt);
10329 		    return ret;
10330 		}
10331 		k++;
10332 	    }
10333 	    rowid = *(sqlite4_int64 *) val;
10334 	    sqlite4_bind_int64(s4stmt, k, rowid);
10335 	    if (d->trace) {
10336 		fprintf(d->trace,
10337 #ifdef _WIN32
10338 			"-- parameter %d: %I64d\n",
10339 #else
10340 			"-- parameter %d: %lld\n",
10341 #endif
10342 			k, rowid);
10343 		fflush(d->trace);
10344 	    }
10345 	    rc = sqlite4_step(s4stmt);
10346 	    if (rc != SQLITE4_DONE) {
10347 		setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
10348 			sqlite4_errmsg(d->sqlite), rc);
10349 		ret = SQL_ERROR;
10350 		goto ustmterr;
10351 	    }
10352 	    if (sqlite4_changes(d->sqlite) > 0) {
10353 		if (s->row_status0) {
10354 		    s->row_status0[row] = SQL_ROW_UPDATED;
10355 		}
10356 		if (s->row_status) {
10357 		    s->row_status[row] = SQL_ROW_UPDATED;
10358 		}
10359 	    }
10360 	    dbtraceapi(d, "sqlite4_reset", NULL);
10361 	    sqlite4_reset(s4stmt);
10362 	}
10363 	dbtraceapi(d, "sqlite4_finalize", NULL);
10364 	sqlite4_finalize(s4stmt);
10365 	return SQL_SUCCESS;
10366     }
10367     setstat(s, -1, "unsupported operation", (*s->ov3) ? "HY000" : "S1000");
10368     return SQL_ERROR;
10369 }
10370 
10371 /**
10372  * Perform bulk operation on HSTMT.
10373  * @param stmt statement handle
10374  * @param oper operation to be performed
10375  * @result ODBC error code
10376  */
10377 
10378 SQLRETURN SQL_API
SQLBulkOperations(SQLHSTMT stmt,SQLSMALLINT oper)10379 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
10380 {
10381     SQLRETURN ret;
10382 
10383     HSTMT_LOCK(stmt);
10384     ret = drvbulkoperations(stmt, oper);
10385     HSTMT_UNLOCK(stmt);
10386     return ret;
10387 }
10388 
10389 /**
10390  * Function not implemented.
10391  */
10392 
10393 SQLRETURN SQL_API
SQLSetScrollOptions(SQLHSTMT stmt,SQLUSMALLINT concur,SQLLEN rowkeyset,SQLUSMALLINT rowset)10394 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
10395 		    SQLUSMALLINT rowset)
10396 {
10397     SQLRETURN ret;
10398 
10399     HSTMT_LOCK(stmt);
10400     ret = drvunimplstmt(stmt);
10401     HSTMT_UNLOCK(stmt);
10402     return ret;
10403 }
10404 
10405 #define strmak(dst, src, max, lenp) { \
10406     int len = strlen(src); \
10407     int cnt = min(len + 1, max); \
10408     strncpy(dst, src, cnt); \
10409     *lenp = (cnt > len) ? len : cnt; \
10410 }
10411 
10412 /**
10413  * Internal return information about what this ODBC driver supports.
10414  * @param dbc database connection handle
10415  * @param type type of information to be retrieved
10416  * @param val output buffer
10417  * @param valMax length of output buffer
10418  * @param valLen output length
10419  * @result ODBC error code
10420  */
10421 
10422 static SQLRETURN
drvgetinfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)10423 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
10424 	   SQLSMALLINT *valLen)
10425 {
10426     DBC *d;
10427     char dummyc[301];
10428     SQLSMALLINT dummy;
10429 #if defined(_WIN32) || defined(_WIN64)
10430     char pathbuf[301], *drvname;
10431 #else
10432     static char drvname[] = "sqlite4odbc.so";
10433 #endif
10434 
10435     if (dbc == SQL_NULL_HDBC) {
10436 	return SQL_INVALID_HANDLE;
10437     }
10438     d = (DBC *) dbc;
10439     if (valMax) {
10440 	valMax--;
10441     }
10442     if (!valLen) {
10443 	valLen = &dummy;
10444     }
10445     if (!val) {
10446 	val = dummyc;
10447 	valMax = sizeof (dummyc) - 1;
10448     }
10449     switch (type) {
10450     case SQL_MAX_USER_NAME_LEN:
10451 	*((SQLSMALLINT *) val) = 16;
10452 	*valLen = sizeof (SQLSMALLINT);
10453 	break;
10454     case SQL_USER_NAME:
10455 	strmak(val, "", valMax, valLen);
10456 	break;
10457     case SQL_DRIVER_ODBC_VER:
10458 #if 0
10459 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
10460 #else
10461 	strmak(val, "03.00", valMax, valLen);
10462 #endif
10463 	break;
10464     case SQL_ACTIVE_CONNECTIONS:
10465     case SQL_ACTIVE_STATEMENTS:
10466 	*((SQLSMALLINT *) val) = 0;
10467 	*valLen = sizeof (SQLSMALLINT);
10468 	break;
10469 #ifdef SQL_ASYNC_MODE
10470     case SQL_ASYNC_MODE:
10471 	*((SQLUINTEGER *) val) = SQL_AM_NONE;
10472 	*valLen = sizeof (SQLUINTEGER);
10473 	break;
10474 #endif
10475 #ifdef SQL_CREATE_TABLE
10476     case SQL_CREATE_TABLE:
10477 	*((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
10478 				 SQL_CT_COLUMN_DEFAULT |
10479 				 SQL_CT_COLUMN_CONSTRAINT |
10480 				 SQL_CT_CONSTRAINT_NON_DEFERRABLE;
10481 	*valLen = sizeof (SQLUINTEGER);
10482 	break;
10483 #endif
10484 #ifdef SQL_CREATE_VIEW
10485     case SQL_CREATE_VIEW:
10486 	*((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
10487 	*valLen = sizeof (SQLUINTEGER);
10488 	break;
10489 #endif
10490 #ifdef SQL_DDL_INDEX
10491     case SQL_DDL_INDEX:
10492 	*((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
10493 	*valLen = sizeof (SQLUINTEGER);
10494 	break;
10495 #endif
10496 #ifdef SQL_DROP_TABLE
10497     case SQL_DROP_TABLE:
10498 	*((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
10499 	*valLen = sizeof (SQLUINTEGER);
10500 	break;
10501 #endif
10502 #ifdef SQL_DROP_VIEW
10503     case SQL_DROP_VIEW:
10504 	*((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
10505 	*valLen = sizeof (SQLUINTEGER);
10506 	break;
10507 #endif
10508 #ifdef SQL_INDEX_KEYWORDS
10509     case SQL_INDEX_KEYWORDS:
10510 	*((SQLUINTEGER *) val) = SQL_IK_ALL;
10511 	*valLen = sizeof (SQLUINTEGER);
10512 	break;
10513 #endif
10514     case SQL_DATA_SOURCE_NAME:
10515 	strmak(val, d->dsn ? d->dsn : "", valMax, valLen);
10516 	break;
10517     case SQL_DRIVER_NAME:
10518 #if defined(_WIN32) || defined(_WIN64)
10519 	GetModuleFileName(hModule, pathbuf, sizeof (pathbuf));
10520 	drvname = strrchr(pathbuf, '\\');
10521 	if (drvname == NULL) {
10522 	    drvname = strrchr(pathbuf, '/');
10523 	}
10524 	if (drvname == NULL) {
10525 	    drvname = pathbuf;
10526 	} else {
10527 	    drvname++;
10528 	}
10529 #endif
10530 	strmak(val, drvname, valMax, valLen);
10531 	break;
10532     case SQL_DRIVER_VER:
10533 	strmak(val, DRIVER_VER_INFO, valMax, valLen);
10534 	break;
10535     case SQL_FETCH_DIRECTION:
10536 	*((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
10537 	    SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
10538 	*valLen = sizeof (SQLUINTEGER);
10539 	break;
10540     case SQL_ODBC_VER:
10541 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
10542 	break;
10543     case SQL_ODBC_SAG_CLI_CONFORMANCE:
10544 	*((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
10545 	*valLen = sizeof (SQLSMALLINT);
10546 	break;
10547     case SQL_STANDARD_CLI_CONFORMANCE:
10548 	*((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
10549 	*valLen = sizeof (SQLUINTEGER);
10550 	break;
10551     case SQL_SQL_CONFORMANCE:
10552 	*((SQLUINTEGER *) val) = SQL_SC_SQL92_ENTRY;
10553 	*valLen = sizeof (SQLUINTEGER);
10554 	break;
10555     case SQL_SERVER_NAME:
10556     case SQL_DATABASE_NAME:
10557 	strmak(val, d->dbname ? d->dbname : "", valMax, valLen);
10558 	break;
10559     case SQL_SEARCH_PATTERN_ESCAPE:
10560 	strmak(val, "\\", valMax, valLen);
10561 	break;
10562     case SQL_ODBC_SQL_CONFORMANCE:
10563 	*((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
10564 	*valLen = sizeof (SQLSMALLINT);
10565 	break;
10566     case SQL_ODBC_API_CONFORMANCE:
10567 	*((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
10568 	*valLen = sizeof (SQLSMALLINT);
10569 	break;
10570     case SQL_DBMS_NAME:
10571 	strmak(val, "SQLite", valMax, valLen);
10572 	break;
10573     case SQL_DBMS_VER:
10574 	strmak(val, SQLITE4_VERSION, valMax, valLen);
10575 	break;
10576     case SQL_COLUMN_ALIAS:
10577     case SQL_NEED_LONG_DATA_LEN:
10578     case SQL_OUTER_JOINS:
10579 	strmak(val, "Y", valMax, valLen);
10580 	break;
10581     case SQL_ROW_UPDATES:
10582     case SQL_ACCESSIBLE_PROCEDURES:
10583     case SQL_PROCEDURES:
10584     case SQL_EXPRESSIONS_IN_ORDERBY:
10585     case SQL_ODBC_SQL_OPT_IEF:
10586     case SQL_LIKE_ESCAPE_CLAUSE:
10587     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
10588     case SQL_ACCESSIBLE_TABLES:
10589     case SQL_MULT_RESULT_SETS:
10590     case SQL_MULTIPLE_ACTIVE_TXN:
10591     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
10592 	strmak(val, "N", valMax, valLen);
10593 	break;
10594 #ifdef SQL_CATALOG_NAME
10595     case SQL_CATALOG_NAME:
10596 #if defined(_WIN32) || defined(_WIN64)
10597 	strmak(val, d->xcelqrx ? "Y" : "N", valMax, valLen);
10598 #else
10599 	strmak(val, "N", valMax, valLen);
10600 #endif
10601 	break;
10602 #endif
10603     case SQL_DATA_SOURCE_READ_ONLY:
10604 	strmak(val, "N", valMax, valLen);
10605 	break;
10606 #ifdef SQL_OJ_CAPABILITIES
10607     case SQL_OJ_CAPABILITIES:
10608 	*((SQLUINTEGER *) val) = SQL_OJ_LEFT;
10609 	*valLen = sizeof (SQLUINTEGER);
10610 	break;
10611 #endif
10612 #ifdef SQL_MAX_IDENTIFIER_LEN
10613     case SQL_MAX_IDENTIFIER_LEN:
10614 	*((SQLUSMALLINT *) val) = 255;
10615 	*valLen = sizeof (SQLUSMALLINT);
10616 	break;
10617 #endif
10618     case SQL_CONCAT_NULL_BEHAVIOR:
10619 	*((SQLSMALLINT *) val) = SQL_CB_NULL;
10620 	*valLen = sizeof (SQLSMALLINT);
10621 	break;
10622     case SQL_CURSOR_COMMIT_BEHAVIOR:
10623     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
10624 	*((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
10625 	*valLen = sizeof (SQLSMALLINT);
10626 	break;
10627 #ifdef SQL_CURSOR_SENSITIVITY
10628     case SQL_CURSOR_SENSITIVITY:
10629 	*((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
10630 	*valLen = sizeof (SQLUINTEGER);
10631 	break;
10632 #endif
10633     case SQL_DEFAULT_TXN_ISOLATION:
10634 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
10635 	*valLen = sizeof (SQLUINTEGER);
10636 	break;
10637 #ifdef SQL_DESCRIBE_PARAMETER
10638     case SQL_DESCRIBE_PARAMETER:
10639 	strmak(val, "Y", valMax, valLen);
10640 	break;
10641 #endif
10642     case SQL_TXN_ISOLATION_OPTION:
10643 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
10644 	*valLen = sizeof (SQLUINTEGER);
10645 	break;
10646     case SQL_IDENTIFIER_CASE:
10647 	*((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
10648 	*valLen = sizeof (SQLSMALLINT);
10649 	break;
10650     case SQL_IDENTIFIER_QUOTE_CHAR:
10651 	strmak(val, "\"", valMax, valLen);
10652 	break;
10653     case SQL_MAX_TABLE_NAME_LEN:
10654     case SQL_MAX_COLUMN_NAME_LEN:
10655 	*((SQLSMALLINT *) val) = 255;
10656 	*valLen = sizeof (SQLSMALLINT);
10657 	break;
10658     case SQL_MAX_CURSOR_NAME_LEN:
10659 	*((SQLSMALLINT *) val) = 255;
10660 	*valLen = sizeof (SQLSMALLINT);
10661 	break;
10662     case SQL_MAX_PROCEDURE_NAME_LEN:
10663 	*((SQLSMALLINT *) val) = 0;
10664 	break;
10665     case SQL_MAX_QUALIFIER_NAME_LEN:
10666     case SQL_MAX_OWNER_NAME_LEN:
10667 	*((SQLSMALLINT *) val) = 255;
10668 	break;
10669     case SQL_OWNER_TERM:
10670 	strmak(val, "", valMax, valLen);
10671 	break;
10672     case SQL_PROCEDURE_TERM:
10673 	strmak(val, "PROCEDURE", valMax, valLen);
10674 	break;
10675     case SQL_QUALIFIER_NAME_SEPARATOR:
10676 	strmak(val, ".", valMax, valLen);
10677 	break;
10678     case SQL_QUALIFIER_TERM:
10679 #if defined(_WIN32) || defined(_WIN64)
10680 	strmak(val, d->xcelqrx ? "catalog" : "", valMax, valLen);
10681 #else
10682 	strmak(val, "", valMax, valLen);
10683 #endif
10684 	break;
10685     case SQL_QUALIFIER_USAGE:
10686 #if defined(_WIN32) || defined(_WIN64)
10687 	*((SQLUINTEGER *) val) = d->xcelqrx ?
10688 	    (SQL_CU_DML_STATEMENTS | SQL_CU_INDEX_DEFINITION |
10689 	     SQL_CU_TABLE_DEFINITION) : 0;
10690 #else
10691 	*((SQLUINTEGER *) val) = 0;
10692 #endif
10693 	*valLen = sizeof (SQLUINTEGER);
10694 	break;
10695     case SQL_SCROLL_CONCURRENCY:
10696 	*((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
10697 	*valLen = sizeof (SQLUINTEGER);
10698 	break;
10699     case SQL_SCROLL_OPTIONS:
10700 	*((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
10701 	*valLen = sizeof (SQLUINTEGER);
10702 	break;
10703     case SQL_TABLE_TERM:
10704 	strmak(val, "TABLE", valMax, valLen);
10705 	break;
10706     case SQL_TXN_CAPABLE:
10707 	*((SQLSMALLINT *) val) = SQL_TC_ALL;
10708 	*valLen = sizeof (SQLSMALLINT);
10709 	break;
10710     case SQL_CONVERT_FUNCTIONS:
10711 	*((SQLUINTEGER *) val) = 0;
10712 	*valLen = sizeof (SQLUINTEGER);
10713        break;
10714     case SQL_SYSTEM_FUNCTIONS:
10715     case SQL_NUMERIC_FUNCTIONS:
10716     case SQL_STRING_FUNCTIONS:
10717     case SQL_TIMEDATE_FUNCTIONS:
10718 	*((SQLUINTEGER *) val) = 0;
10719 	*valLen = sizeof (SQLUINTEGER);
10720 	break;
10721     case SQL_CONVERT_BIGINT:
10722     case SQL_CONVERT_BIT:
10723     case SQL_CONVERT_CHAR:
10724     case SQL_CONVERT_DATE:
10725     case SQL_CONVERT_DECIMAL:
10726     case SQL_CONVERT_DOUBLE:
10727     case SQL_CONVERT_FLOAT:
10728     case SQL_CONVERT_INTEGER:
10729     case SQL_CONVERT_LONGVARCHAR:
10730     case SQL_CONVERT_NUMERIC:
10731     case SQL_CONVERT_REAL:
10732     case SQL_CONVERT_SMALLINT:
10733     case SQL_CONVERT_TIME:
10734     case SQL_CONVERT_TIMESTAMP:
10735     case SQL_CONVERT_TINYINT:
10736     case SQL_CONVERT_VARCHAR:
10737 	*((SQLUINTEGER *) val) =
10738 	    SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
10739 	    SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
10740 	    SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
10741 	    SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
10742 	    SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
10743 	*valLen = sizeof (SQLUINTEGER);
10744 	break;
10745     case SQL_CONVERT_BINARY:
10746     case SQL_CONVERT_VARBINARY:
10747     case SQL_CONVERT_LONGVARBINARY:
10748 	*((SQLUINTEGER *) val) = 0;
10749 	*valLen = sizeof (SQLUINTEGER);
10750 	break;
10751     case SQL_POSITIONED_STATEMENTS:
10752 	*((SQLUINTEGER *) val) = 0;
10753 	*valLen = sizeof (SQLUINTEGER);
10754 	break;
10755     case SQL_LOCK_TYPES:
10756 	*((SQLUINTEGER *) val) = SQL_LCK_NO_CHANGE;
10757 	*valLen = sizeof (SQLUINTEGER);
10758 	break;
10759     case SQL_BOOKMARK_PERSISTENCE:
10760 	*((SQLUINTEGER *) val) = SQL_BP_SCROLL;
10761 	*valLen = sizeof (SQLUINTEGER);
10762 	break;
10763     case SQL_UNION:
10764 	*((SQLUINTEGER *) val) = SQL_U_UNION | SQL_U_UNION_ALL;
10765 	*valLen = sizeof (SQLUINTEGER);
10766 	break;
10767     case SQL_OWNER_USAGE:
10768     case SQL_SUBQUERIES:
10769     case SQL_TIMEDATE_ADD_INTERVALS:
10770     case SQL_TIMEDATE_DIFF_INTERVALS:
10771 	*((SQLUINTEGER *) val) = 0;
10772 	*valLen = sizeof (SQLUINTEGER);
10773 	break;
10774     case SQL_QUOTED_IDENTIFIER_CASE:
10775 	*((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
10776 	*valLen = sizeof (SQLUSMALLINT);
10777 	break;
10778     case SQL_POS_OPERATIONS:
10779 	*((SQLUINTEGER *) val) = SQL_POS_POSITION | SQL_POS_UPDATE |
10780 	    SQL_POS_DELETE | SQL_POS_ADD | SQL_POS_REFRESH;
10781 	*valLen = sizeof (SQLUINTEGER);
10782 	break;
10783     case SQL_ALTER_TABLE:
10784 	*((SQLUINTEGER *) val) = 0;
10785 	*valLen = sizeof (SQLUINTEGER);
10786 	break;
10787     case SQL_CORRELATION_NAME:
10788 	*((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
10789 	*valLen = sizeof (SQLSMALLINT);
10790 	break;
10791     case SQL_NON_NULLABLE_COLUMNS:
10792 	*((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
10793 	*valLen = sizeof (SQLSMALLINT);
10794 	break;
10795     case SQL_NULL_COLLATION:
10796 	*((SQLSMALLINT *) val) = SQL_NC_START;
10797 	*valLen = sizeof (SQLSMALLINT);
10798 	break;
10799     case SQL_MAX_COLUMNS_IN_GROUP_BY:
10800     case SQL_MAX_COLUMNS_IN_ORDER_BY:
10801     case SQL_MAX_COLUMNS_IN_SELECT:
10802     case SQL_MAX_COLUMNS_IN_TABLE:
10803     case SQL_MAX_ROW_SIZE:
10804     case SQL_MAX_TABLES_IN_SELECT:
10805 	*((SQLSMALLINT *) val) = 0;
10806 	*valLen = sizeof (SQLSMALLINT);
10807 	break;
10808     case SQL_MAX_BINARY_LITERAL_LEN:
10809     case SQL_MAX_CHAR_LITERAL_LEN:
10810 	*((SQLUINTEGER *) val) = 0;
10811 	*valLen = sizeof (SQLUINTEGER);
10812 	break;
10813     case SQL_MAX_COLUMNS_IN_INDEX:
10814 	*((SQLSMALLINT *) val) = 0;
10815 	*valLen = sizeof (SQLSMALLINT);
10816 	break;
10817     case SQL_MAX_INDEX_SIZE:
10818 	*((SQLUINTEGER *) val) = 0;
10819 	*valLen = sizeof (SQLUINTEGER);
10820 	break;
10821 #ifdef SQL_MAX_IDENTIFIER_LENGTH
10822     case SQL_MAX_IDENTIFIER_LENGTH:
10823 	*((SQLUINTEGER *) val) = 255;
10824 	*valLen = sizeof (SQLUINTEGER);
10825 	break;
10826 #endif
10827     case SQL_MAX_STATEMENT_LEN:
10828 	*((SQLUINTEGER *) val) = 16384;
10829 	*valLen = sizeof (SQLUINTEGER);
10830 	break;
10831     case SQL_QUALIFIER_LOCATION:
10832 	*((SQLSMALLINT *) val) = SQL_QL_START;
10833 	*valLen = sizeof (SQLSMALLINT);
10834 	break;
10835     case SQL_GETDATA_EXTENSIONS:
10836 	*((SQLUINTEGER *) val) =
10837 	    SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
10838 	*valLen = sizeof (SQLUINTEGER);
10839 	break;
10840     case SQL_STATIC_SENSITIVITY:
10841 	*((SQLUINTEGER *) val) = 0;
10842 	*valLen = sizeof (SQLUINTEGER);
10843 	break;
10844     case SQL_FILE_USAGE:
10845 #if defined(_WIN32) || defined(_WIN64)
10846 	*((SQLSMALLINT *) val) =
10847 	    d->xcelqrx ? SQL_FILE_CATALOG : SQL_FILE_NOT_SUPPORTED;
10848 #else
10849 	*((SQLSMALLINT *) val) = SQL_FILE_NOT_SUPPORTED;
10850 #endif
10851 	*valLen = sizeof (SQLSMALLINT);
10852 	break;
10853     case SQL_GROUP_BY:
10854 	*((SQLSMALLINT *) val) = SQL_GB_GROUP_BY_EQUALS_SELECT;
10855 	*valLen = sizeof (SQLSMALLINT);
10856 	break;
10857     case SQL_KEYWORDS:
10858 	strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
10859 	       "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
10860 	       valMax, valLen);
10861 	break;
10862     case SQL_SPECIAL_CHARACTERS:
10863 #ifdef SQL_COLLATION_SEQ
10864     case SQL_COLLATION_SEQ:
10865 #endif
10866 	strmak(val, "", valMax, valLen);
10867 	break;
10868     case SQL_BATCH_SUPPORT:
10869     case SQL_BATCH_ROW_COUNT:
10870     case SQL_PARAM_ARRAY_ROW_COUNTS:
10871 	*((SQLUINTEGER *) val) = 0;
10872 	*valLen = sizeof (SQLUINTEGER);
10873 	break;
10874     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
10875 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
10876 	*valLen = sizeof (SQLUINTEGER);
10877 	break;
10878     case SQL_STATIC_CURSOR_ATTRIBUTES1:
10879 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
10880 	    SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK | SQL_CA1_POS_POSITION |
10881 	    SQL_CA1_POS_DELETE | SQL_CA1_POS_UPDATE | SQL_CA1_POS_REFRESH |
10882 	    SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_BULK_ADD |
10883 	    SQL_CA1_BULK_UPDATE_BY_BOOKMARK | SQL_CA1_BULK_DELETE_BY_BOOKMARK;
10884 	*valLen = sizeof (SQLUINTEGER);
10885 	break;
10886     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
10887     case SQL_STATIC_CURSOR_ATTRIBUTES2:
10888 	*((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
10889 	    SQL_CA2_LOCK_CONCURRENCY;
10890 	*valLen = sizeof (SQLUINTEGER);
10891 	break;
10892     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
10893     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
10894     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
10895     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
10896 	*((SQLUINTEGER *) val) = 0;
10897 	*valLen = sizeof (SQLUINTEGER);
10898 	break;
10899     case SQL_ODBC_INTERFACE_CONFORMANCE:
10900 	*((SQLUINTEGER *) val) = SQL_OIC_CORE;
10901 	*valLen = sizeof (SQLUINTEGER);
10902 	break;
10903     default:
10904 	setstatd(d, -1, "unsupported info option %d",
10905 		 (*d->ov3) ? "HYC00" : "S1C00", type);
10906 	return SQL_ERROR;
10907     }
10908     return SQL_SUCCESS;
10909 }
10910 
10911 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
10912 /**
10913  * Return information about what this ODBC driver supports.
10914  * @param dbc database connection handle
10915  * @param type type of information to be retrieved
10916  * @param val output buffer
10917  * @param valMax length of output buffer
10918  * @param valLen output length
10919  * @result ODBC error code
10920  */
10921 
10922 SQLRETURN SQL_API
SQLGetInfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)10923 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
10924 	   SQLSMALLINT *valLen)
10925 {
10926     SQLRETURN ret;
10927 
10928     HDBC_LOCK(dbc);
10929     ret = drvgetinfo(dbc, type, val, valMax, valLen);
10930     HDBC_UNLOCK(dbc);
10931     return ret;
10932 }
10933 #endif
10934 
10935 #ifdef WINTERFACE
10936 /**
10937  * Return information about what this ODBC driver supports.
10938  * @param dbc database connection handle
10939  * @param type type of information to be retrieved
10940  * @param val output buffer
10941  * @param valMax length of output buffer
10942  * @param valLen output length
10943  * @result ODBC error code
10944  */
10945 
10946 SQLRETURN SQL_API
SQLGetInfoW(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)10947 SQLGetInfoW(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
10948 	    SQLSMALLINT *valLen)
10949 {
10950     SQLRETURN ret;
10951     SQLSMALLINT len = 0;
10952 
10953     HDBC_LOCK(dbc);
10954     ret = drvgetinfo(dbc, type, val, valMax, &len);
10955     HDBC_UNLOCK(dbc);
10956     if (ret == SQL_SUCCESS) {
10957 	SQLWCHAR *v = NULL;
10958 
10959 	switch (type) {
10960 	case SQL_USER_NAME:
10961 	case SQL_DRIVER_ODBC_VER:
10962 	case SQL_DATA_SOURCE_NAME:
10963 	case SQL_DRIVER_NAME:
10964 	case SQL_DRIVER_VER:
10965 	case SQL_ODBC_VER:
10966 	case SQL_SERVER_NAME:
10967 	case SQL_DATABASE_NAME:
10968 	case SQL_SEARCH_PATTERN_ESCAPE:
10969 	case SQL_DBMS_NAME:
10970 	case SQL_DBMS_VER:
10971 	case SQL_NEED_LONG_DATA_LEN:
10972 	case SQL_ROW_UPDATES:
10973 	case SQL_ACCESSIBLE_PROCEDURES:
10974 	case SQL_PROCEDURES:
10975 	case SQL_EXPRESSIONS_IN_ORDERBY:
10976 	case SQL_ODBC_SQL_OPT_IEF:
10977 	case SQL_LIKE_ESCAPE_CLAUSE:
10978 	case SQL_ORDER_BY_COLUMNS_IN_SELECT:
10979 	case SQL_OUTER_JOINS:
10980 	case SQL_COLUMN_ALIAS:
10981 	case SQL_ACCESSIBLE_TABLES:
10982 	case SQL_MULT_RESULT_SETS:
10983 	case SQL_MULTIPLE_ACTIVE_TXN:
10984 	case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
10985 	case SQL_DATA_SOURCE_READ_ONLY:
10986 #ifdef SQL_DESCRIBE_PARAMETER
10987 	case SQL_DESCRIBE_PARAMETER:
10988 #endif
10989 	case SQL_IDENTIFIER_QUOTE_CHAR:
10990 	case SQL_OWNER_TERM:
10991 	case SQL_PROCEDURE_TERM:
10992 	case SQL_QUALIFIER_NAME_SEPARATOR:
10993 	case SQL_QUALIFIER_TERM:
10994 	case SQL_TABLE_TERM:
10995 	case SQL_KEYWORDS:
10996 	case SQL_SPECIAL_CHARACTERS:
10997 #ifdef SQL_CATALOG_NAME
10998 	case SQL_CATALOG_NAME:
10999 #endif
11000 #ifdef SQL_COLLATION_SEQ
11001 	case SQL_COLLATION_SEQ:
11002 #endif
11003 	    if (val) {
11004 		if (len > 0) {
11005 		    v = uc_from_utf((SQLCHAR *) val, len);
11006 		    if (v) {
11007 			int vmax = valMax / sizeof (SQLWCHAR);
11008 
11009 			uc_strncpy(val, v, vmax);
11010 			if (len < vmax) {
11011 			    len = min(vmax, uc_strlen(v));
11012 			    v[len] = 0;
11013 			} else {
11014 			    len = vmax;
11015 			}
11016 			uc_free(v);
11017 			len *= sizeof (SQLWCHAR);
11018 		    } else {
11019 			len = 0;
11020 		    }
11021 		}
11022 		if (len <= 0) {
11023 		    len = 0;
11024 		    if (valMax >= sizeof (SQLWCHAR)) {
11025 			*((SQLWCHAR *)val) = 0;
11026 		    }
11027 		}
11028 	    } else {
11029 		len *= sizeof (SQLWCHAR);
11030 	    }
11031 	    break;
11032 	}
11033 	if (valLen) {
11034 	    *valLen = len;
11035 	}
11036     }
11037     return ret;
11038 }
11039 #endif
11040 
11041 /**
11042  * Return information about supported ODBC API functions.
11043  * @param dbc database connection handle
11044  * @param func function code to be retrieved
11045  * @param flags output indicator
11046  * @result ODBC error code
11047  */
11048 
11049 SQLRETURN SQL_API
SQLGetFunctions(SQLHDBC dbc,SQLUSMALLINT func,SQLUSMALLINT * flags)11050 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
11051 		SQLUSMALLINT *flags)
11052 {
11053     int i;
11054     SQLUSMALLINT exists[100];
11055 
11056     if (dbc == SQL_NULL_HDBC) {
11057 	return SQL_INVALID_HANDLE;
11058     }
11059     for (i = 0; i < array_size(exists); i++) {
11060 	exists[i] = SQL_FALSE;
11061     }
11062     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
11063     exists[SQL_API_SQLFETCH] = SQL_TRUE;
11064     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
11065     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
11066     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
11067     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
11068     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
11069     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
11070     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
11071     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
11072     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
11073     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
11074     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
11075     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
11076     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
11077     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
11078     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
11079     exists[SQL_API_SQLSETCURSORNAME] = SQL_FALSE;
11080     exists[SQL_API_SQLERROR] = SQL_TRUE;
11081     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
11082     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
11083     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
11084     exists[SQL_API_SQLBULKOPERATIONS] = SQL_TRUE;
11085     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
11086     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
11087     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
11088     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
11089     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
11090     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
11091     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
11092     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
11093     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
11094     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
11095     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
11096     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
11097     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
11098     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
11099     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
11100     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
11101     exists[SQL_API_SQLTABLES] = SQL_TRUE;
11102     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
11103     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
11104     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
11105     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
11106     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
11107     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
11108     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
11109     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
11110     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
11111     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
11112     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
11113     exists[SQL_API_SQLSETPOS] = SQL_TRUE;
11114     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
11115     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
11116     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
11117     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_TRUE;
11118     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
11119     if (func == SQL_API_ALL_FUNCTIONS) {
11120 	memcpy(flags, exists, sizeof (exists));
11121     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
11122 	int i;
11123 #define SET_EXISTS(x) \
11124 	flags[(x) >> 4] |= (1 << ((x) & 0xF))
11125 #define CLR_EXISTS(x) \
11126 	flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
11127 
11128 	memset(flags, 0,
11129 	       sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
11130 	for (i = 0; i < array_size(exists); i++) {
11131 	    if (exists[i]) {
11132 		flags[i >> 4] |= (1 << (i & 0xF));
11133 	    }
11134 	}
11135 	SET_EXISTS(SQL_API_SQLALLOCHANDLE);
11136 	SET_EXISTS(SQL_API_SQLFREEHANDLE);
11137 	SET_EXISTS(SQL_API_SQLGETSTMTATTR);
11138 	SET_EXISTS(SQL_API_SQLSETSTMTATTR);
11139 	SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
11140 	SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
11141 	SET_EXISTS(SQL_API_SQLGETENVATTR);
11142 	SET_EXISTS(SQL_API_SQLSETENVATTR);
11143 	SET_EXISTS(SQL_API_SQLCLOSECURSOR);
11144 	SET_EXISTS(SQL_API_SQLBINDPARAM);
11145 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
11146 	/*
11147 	 * Some unixODBC versions have problems with
11148 	 * SQLError() vs. SQLGetDiagRec() with loss
11149 	 * of error/warning messages.
11150 	 */
11151 	SET_EXISTS(SQL_API_SQLGETDIAGREC);
11152 #endif
11153 	SET_EXISTS(SQL_API_SQLGETDIAGFIELD);
11154 	SET_EXISTS(SQL_API_SQLFETCHSCROLL);
11155 	SET_EXISTS(SQL_API_SQLENDTRAN);
11156     } else {
11157 	if (func < array_size(exists)) {
11158 	    *flags = exists[func];
11159 	} else {
11160 	    switch (func) {
11161 	    case SQL_API_SQLALLOCHANDLE:
11162 	    case SQL_API_SQLFREEHANDLE:
11163 	    case SQL_API_SQLGETSTMTATTR:
11164 	    case SQL_API_SQLSETSTMTATTR:
11165 	    case SQL_API_SQLGETCONNECTATTR:
11166 	    case SQL_API_SQLSETCONNECTATTR:
11167 	    case SQL_API_SQLGETENVATTR:
11168 	    case SQL_API_SQLSETENVATTR:
11169 	    case SQL_API_SQLCLOSECURSOR:
11170 	    case SQL_API_SQLBINDPARAM:
11171 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
11172 	    /*
11173 	     * Some unixODBC versions have problems with
11174 	     * SQLError() vs. SQLGetDiagRec() with loss
11175 	     * of error/warning messages.
11176 	     */
11177 	    case SQL_API_SQLGETDIAGREC:
11178 #endif
11179 	    case SQL_API_SQLGETDIAGFIELD:
11180 	    case SQL_API_SQLFETCHSCROLL:
11181 	    case SQL_API_SQLENDTRAN:
11182 		*flags = SQL_TRUE;
11183 		break;
11184 	    default:
11185 		*flags = SQL_FALSE;
11186 	    }
11187 	}
11188     }
11189     return SQL_SUCCESS;
11190 }
11191 
11192 /**
11193  * Internal allocate HENV.
11194  * @param env pointer to environment handle
11195  * @result ODBC error code
11196  */
11197 
11198 static SQLRETURN
drvallocenv(SQLHENV * env)11199 drvallocenv(SQLHENV *env)
11200 {
11201     ENV *e;
11202 
11203     if (env == NULL) {
11204 	return SQL_INVALID_HANDLE;
11205     }
11206     e = (ENV *) xmalloc(sizeof (ENV));
11207     if (e == NULL) {
11208 	*env = SQL_NULL_HENV;
11209 	return SQL_ERROR;
11210     }
11211     e->magic = ENV_MAGIC;
11212     e->ov3 = 0;
11213     e->pool = 0;
11214 #if defined(_WIN32) || defined(_WIN64)
11215     InitializeCriticalSection(&e->cs);
11216 #endif
11217     e->dbcs = NULL;
11218     *env = (SQLHENV) e;
11219     return SQL_SUCCESS;
11220 }
11221 
11222 /**
11223  * Allocate HENV.
11224  * @param env pointer to environment handle
11225  * @result ODBC error code
11226  */
11227 
11228 SQLRETURN SQL_API
SQLAllocEnv(SQLHENV * env)11229 SQLAllocEnv(SQLHENV *env)
11230 {
11231     return drvallocenv(env);
11232 }
11233 
11234 /**
11235  * Internal free HENV.
11236  * @param env environment handle
11237  * @result ODBC error code
11238  */
11239 
11240 static SQLRETURN
drvfreeenv(SQLHENV env)11241 drvfreeenv(SQLHENV env)
11242 {
11243     ENV *e;
11244 
11245     if (env == SQL_NULL_HENV) {
11246 	return SQL_INVALID_HANDLE;
11247     }
11248     e = (ENV *) env;
11249     if (e->magic != ENV_MAGIC) {
11250 	return SQL_SUCCESS;
11251     }
11252 #if defined(_WIN32) || defined(_WIN64)
11253     EnterCriticalSection(&e->cs);
11254 #endif
11255     if (e->dbcs) {
11256 #if defined(_WIN32) || defined(_WIN64)
11257 	LeaveCriticalSection(&e->cs);
11258 #endif
11259 	return SQL_ERROR;
11260     }
11261     e->magic = DEAD_MAGIC;
11262 #if defined(_WIN32) || defined(_WIN64)
11263     LeaveCriticalSection(&e->cs);
11264     DeleteCriticalSection(&e->cs);
11265 #endif
11266     xfree(e);
11267     return SQL_SUCCESS;
11268 }
11269 
11270 /**
11271  * Free HENV.
11272  * @param env environment handle
11273  * @result ODBC error code
11274  */
11275 
11276 SQLRETURN SQL_API
SQLFreeEnv(SQLHENV env)11277 SQLFreeEnv(SQLHENV env)
11278 {
11279     return drvfreeenv(env);
11280 }
11281 
11282 /**
11283  * Internal allocate HDBC.
11284  * @param env environment handle
11285  * @param dbc pointer to database connection handle
11286  * @result ODBC error code
11287  */
11288 
11289 static SQLRETURN
drvallocconnect(SQLHENV env,SQLHDBC * dbc)11290 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
11291 {
11292     DBC *d;
11293     ENV *e;
11294     const char *verstr;
11295     int maj = 0, min = 0, lev = 0;
11296 
11297     if (dbc == NULL) {
11298 	return SQL_ERROR;
11299     }
11300     d = (DBC *) xmalloc(sizeof (DBC));
11301     if (d == NULL) {
11302 	*dbc = SQL_NULL_HDBC;
11303 	return SQL_ERROR;
11304     }
11305     memset(d, 0, sizeof (DBC));
11306     d->curtype = SQL_CURSOR_STATIC;
11307     d->ov3 = &d->ov3val;
11308     verstr = sqlite4_libversion();
11309     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
11310     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
11311     e = (ENV *) env;
11312 #if defined(_WIN32) || defined(_WIN64)
11313     if (e->magic == ENV_MAGIC) {
11314 	EnterCriticalSection(&e->cs);
11315     }
11316 #endif
11317     if (e->magic == ENV_MAGIC) {
11318 	DBC *n, *p;
11319 
11320 	d->env = e;
11321 	d->ov3 = &e->ov3;
11322 	p = NULL;
11323 	n = e->dbcs;
11324 	while (n) {
11325 	    p = n;
11326 	    n = n->next;
11327 	}
11328 	if (p) {
11329 	    p->next = d;
11330 	} else {
11331 	    e->dbcs = d;
11332 	}
11333     }
11334 #if defined(_WIN32) || defined(_WIN64)
11335     InitializeCriticalSection(&d->cs);
11336     d->owner = 0;
11337     if (e->magic == ENV_MAGIC) {
11338 	LeaveCriticalSection(&e->cs);
11339     }
11340     d->oemcp = 1;
11341 #endif
11342     d->autocommit = 1;
11343     d->magic = DBC_MAGIC;
11344     *dbc = (SQLHDBC) d;
11345     drvgetgpps(d);
11346     return SQL_SUCCESS;
11347 }
11348 
11349 /**
11350  * Allocate HDBC.
11351  * @param env environment handle
11352  * @param dbc pointer to database connection handle
11353  * @result ODBC error code
11354  */
11355 
11356 SQLRETURN SQL_API
SQLAllocConnect(SQLHENV env,SQLHDBC * dbc)11357 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
11358 {
11359     return drvallocconnect(env, dbc);
11360 }
11361 
11362 /**
11363  * Internal free connection (HDBC).
11364  * @param dbc database connection handle
11365  * @result ODBC error code
11366  */
11367 
11368 static SQLRETURN
drvfreeconnect(SQLHDBC dbc)11369 drvfreeconnect(SQLHDBC dbc)
11370 {
11371     DBC *d;
11372     ENV *e;
11373     SQLRETURN ret = SQL_ERROR;
11374 
11375     if (dbc == SQL_NULL_HDBC) {
11376 	return SQL_INVALID_HANDLE;
11377     }
11378     d = (DBC *) dbc;
11379     if (d->magic != DBC_MAGIC) {
11380 	return SQL_INVALID_HANDLE;
11381     }
11382     e = d->env;
11383     if (e && e->magic == ENV_MAGIC) {
11384 #if defined(_WIN32) || defined(_WIN64)
11385 	EnterCriticalSection(&e->cs);
11386 #endif
11387     } else {
11388 	e = NULL;
11389     }
11390     HDBC_LOCK(dbc);
11391     if (d->sqlite) {
11392 	setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
11393 	HDBC_UNLOCK(dbc);
11394 	goto done;
11395     }
11396     while (d->stmt) {
11397 	freestmt((HSTMT) d->stmt);
11398     }
11399     if (e && e->magic == ENV_MAGIC) {
11400 	DBC *n, *p;
11401 
11402 	p = NULL;
11403 	n = e->dbcs;
11404 	while (n) {
11405 	    if (n == d) {
11406 		break;
11407 	    }
11408 	    p = n;
11409 	    n = n->next;
11410 	}
11411 	if (n) {
11412 	    if (p) {
11413 		p->next = d->next;
11414 	    } else {
11415 		e->dbcs = d->next;
11416 	    }
11417 	}
11418     }
11419     drvrelgpps(d);
11420     d->magic = DEAD_MAGIC;
11421     if (d->trace) {
11422 	fclose(d->trace);
11423     }
11424 #if defined(_WIN32) || defined(_WIN64)
11425     d->owner = 0;
11426     LeaveCriticalSection(&d->cs);
11427     DeleteCriticalSection(&d->cs);
11428 #endif
11429     xfree(d);
11430     ret = SQL_SUCCESS;
11431 done:
11432 #if defined(_WIN32) || defined(_WIN64)
11433     if (e) {
11434 	LeaveCriticalSection(&e->cs);
11435     }
11436 #endif
11437     return ret;
11438 }
11439 
11440 /**
11441  * Free connection (HDBC).
11442  * @param dbc database connection handle
11443  * @result ODBC error code
11444  */
11445 
11446 SQLRETURN SQL_API
SQLFreeConnect(SQLHDBC dbc)11447 SQLFreeConnect(SQLHDBC dbc)
11448 {
11449     return drvfreeconnect(dbc);
11450 }
11451 
11452 /**
11453  * Internal get connect attribute of HDBC.
11454  * @param dbc database connection handle
11455  * @param attr option to be retrieved
11456  * @param val output buffer
11457  * @param bufmax size of output buffer
11458  * @param buflen output length
11459  * @result ODBC error code
11460  */
11461 
11462 static SQLRETURN
drvgetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)11463 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
11464 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
11465 {
11466     DBC *d;
11467     SQLINTEGER dummy;
11468 
11469     if (dbc == SQL_NULL_HDBC) {
11470 	return SQL_INVALID_HANDLE;
11471     }
11472     d = (DBC *) dbc;
11473     if (!val) {
11474 	val = (SQLPOINTER) &dummy;
11475     }
11476     if (!buflen) {
11477 	buflen = &dummy;
11478     }
11479     switch (attr) {
11480     case SQL_ATTR_CONNECTION_DEAD:
11481 	*((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
11482 	*buflen = sizeof (SQLINTEGER);
11483 	break;
11484     case SQL_ATTR_ACCESS_MODE:
11485 	*((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
11486 	*buflen = sizeof (SQLINTEGER);
11487 	break;
11488     case SQL_ATTR_AUTOCOMMIT:
11489 	*((SQLINTEGER *) val) =
11490 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
11491 	*buflen = sizeof (SQLINTEGER);
11492 	break;
11493     case SQL_ATTR_LOGIN_TIMEOUT:
11494 	*((SQLINTEGER *) val) = 100;
11495 	*buflen = sizeof (SQLINTEGER);
11496 	break;
11497     case SQL_ATTR_ODBC_CURSORS:
11498 	*((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
11499 	*buflen = sizeof (SQLINTEGER);
11500 	break;
11501     case SQL_ATTR_PACKET_SIZE:
11502 	*((SQLINTEGER *) val) = 16384;
11503 	*buflen = sizeof (SQLINTEGER);
11504 	break;
11505     case SQL_ATTR_TXN_ISOLATION:
11506 	*((SQLINTEGER *) val) = SQL_TXN_SERIALIZABLE;
11507 	*buflen = sizeof (SQLINTEGER);
11508 	break;
11509     case SQL_ATTR_TRACEFILE:
11510     case SQL_ATTR_TRANSLATE_LIB:
11511 	*((SQLCHAR *) val) = 0;
11512 	*buflen = 0;
11513 	break;
11514     case SQL_ATTR_CURRENT_CATALOG:
11515 #if defined(_WIN32) || defined(_WIN64)
11516 	if (d->xcelqrx) {
11517 	    if ((bufmax > 4) && (val != (SQLPOINTER) &dummy)) {
11518 		strcpy((char *) val, "main");
11519 		*buflen = 4;
11520 		break;
11521 	    }
11522 	}
11523 #endif
11524 	*((SQLCHAR *) val) = 0;
11525 	*buflen = 0;
11526 	break;
11527     case SQL_ATTR_TRACE:
11528     case SQL_ATTR_QUIET_MODE:
11529     case SQL_ATTR_TRANSLATE_OPTION:
11530     case SQL_ATTR_KEYSET_SIZE:
11531     case SQL_ATTR_QUERY_TIMEOUT:
11532 	*((SQLINTEGER *) val) = 0;
11533 	*buflen = sizeof (SQLINTEGER);
11534 	break;
11535     case SQL_ATTR_PARAM_BIND_TYPE:
11536 	*((SQLULEN *) val) = SQL_PARAM_BIND_BY_COLUMN;
11537 	*buflen = sizeof (SQLUINTEGER);
11538 	break;
11539     case SQL_ATTR_ROW_BIND_TYPE:
11540 	*((SQLULEN *) val) = SQL_BIND_BY_COLUMN;
11541 	*buflen = sizeof (SQLULEN);
11542 	break;
11543     case SQL_ATTR_USE_BOOKMARKS:
11544 	*((SQLINTEGER *) val) = SQL_UB_OFF;
11545 	*buflen = sizeof (SQLINTEGER);
11546 	break;
11547     case SQL_ATTR_ASYNC_ENABLE:
11548 	*((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
11549 	*buflen = sizeof (SQLINTEGER);
11550 	break;
11551     case SQL_ATTR_NOSCAN:
11552 	*((SQLINTEGER *) val) = SQL_NOSCAN_ON;
11553 	*buflen = sizeof (SQLINTEGER);
11554 	break;
11555     case SQL_ATTR_CONCURRENCY:
11556 	*((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
11557 	*buflen = sizeof (SQLINTEGER);
11558 	break;
11559 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
11560     case SQL_ATTR_CURSOR_SENSITIVITY:
11561 	*((SQLINTEGER *) val) = SQL_UNSPECIFIED;
11562 	*buflen = sizeof (SQLINTEGER);
11563 	break;
11564 #endif
11565     case SQL_ATTR_SIMULATE_CURSOR:
11566 	*((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
11567 	*buflen = sizeof (SQLINTEGER);
11568 	break;
11569     case SQL_ATTR_MAX_ROWS:
11570 	*((SQLINTEGER *) val) = 0;
11571 	*buflen = sizeof (SQLINTEGER);
11572     case SQL_ATTR_MAX_LENGTH:
11573 	*((SQLINTEGER *) val) = 1000000000;
11574 	*buflen = sizeof (SQLINTEGER);
11575 	break;
11576     case SQL_ATTR_CURSOR_TYPE:
11577 	*((SQLINTEGER *) val) = d->curtype;
11578 	*buflen = sizeof (SQLINTEGER);
11579 	break;
11580     case SQL_ATTR_RETRIEVE_DATA:
11581 	*((SQLINTEGER *) val) = SQL_RD_ON;
11582 	*buflen = sizeof (SQLINTEGER);
11583 	break;
11584 #ifdef SQL_ATTR_METADATA_ID
11585     case SQL_ATTR_METADATA_ID:
11586 	*((SQLULEN *) val) = SQL_FALSE;
11587 	return SQL_SUCCESS;
11588 #endif
11589     default:
11590 	*((SQLINTEGER *) val) = 0;
11591 	*buflen = sizeof (SQLINTEGER);
11592 	setstatd(d, -1, "unsupported connect attribute %d",
11593 		 (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
11594 	return SQL_ERROR;
11595     }
11596     return SQL_SUCCESS;
11597 }
11598 
11599 #ifndef WINTERFACE
11600 /**
11601  * Get connect attribute of HDBC.
11602  * @param dbc database connection handle
11603  * @param attr option to be retrieved
11604  * @param val output buffer
11605  * @param bufmax size of output buffer
11606  * @param buflen output length
11607  * @result ODBC error code
11608  */
11609 
11610 SQLRETURN SQL_API
SQLGetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)11611 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
11612 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
11613 {
11614     SQLRETURN ret;
11615 
11616     HDBC_LOCK(dbc);
11617     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
11618     HDBC_UNLOCK(dbc);
11619     return ret;
11620 }
11621 #endif
11622 
11623 #ifdef WINTERFACE
11624 /**
11625  * Get connect attribute of HDBC (UNICODE version).
11626  * @param dbc database connection handle
11627  * @param attr option to be retrieved
11628  * @param val output buffer
11629  * @param bufmax size of output buffer
11630  * @param buflen output length
11631  * @result ODBC error code
11632  */
11633 
11634 SQLRETURN SQL_API
SQLGetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)11635 SQLGetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
11636 		   SQLINTEGER bufmax, SQLINTEGER *buflen)
11637 {
11638     SQLRETURN ret;
11639     SQLINTEGER len = 0;
11640 
11641     HDBC_LOCK(dbc);
11642     ret = drvgetconnectattr(dbc, attr, val, bufmax, &len);
11643     if (ret == SQL_SUCCESS) {
11644 	SQLWCHAR *v = NULL;
11645 
11646 	switch (attr) {
11647 	case SQL_ATTR_TRACEFILE:
11648 	case SQL_ATTR_CURRENT_CATALOG:
11649 	case SQL_ATTR_TRANSLATE_LIB:
11650 	    if (val) {
11651 		if (len > 0) {
11652 		    v = uc_from_utf((SQLCHAR *) val, len);
11653 		    if (v) {
11654 			int vmax = bufmax / sizeof (SQLWCHAR);
11655 
11656 			uc_strncpy(val, v, vmax);
11657 			if (len < vmax) {
11658 			    len = min(vmax, uc_strlen(v));
11659 			    v[len] = 0;
11660 			} else {
11661 			    len = vmax;
11662 			}
11663 			uc_free(v);
11664 			len *= sizeof (SQLWCHAR);
11665 		    } else {
11666 			len = 0;
11667 		    }
11668 		}
11669 		if (len <= 0) {
11670 		    len = 0;
11671 		    if (bufmax >= sizeof (SQLWCHAR)) {
11672 			*((SQLWCHAR *)val) = 0;
11673 		    }
11674 		}
11675 	    } else {
11676 		len *= sizeof (SQLWCHAR);
11677 	    }
11678 	    break;
11679 	}
11680 	if (buflen) {
11681 	    *buflen = len;
11682 	}
11683     }
11684     HDBC_UNLOCK(dbc);
11685     return ret;
11686 }
11687 #endif
11688 
11689 /**
11690  * Internal set connect attribute of HDBC.
11691  * @param dbc database connection handle
11692  * @param attr option to be set
11693  * @param val option value
11694  * @param len size of option
11695  * @result ODBC error code
11696  */
11697 
11698 static SQLRETURN
drvsetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)11699 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
11700 		  SQLINTEGER len)
11701 {
11702     DBC *d;
11703 
11704     if (dbc == SQL_NULL_HDBC) {
11705 	return SQL_INVALID_HANDLE;
11706     }
11707     d = (DBC *) dbc;
11708     switch (attr) {
11709     case SQL_AUTOCOMMIT:
11710 	d->autocommit = val == (SQLPOINTER) SQL_AUTOCOMMIT_ON;
11711 	if (d->autocommit && d->intrans) {
11712 	    return endtran(d, SQL_COMMIT, 1);
11713 	} else if (!d->autocommit) {
11714 	    s4stmt_end(d->cur_s4stmt);
11715 	}
11716 	break;
11717 #ifdef SQL_ATTR_METADATA_ID
11718     case SQL_ATTR_METADATA_ID:
11719 	if (val == (SQLPOINTER) SQL_FALSE) {
11720 	    break;
11721 	}
11722 	/* fall through */
11723 #endif
11724     default:
11725 	setstatd(d, -1, "option value changed", "01S02");
11726 	return SQL_SUCCESS_WITH_INFO;
11727     }
11728     return SQL_SUCCESS;
11729 }
11730 
11731 #ifndef WINTERFACE
11732 /**
11733  * Set connect attribute of HDBC.
11734  * @param dbc database connection handle
11735  * @param attr option to be set
11736  * @param val option value
11737  * @param len size of option
11738  * @result ODBC error code
11739  */
11740 
11741 SQLRETURN SQL_API
SQLSetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)11742 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
11743 		  SQLINTEGER len)
11744 {
11745     SQLRETURN ret;
11746 
11747     HDBC_LOCK(dbc);
11748     ret = drvsetconnectattr(dbc, attr, val, len);
11749     HDBC_UNLOCK(dbc);
11750     return ret;
11751 }
11752 #endif
11753 
11754 #ifdef WINTERFACE
11755 /**
11756  * Set connect attribute of HDBC (UNICODE version).
11757  * @param dbc database connection handle
11758  * @param attr option to be set
11759  * @param val option value
11760  * @param len size of option
11761  * @result ODBC error code
11762  */
11763 
11764 SQLRETURN SQL_API
SQLSetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)11765 SQLSetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
11766 		   SQLINTEGER len)
11767 {
11768     SQLRETURN ret;
11769 
11770     HDBC_LOCK(dbc);
11771     ret = drvsetconnectattr(dbc, attr, val, len);
11772     HDBC_UNLOCK(dbc);
11773     return ret;
11774 }
11775 #endif
11776 
11777 /**
11778  * Internal get connect option of HDBC.
11779  * @param dbc database connection handle
11780  * @param opt option to be retrieved
11781  * @param param output buffer
11782  * @result ODBC error code
11783  */
11784 
11785 static SQLRETURN
drvgetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)11786 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
11787 {
11788     DBC *d;
11789     SQLINTEGER dummy;
11790 
11791     if (dbc == SQL_NULL_HDBC) {
11792 	return SQL_INVALID_HANDLE;
11793     }
11794     d = (DBC *) dbc;
11795     if (!param) {
11796 	param = (SQLPOINTER) &dummy;
11797     }
11798     switch (opt) {
11799     case SQL_ACCESS_MODE:
11800 	*((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
11801 	break;
11802     case SQL_AUTOCOMMIT:
11803 	*((SQLINTEGER *) param) =
11804 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
11805 	break;
11806     case SQL_LOGIN_TIMEOUT:
11807 	*((SQLINTEGER *) param) = 100;
11808 	break;
11809     case SQL_ODBC_CURSORS:
11810 	*((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
11811 	break;
11812     case SQL_PACKET_SIZE:
11813 	*((SQLINTEGER *) param) = 16384;
11814 	break;
11815     case SQL_TXN_ISOLATION:
11816 	*((SQLINTEGER *) param) = SQL_TXN_SERIALIZABLE;
11817 	break;
11818     case SQL_OPT_TRACE:
11819     case SQL_OPT_TRACEFILE:
11820     case SQL_QUIET_MODE:
11821     case SQL_TRANSLATE_DLL:
11822     case SQL_TRANSLATE_OPTION:
11823     case SQL_KEYSET_SIZE:
11824     case SQL_QUERY_TIMEOUT:
11825     case SQL_BIND_TYPE:
11826     case SQL_CURRENT_QUALIFIER:
11827 	*((SQLINTEGER *) param) = 0;
11828 	break;
11829     case SQL_USE_BOOKMARKS:
11830 	*((SQLINTEGER *) param) = SQL_UB_OFF;
11831 	break;
11832     case SQL_ASYNC_ENABLE:
11833 	*((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
11834 	break;
11835     case SQL_NOSCAN:
11836 	*((SQLINTEGER *) param) = SQL_NOSCAN_ON;
11837 	break;
11838     case SQL_CONCURRENCY:
11839 	*((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
11840 	break;
11841     case SQL_SIMULATE_CURSOR:
11842 	*((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
11843 	break;
11844     case SQL_MAX_ROWS:
11845 	*((SQLINTEGER *) param) = 0;
11846 	break;
11847     case SQL_ROWSET_SIZE:
11848     case SQL_MAX_LENGTH:
11849 	*((SQLINTEGER *) param) = 1000000000;
11850 	break;
11851     case SQL_CURSOR_TYPE:
11852 	*((SQLINTEGER *) param) = d->curtype;
11853 	break;
11854     case SQL_RETRIEVE_DATA:
11855 	*((SQLINTEGER *) param) = SQL_RD_ON;
11856 	break;
11857     default:
11858 	*((SQLINTEGER *) param) = 0;
11859 	setstatd(d, -1, "unsupported connect option %d",
11860 		 (*d->ov3) ? "HYC00" : "S1C00", opt);
11861 	return SQL_ERROR;
11862     }
11863     return SQL_SUCCESS;
11864 }
11865 
11866 #ifndef WINTERFACE
11867 /**
11868  * Get connect option of HDBC.
11869  * @param dbc database connection handle
11870  * @param opt option to be retrieved
11871  * @param param output buffer
11872  * @result ODBC error code
11873  */
11874 
11875 SQLRETURN SQL_API
SQLGetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)11876 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
11877 {
11878     SQLRETURN ret;
11879 
11880     HDBC_LOCK(dbc);
11881     ret = drvgetconnectoption(dbc, opt, param);
11882     HDBC_UNLOCK(dbc);
11883     return ret;
11884 }
11885 #endif
11886 
11887 #ifdef WINTERFACE
11888 /**
11889  * Get connect option of HDBC (UNICODE version).
11890  * @param dbc database connection handle
11891  * @param opt option to be retrieved
11892  * @param param output buffer
11893  * @result ODBC error code
11894  */
11895 
11896 SQLRETURN SQL_API
SQLGetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)11897 SQLGetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
11898 {
11899     SQLRETURN ret;
11900 
11901     HDBC_LOCK(dbc);
11902     ret = drvgetconnectoption(dbc, opt, param);
11903     if (SQL_SUCCEEDED(ret)) {
11904 	switch (opt) {
11905 	case SQL_OPT_TRACEFILE:
11906 	case SQL_CURRENT_QUALIFIER:
11907 	case SQL_TRANSLATE_DLL:
11908 	    if (param) {
11909 		*(SQLWCHAR *) param = 0;
11910 	    }
11911 	    break;
11912 	}
11913     }
11914     HDBC_UNLOCK(dbc);
11915     return ret;
11916 }
11917 #endif
11918 
11919 /**
11920  * Internal set option on HDBC.
11921  * @param dbc database connection handle
11922  * @param opt option to be set
11923  * @param param option value
11924  * @result ODBC error code
11925  */
11926 
11927 static SQLRETURN
drvsetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLUINTEGER param)11928 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
11929 {
11930     DBC *d;
11931 
11932     if (dbc == SQL_NULL_HDBC) {
11933 	return SQL_INVALID_HANDLE;
11934     }
11935     d = (DBC *) dbc;
11936     switch (opt) {
11937     case SQL_AUTOCOMMIT:
11938 	d->autocommit = param == SQL_AUTOCOMMIT_ON;
11939 	if (d->autocommit && d->intrans) {
11940 	    return endtran(d, SQL_COMMIT, 1);
11941 	} else if (!d->autocommit) {
11942 	    s4stmt_end(d->cur_s4stmt);
11943 	}
11944 	break;
11945     default:
11946 	setstatd(d, -1, "option value changed", "01S02");
11947 	return SQL_SUCCESS_WITH_INFO;
11948     }
11949     return SQL_SUCCESS;
11950 }
11951 
11952 #ifndef WINTERFACE
11953 /**
11954  * Set option on HDBC.
11955  * @param dbc database connection handle
11956  * @param opt option to be set
11957  * @param param option value
11958  * @result ODBC error code
11959  */
11960 
11961 SQLRETURN SQL_API
SQLSetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)11962 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
11963 {
11964     SQLRETURN ret;
11965 
11966     HDBC_LOCK(dbc);
11967     ret = drvsetconnectoption(dbc, opt, param);
11968     HDBC_UNLOCK(dbc);
11969     return ret;
11970 }
11971 #endif
11972 
11973 #ifdef WINTERFACE
11974 /**
11975  * Set option on HDBC (UNICODE version).
11976  * @param dbc database connection handle
11977  * @param opt option to be set
11978  * @param param option value
11979  * @result ODBC error code
11980  */
11981 
11982 SQLRETURN SQL_API
SQLSetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)11983 SQLSetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
11984 {
11985     SQLRETURN ret;
11986 
11987     HDBC_LOCK(dbc);
11988     ret = drvsetconnectoption(dbc, opt, param);
11989     HDBC_UNLOCK(dbc);
11990     return ret;
11991 }
11992 #endif
11993 
11994 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
11995 
11996 /**
11997  * Handling of SQLConnect() connection attributes
11998  * for standalone operation without driver manager.
11999  * @param dsn DSN/driver connection string
12000  * @param attr attribute string to be retrieved
12001  * @param out output buffer
12002  * @param outLen length of output buffer
12003  * @result true or false
12004  */
12005 
12006 static int
getdsnattr(char * dsn,char * attr,char * out,int outLen)12007 getdsnattr(char *dsn, char *attr, char *out, int outLen)
12008 {
12009     char *str = dsn, *start;
12010     int len = strlen(attr);
12011 
12012     while (*str) {
12013 	while (*str && *str == ';') {
12014 	    ++str;
12015 	}
12016 	start = str;
12017 	if ((str = strchr(str, '=')) == NULL) {
12018 	    return 0;
12019 	}
12020 	if (str - start == len && strncasecmp(start, attr, len) == 0) {
12021 	    start = ++str;
12022 	    while (*str && *str != ';') {
12023 		++str;
12024 	    }
12025 	    len = min(outLen - 1, str - start);
12026 	    strncpy(out, start, len);
12027 	    out[len] = '\0';
12028 	    return 1;
12029 	}
12030 	while (*str && *str != ';') {
12031 	    ++str;
12032 	}
12033     }
12034     return 0;
12035 }
12036 #endif
12037 
12038 /**
12039  * Internal connect to SQLite database.
12040  * @param dbc database connection handle
12041  * @param dsn DSN string
12042  * @param dsnLen length of DSN string or SQL_NTS
12043  * @param pwd password or NULL
12044  * @param pwdLen length of password or SQL_NTS
12045  * @param isu true/false: file name is UTF8 encoded
12046  * @result ODBC error code
12047  */
12048 
12049 static SQLRETURN
drvconnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,char * pwd,int pwdLen,int isu)12050 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen, char *pwd,
12051 	   int pwdLen, int isu)
12052 {
12053     DBC *d;
12054     int len;
12055     SQLRETURN ret;
12056     char buf[SQL_MAX_MESSAGE_LENGTH * 6], dbname[SQL_MAX_MESSAGE_LENGTH];
12057     char busy[SQL_MAX_MESSAGE_LENGTH / 4], tracef[SQL_MAX_MESSAGE_LENGTH];
12058     char loadext[SQL_MAX_MESSAGE_LENGTH];
12059     char sflag[32], spflag[32], ntflag[32], nwflag[32], biflag[32];
12060     char snflag[32], lnflag[32], ncflag[32], fkflag[32], jmode[32];
12061 #if defined(_WIN32) || defined(_WIN64)
12062     char oemcp[32];
12063 #endif
12064 
12065     if (dbc == SQL_NULL_HDBC) {
12066 	return SQL_INVALID_HANDLE;
12067     }
12068     d = (DBC *) dbc;
12069     if (d->magic != DBC_MAGIC) {
12070 	return SQL_INVALID_HANDLE;
12071     }
12072     if (d->sqlite != NULL) {
12073 	setstatd(d, -1, "connection already established", "08002");
12074 	return SQL_ERROR;
12075     }
12076     buf[0] = '\0';
12077     if (dsnLen == SQL_NTS) {
12078 	len = sizeof (buf) - 1;
12079     } else {
12080 	len = min(sizeof (buf) - 1, dsnLen);
12081     }
12082     if (dsn != NULL) {
12083 	strncpy(buf, (char *) dsn, len);
12084     }
12085     buf[len] = '\0';
12086     if (buf[0] == '\0') {
12087 	setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
12088 	return SQL_ERROR;
12089     }
12090 #if defined(_WIN32) || defined(_WIN64)
12091     /*
12092      * When DSN is in UTF it must be converted to ANSI
12093      * here for ANSI SQLGetPrivateProfileString()
12094      */
12095     if (isu) {
12096 	char *cdsn = utf_to_wmb(buf, len);
12097 
12098 	if (!cdsn) {
12099 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12100 	    return SQL_ERROR;
12101 	}
12102 	strcpy(buf, cdsn);
12103 	uc_free(cdsn);
12104     }
12105 #endif
12106     busy[0] = '\0';
12107     dbname[0] = '\0';
12108 #ifdef WITHOUT_DRIVERMGR
12109     getdsnattr(buf, "database", dbname, sizeof (dbname));
12110     if (dbname[0] == '\0') {
12111 	strncpy(dbname, buf, sizeof (dbname));
12112 	dbname[sizeof (dbname) - 1] = '\0';
12113     }
12114     getdsnattr(buf, "timeout", busy, sizeof (busy));
12115     sflag[0] = '\0';
12116     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
12117     spflag[0] = '\0';
12118     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
12119     ntflag[0] = '\0';
12120     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
12121     nwflag[0] = '\0';
12122     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
12123     snflag[0] = '\0';
12124     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
12125     lnflag[0] = '\0';
12126     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
12127     ncflag[0] = '\0';
12128     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
12129     fkflag[0] = '\0';
12130     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
12131     loadext[0] = '\0';
12132     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
12133     jmode[0] = '\0';
12134     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
12135 #if defined(_WIN32) || defined(_WIN64)
12136     oemcp[0] = '\0';
12137     getdsnattr(buf, "oemcp", oemcp, sizeof (oemcp));
12138 #endif
12139     biflag[0] = '\0';
12140     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
12141 #else
12142     SQLGetPrivateProfileString(buf, "timeout", "100000",
12143 			       busy, sizeof (busy), ODBC_INI);
12144     SQLGetPrivateProfileString(buf, "database", "",
12145 			       dbname, sizeof (dbname), ODBC_INI);
12146 #if defined(_WIN32) || defined(_WIN64)
12147     /* database name read from registry is not UTF8 !!! */
12148     isu = 0;
12149 #endif
12150     SQLGetPrivateProfileString(buf, "stepapi", "",
12151 			       sflag, sizeof (sflag), ODBC_INI);
12152     SQLGetPrivateProfileString(buf, "syncpragma", "NORMAL",
12153 			       spflag, sizeof (spflag), ODBC_INI);
12154     SQLGetPrivateProfileString(buf, "notxn", "",
12155 			       ntflag, sizeof (ntflag), ODBC_INI);
12156     SQLGetPrivateProfileString(buf, "nowchar", "",
12157 			       nwflag, sizeof (nwflag), ODBC_INI);
12158     SQLGetPrivateProfileString(buf, "shortnames", "",
12159 			       snflag, sizeof (snflag), ODBC_INI);
12160     SQLGetPrivateProfileString(buf, "longnames", "",
12161 			       lnflag, sizeof (lnflag), ODBC_INI);
12162     SQLGetPrivateProfileString(buf, "nocreat", "",
12163 			       ncflag, sizeof (ncflag), ODBC_INI);
12164     SQLGetPrivateProfileString(buf, "fksupport", "",
12165 			       fkflag, sizeof (fkflag), ODBC_INI);
12166     SQLGetPrivateProfileString(buf, "loadext", "",
12167 			       loadext, sizeof (loadext), ODBC_INI);
12168     SQLGetPrivateProfileString(buf, "journalmode", "",
12169 			       jmode, sizeof (jmode), ODBC_INI);
12170 #if defined(_WIN32) || defined(_WIN64)
12171     SQLGetPrivateProfileString(buf, "oemcp", "1",
12172 			       oemcp, sizeof (oemcp), ODBC_INI);
12173 #endif
12174     SQLGetPrivateProfileString(buf, "bigint", "",
12175 			       biflag, sizeof (biflag), ODBC_INI);
12176 #endif
12177     tracef[0] = '\0';
12178 #ifdef WITHOUT_DRIVERMGR
12179     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
12180 #else
12181     SQLGetPrivateProfileString(buf, "tracefile", "",
12182 			       tracef, sizeof (tracef), ODBC_INI);
12183 #endif
12184     if (tracef[0] != '\0') {
12185 	d->trace = fopen(tracef, "a");
12186     }
12187     d->nowchar = getbool(nwflag);
12188     d->shortnames = getbool(snflag);
12189     d->longnames = getbool(lnflag);
12190     d->nocreat = getbool(ncflag);
12191     d->fksupport = getbool(fkflag);
12192 #if defined(_WIN32) || defined(_WIN64)
12193     d->oemcp = getbool(oemcp);
12194 #else
12195     d->oemcp = 0;
12196 #endif
12197     d->dobigint = getbool(biflag);
12198     d->pwd = pwd;
12199     d->pwdLen = 0;
12200     if (d->pwd) {
12201 	d->pwdLen = (pwdLen == SQL_NTS) ? strlen(d->pwd) : pwdLen;
12202     }
12203     ret = dbopen(d, dbname, isu, (char *) dsn, sflag, spflag, ntflag,
12204 		  jmode, busy);
12205     if (ret == SQL_SUCCESS) {
12206 	dbloadext(d, loadext);
12207     }
12208     return ret;
12209 }
12210 
12211 #ifndef WINTERFACE
12212 /**
12213  * Connect to SQLite database.
12214  * @param dbc database connection handle
12215  * @param dsn DSN string
12216  * @param dsnLen length of DSN string or SQL_NTS
12217  * @param uid user id string or NULL
12218  * @param uidLen length of user id string or SQL_NTS
12219  * @param pwd password string or NULL
12220  * @param pwdLen length of password string or SQL_NTS
12221  * @result ODBC error code
12222  */
12223 
12224 SQLRETURN SQL_API
SQLConnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,SQLCHAR * uid,SQLSMALLINT uidLen,SQLCHAR * pwd,SQLSMALLINT pwdLen)12225 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
12226 	   SQLCHAR *uid, SQLSMALLINT uidLen,
12227 	   SQLCHAR *pwd, SQLSMALLINT pwdLen)
12228 {
12229     SQLRETURN ret;
12230 
12231     HDBC_LOCK(dbc);
12232     ret = drvconnect(dbc, dsn, dsnLen, (char *) pwd, pwdLen, 0);
12233     HDBC_UNLOCK(dbc);
12234     return ret;
12235 }
12236 #endif
12237 
12238 #ifdef WINTERFACE
12239 /**
12240  * Connect to SQLite database.
12241  * @param dbc database connection handle
12242  * @param dsn DSN string
12243  * @param dsnLen length of DSN string or SQL_NTS
12244  * @param uid user id string or NULL
12245  * @param uidLen length of user id string or SQL_NTS
12246  * @param pwd password string or NULL
12247  * @param pwdLen length of password string or SQL_NTS
12248  * @result ODBC error code
12249  */
12250 
12251 SQLRETURN SQL_API
SQLConnectW(SQLHDBC dbc,SQLWCHAR * dsn,SQLSMALLINT dsnLen,SQLWCHAR * uid,SQLSMALLINT uidLen,SQLWCHAR * pwd,SQLSMALLINT pwdLen)12252 SQLConnectW(SQLHDBC dbc, SQLWCHAR *dsn, SQLSMALLINT dsnLen,
12253 	    SQLWCHAR *uid, SQLSMALLINT uidLen,
12254 	    SQLWCHAR *pwd, SQLSMALLINT pwdLen)
12255 {
12256     char *dsna = NULL;
12257     char *pwda = NULL;
12258     SQLRETURN ret;
12259 
12260     HDBC_LOCK(dbc);
12261     if (dsn) {
12262 	dsna = uc_to_utf_c(dsn, dsnLen);
12263 	if (!dsna) {
12264 	    DBC *d = (DBC *) dbc;
12265 
12266 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12267 	    ret = SQL_ERROR;
12268 	    goto done;
12269 	}
12270     }
12271     if (pwd) {
12272 	pwda = uc_to_utf_c(pwd, pwdLen);
12273 	if (!pwda) {
12274 	    DBC *d = (DBC *) dbc;
12275 
12276 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
12277 	    ret = SQL_ERROR;
12278 	    goto done;
12279 	}
12280     }
12281     ret = drvconnect(dbc, (SQLCHAR *) dsna, SQL_NTS, pwda, SQL_NTS, 1);
12282 done:
12283     HDBC_UNLOCK(dbc);
12284     uc_free(dsna);
12285     uc_free(pwda);
12286     return ret;
12287 }
12288 #endif
12289 
12290 /**
12291  * Internal disconnect given HDBC.
12292  * @param dbc database connection handle
12293  * @result ODBC error code
12294  */
12295 
12296 static SQLRETURN
drvdisconnect(SQLHDBC dbc)12297 drvdisconnect(SQLHDBC dbc)
12298 {
12299     DBC *d;
12300 
12301     if (dbc == SQL_NULL_HDBC) {
12302 	return SQL_INVALID_HANDLE;
12303     }
12304     d = (DBC *) dbc;
12305     if (d->magic != DBC_MAGIC) {
12306 	return SQL_INVALID_HANDLE;
12307     }
12308     if (d->intrans) {
12309 	setstatd(d, -1, "incomplete transaction", "25000");
12310 	return SQL_ERROR;
12311     }
12312     if (d->cur_s4stmt) {
12313 	s4stmt_end(d->cur_s4stmt);
12314     }
12315     if (d->sqlite) {
12316 	if (d->trace) {
12317 	    fprintf(d->trace, "-- sqlite4_close: '%s'\n",
12318 		    d->dbname);
12319 	    fflush(d->trace);
12320 	}
12321 	sqlite4_close(d->sqlite, 0);
12322 	d->sqlite = NULL;
12323     }
12324     freep(&d->dbname);
12325     freep(&d->dsn);
12326     return SQL_SUCCESS;
12327 }
12328 
12329 /**
12330  * Disconnect given HDBC.
12331  * @param dbc database connection handle
12332  * @result ODBC error code
12333  */
12334 
12335 SQLRETURN SQL_API
SQLDisconnect(SQLHDBC dbc)12336 SQLDisconnect(SQLHDBC dbc)
12337 {
12338     SQLRETURN ret;
12339 
12340     HDBC_LOCK(dbc);
12341     ret = drvdisconnect(dbc);
12342     HDBC_UNLOCK(dbc);
12343     return ret;
12344 }
12345 
12346 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64))
12347 
12348 /**
12349  * Internal standalone (w/o driver manager) database connect.
12350  * @param dbc database connection handle
12351  * @param hwnd dummy window handle or NULL
12352  * @param connIn driver connect input string
12353  * @param connInLen length of driver connect input string or SQL_NTS
12354  * @param connOut driver connect output string
12355  * @param connOutMax length of driver connect output string
12356  * @param connOutLen output length of driver connect output string
12357  * @param drvcompl completion type
12358  * @result ODBC error code
12359  */
12360 
12361 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)12362 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
12363 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
12364 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
12365 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
12366 {
12367     DBC *d;
12368     int len;
12369     SQLRETURN ret;
12370     char buf[SQL_MAX_MESSAGE_LENGTH * 6], dbname[SQL_MAX_MESSAGE_LENGTH];
12371     char dsn[SQL_MAX_MESSAGE_LENGTH], busy[SQL_MAX_MESSAGE_LENGTH / 4];
12372     char tracef[SQL_MAX_MESSAGE_LENGTH], loadext[SQL_MAX_MESSAGE_LENGTH];
12373     char pwd[SQL_MAX_MESSAGE_LENGTH];
12374     char sflag[32], spflag[32], ntflag[32], snflag[32], lnflag[32];
12375     char ncflag[32], nwflag[32], fkflag[32], jmode[32], biflag[32];
12376 
12377     if (dbc == SQL_NULL_HDBC) {
12378 	return SQL_INVALID_HANDLE;
12379     }
12380     if (drvcompl != SQL_DRIVER_COMPLETE &&
12381 	drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
12382 	drvcompl != SQL_DRIVER_PROMPT &&
12383 	drvcompl != SQL_DRIVER_NOPROMPT) {
12384 	return SQL_NO_DATA;
12385     }
12386     d = (DBC *) dbc;
12387     if (d->sqlite) {
12388 	setstatd(d, -1, "connection already established", "08002");
12389 	return SQL_ERROR;
12390     }
12391     buf[0] = '\0';
12392     if (connInLen == SQL_NTS) {
12393 	len = sizeof (buf) - 1;
12394     } else {
12395 	len = min(connInLen, sizeof (buf) - 1);
12396     }
12397     if (connIn != NULL) {
12398 	strncpy(buf, (char *) connIn, len);
12399     }
12400     buf[len] = '\0';
12401     if (!buf[0]) {
12402 	setstatd(d, -1, "invalid connect attributes",
12403 		 (*d->ov3) ? "HY090" : "S1090");
12404 	return SQL_ERROR;
12405     }
12406     dsn[0] = '\0';
12407     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
12408 
12409     /* special case: connIn is sole DSN value without keywords */
12410     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
12411 	strncpy(dsn, buf, sizeof (dsn) - 1);
12412 	dsn[sizeof (dsn) - 1] = '\0';
12413     }
12414 
12415     busy[0] = '\0';
12416     getdsnattr(buf, "timeout", busy, sizeof (busy));
12417 #ifndef WITHOUT_DRIVERMGR
12418     if (dsn[0] && !busy[0]) {
12419 	SQLGetPrivateProfileString(dsn, "timeout", "100000",
12420 				   busy, sizeof (busy), ODBC_INI);
12421     }
12422 #endif
12423     dbname[0] = '\0';
12424     getdsnattr(buf, "database", dbname, sizeof (dbname));
12425 #ifndef WITHOUT_DRIVERMGR
12426     if (dsn[0] && !dbname[0]) {
12427 	SQLGetPrivateProfileString(dsn, "database", "",
12428 				   dbname, sizeof (dbname), ODBC_INI);
12429     }
12430 #endif
12431     sflag[0] = '\0';
12432     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
12433 #ifndef WITHOUT_DRIVERMGR
12434     if (dsn[0] && !sflag[0]) {
12435 	SQLGetPrivateProfileString(dsn, "stepapi", "",
12436 				   sflag, sizeof (sflag), ODBC_INI);
12437     }
12438 #endif
12439     spflag[0] = '\0';
12440     getdsnattr(buf, "syncpragma", spflag, sizeof (spflag));
12441 #ifndef WITHOUT_DRIVERMGR
12442     if (dsn[0] && !spflag[0]) {
12443 	SQLGetPrivateProfileString(dsn, "syncpragma", "NORMAL",
12444 				   spflag, sizeof (spflag), ODBC_INI);
12445     }
12446 #endif
12447     ntflag[0] = '\0';
12448     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
12449 #ifndef WITHOUT_DRIVERMGR
12450     if (dsn[0] && !ntflag[0]) {
12451 	SQLGetPrivateProfileString(dsn, "notxn", "",
12452 				   ntflag, sizeof (ntflag), ODBC_INI);
12453     }
12454 #endif
12455     snflag[0] = '\0';
12456     getdsnattr(buf, "shortnames", snflag, sizeof (snflag));
12457 #ifndef WITHOUT_DRIVERMGR
12458     if (dsn[0] && !snflag[0]) {
12459 	SQLGetPrivateProfileString(dsn, "shortnames", "",
12460 				   snflag, sizeof (snflag), ODBC_INI);
12461     }
12462 #endif
12463     lnflag[0] = '\0';
12464     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
12465 #ifndef WITHOUT_DRIVERMGR
12466     if (dsn[0] && !lnflag[0]) {
12467 	SQLGetPrivateProfileString(dsn, "longnames", "",
12468 				   lnflag, sizeof (lnflag), ODBC_INI);
12469     }
12470 #endif
12471     ncflag[0] = '\0';
12472     getdsnattr(buf, "nocreat", ncflag, sizeof (ncflag));
12473 #ifndef WITHOUT_DRIVERMGR
12474     if (dsn[0] && !ncflag[0]) {
12475 	SQLGetPrivateProfileString(dsn, "nocreat", "",
12476 				   ncflag, sizeof (ncflag), ODBC_INI);
12477     }
12478 #endif
12479     nwflag[0] = '\0';
12480     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
12481 #ifndef WITHOUT_DRIVERMGR
12482     if (dsn[0] && !nwflag[0]) {
12483 	SQLGetPrivateProfileString(dsn, "nowchar", "",
12484 				   nwflag, sizeof (nwflag), ODBC_INI);
12485     }
12486 #endif
12487     fkflag[0] = '\0';
12488     getdsnattr(buf, "fksupport", fkflag, sizeof (fkflag));
12489 #ifndef WITHOUT_DRIVERMGR
12490     if (dsn[0] && !fkflag[0]) {
12491 	SQLGetPrivateProfileString(dsn, "fksupport", "",
12492 				   fkflag, sizeof (fkflag), ODBC_INI);
12493     }
12494 #endif
12495     loadext[0] = '\0';
12496     getdsnattr(buf, "loadext", loadext, sizeof (loadext));
12497 #ifndef WITHOUT_DRIVERMGR
12498     if (dsn[0] && !loadext[0]) {
12499 	SQLGetPrivateProfileString(dsn, "loadext", "",
12500 				   loadext, sizeof (loadext), ODBC_INI);
12501     }
12502 #endif
12503     jmode[0] = '\0';
12504     getdsnattr(buf, "journalmode", jmode, sizeof (jmode));
12505 #ifndef WITHOUT_DRIVERMGR
12506     if (dsn[0] && !jmode[0]) {
12507 	SQLGetPrivateProfileString(dsn, "journalmode", "",
12508 				   jmode, sizeof (jmode), ODBC_INI);
12509     }
12510 #endif
12511     biflag[0] = '\0';
12512     getdsnattr(buf, "bigint", biflag, sizeof (biflag));
12513 #ifndef WITHOUT_DRIVERMGR
12514     if (dsn[0] && !biflag[0]) {
12515 	SQLGetPrivateProfileString(dsn, "bigint", "",
12516 				   biflag, sizeof (biflag), ODBC_INI);
12517     }
12518 #endif
12519     pwd[0] = '\0';
12520     getdsnattr(buf, "pwd", pwd, sizeof (pwd));
12521 #ifndef WITHOUT_DRIVERMGR
12522     if (dsn[0] && !pwd[0]) {
12523 	SQLGetPrivateProfileString(dsn, "pwd", "",
12524 				   pwd, sizeof (pwd), ODBC_INI);
12525     }
12526 #endif
12527 
12528     if (!dbname[0] && !dsn[0]) {
12529 	strcpy(dsn, "SQLite");
12530 	strncpy(dbname, buf, sizeof (dbname));
12531 	dbname[sizeof (dbname) - 1] = '\0';
12532     }
12533     tracef[0] = '\0';
12534     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
12535 #ifndef WITHOUT_DRIVERMGR
12536     if (dsn[0] && !tracef[0]) {
12537 	SQLGetPrivateProfileString(dsn, "tracefile", "",
12538 				   tracef, sizeof (tracef), ODBC_INI);
12539     }
12540 #endif
12541     if (connOut || connOutLen) {
12542 	int count;
12543 
12544 	buf[0] = '\0';
12545 	count = snprintf(buf, sizeof (buf),
12546 			 "DSN=%s;Database=%s;StepAPI=%s;Timeout=%s;"
12547 			 "SyncPragma=%s;NoTXN=%s;ShortNames=%s;LongNames=%s;"
12548 			 "NoCreat=%s;NoWCHAR=%s;FKSupport=%s;Tracefile=%s;"
12549 			 "JournalMode=%s;LoadExt=%s;BigInt=%s;PWD=%s",
12550 			 dsn, dbname, sflag, busy, spflag, ntflag,
12551 			 snflag, lnflag, ncflag, nwflag, fkflag, tracef,
12552 			 jmode, loadext, biflag,pwd);
12553 	if (count < 0) {
12554 	    buf[sizeof (buf) - 1] = '\0';
12555 	}
12556 	len = min(connOutMax - 1, strlen(buf));
12557 	if (connOut) {
12558 	    strncpy((char *) connOut, buf, len);
12559 	    connOut[len] = '\0';
12560 	}
12561 	if (connOutLen) {
12562 	    *connOutLen = len;
12563 	}
12564     }
12565     if (tracef[0] != '\0') {
12566 	d->trace = fopen(tracef, "a");
12567     }
12568     d->shortnames = getbool(snflag);
12569     d->longnames = getbool(lnflag);
12570     d->nocreat = getbool(ncflag);
12571     d->nowchar = getbool(nwflag);
12572     d->fksupport = getbool(fkflag);
12573     d->dobigint = getbool(biflag);
12574     d->oemcp = 0;
12575     d->pwdLen = strlen(pwd);
12576     d->pwd = (d->pwdLen > 0) ? pwd : NULL;
12577     ret = dbopen(d, dbname, 0, dsn, sflag, spflag, ntflag, jmode, busy);
12578     memset(pwd, 0, sizeof (pwd));
12579     if (ret == SQL_SUCCESS) {
12580 	dbloadext(d, loadext);
12581     }
12582     return ret;
12583 }
12584 #endif
12585 
12586 /**
12587  * Internal free function for HSTMT.
12588  * @param stmt statement handle
12589  * @result ODBC error code
12590  */
12591 
12592 static SQLRETURN
freestmt(SQLHSTMT stmt)12593 freestmt(SQLHSTMT stmt)
12594 {
12595     STMT *s;
12596     DBC *d;
12597 
12598     if (stmt == SQL_NULL_HSTMT) {
12599 	return SQL_INVALID_HANDLE;
12600     }
12601     s = (STMT *) stmt;
12602     s4stmt_drop(s);
12603     freeresult(s, 1);
12604     freep(&s->query);
12605     d = (DBC *) s->dbc;
12606     if (d && d->magic == DBC_MAGIC) {
12607 	STMT *p, *n;
12608 
12609 	p = NULL;
12610 	n = d->stmt;
12611 	while (n) {
12612 	    if (n == s) {
12613 		break;
12614 	    }
12615 	    p = n;
12616 	    n = n->next;
12617 	}
12618 	if (n) {
12619 	    if (p) {
12620 		p->next = s->next;
12621 	    } else {
12622 		d->stmt = s->next;
12623 	    }
12624 	}
12625     }
12626     freeparams(s);
12627     freep(&s->bindparms);
12628     if (s->row_status0 != &s->row_status1) {
12629 	freep(&s->row_status0);
12630 	s->rowset_size = 1;
12631 	s->row_status0 = &s->row_status1;
12632     }
12633     xfree(s);
12634     return SQL_SUCCESS;
12635 }
12636 
12637 /**
12638  * Allocate HSTMT given HDBC (driver internal version).
12639  * @param dbc database connection handle
12640  * @param stmt pointer to statement handle
12641  * @result ODBC error code
12642  */
12643 
12644 static SQLRETURN
drvallocstmt(SQLHDBC dbc,SQLHSTMT * stmt)12645 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
12646 {
12647     DBC *d;
12648     STMT *s, *sl, *pl;
12649 
12650     if (dbc == SQL_NULL_HDBC) {
12651 	return SQL_INVALID_HANDLE;
12652     }
12653     d = (DBC *) dbc;
12654     if (d->magic != DBC_MAGIC || stmt == NULL) {
12655 	return SQL_INVALID_HANDLE;
12656     }
12657     s = (STMT *) xmalloc(sizeof (STMT));
12658     if (s == NULL) {
12659 	*stmt = SQL_NULL_HSTMT;
12660 	return SQL_ERROR;
12661     }
12662     *stmt = (SQLHSTMT) s;
12663     memset(s, 0, sizeof (STMT));
12664     s->dbc = dbc;
12665     s->ov3 = d->ov3;
12666     s->bkmrk = SQL_UB_OFF;
12667     s->bkmrkptr = 0;
12668     s->oemcp = &d->oemcp;
12669     s->nowchar[0] = d->nowchar;
12670     s->nowchar[1] = 0;
12671     s->dobigint = d->dobigint;
12672     s->curtype = d->curtype;
12673     s->row_status0 = &s->row_status1;
12674     s->rowset_size = 1;
12675     s->longnames = d->longnames;
12676     s->retr_data = SQL_RD_ON;
12677     s->max_rows = 0;
12678     s->bind_type = SQL_BIND_BY_COLUMN;
12679     s->bind_offs = NULL;
12680     s->paramset_size = 1;
12681     s->parm_bind_type = SQL_PARAM_BIND_BY_COLUMN;
12682     s->one_tbl = -1;
12683     s->has_pk = -1;
12684     s->has_rowid = -1;
12685 #ifdef _WIN64
12686     sprintf((char *) s->cursorname, "CUR_%I64X", (SQLUBIGINT) *stmt);
12687 #else
12688     sprintf((char *) s->cursorname, "CUR_%016lX", (long) *stmt);
12689 #endif
12690     sl = d->stmt;
12691     pl = NULL;
12692     while (sl) {
12693 	pl = sl;
12694 	sl = sl->next;
12695     }
12696     if (pl) {
12697 	pl->next = s;
12698     } else {
12699 	d->stmt = s;
12700     }
12701     return SQL_SUCCESS;
12702 }
12703 
12704 /**
12705  * Allocate HSTMT given HDBC.
12706  * @param dbc database connection handle
12707  * @param stmt pointer to statement handle
12708  * @result ODBC error code
12709  */
12710 
12711 SQLRETURN SQL_API
SQLAllocStmt(SQLHDBC dbc,SQLHSTMT * stmt)12712 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
12713 {
12714     SQLRETURN ret;
12715 
12716     HDBC_LOCK(dbc);
12717     ret = drvallocstmt(dbc, stmt);
12718     HDBC_UNLOCK(dbc);
12719     return ret;
12720 }
12721 
12722 /**
12723  * Internal function to perform certain kinds of free/close on STMT.
12724  * @param stmt statement handle
12725  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
12726  * @result ODBC error code
12727  */
12728 
12729 static SQLRETURN
drvfreestmt(SQLHSTMT stmt,SQLUSMALLINT opt)12730 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
12731 {
12732     STMT *s;
12733     SQLRETURN ret = SQL_SUCCESS;
12734     SQLHDBC dbc;
12735 
12736     if (stmt == SQL_NULL_HSTMT) {
12737 	return SQL_INVALID_HANDLE;
12738     }
12739     HSTMT_LOCK(stmt);
12740     s = (STMT *) stmt;
12741     dbc = s->dbc;
12742     switch (opt) {
12743     case SQL_RESET_PARAMS:
12744 	freeparams(s);
12745 	break;
12746     case SQL_UNBIND:
12747 	unbindcols(s);
12748 	break;
12749     case SQL_CLOSE:
12750 	s4stmt_end_if(s);
12751 	freeresult(s, 0);
12752 	break;
12753     case SQL_DROP:
12754 	s4stmt_end_if(s);
12755 	ret = freestmt(stmt);
12756 	break;
12757     default:
12758 	setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
12759 	ret = SQL_ERROR;
12760 	break;
12761     }
12762     HDBC_UNLOCK(dbc);
12763     return ret;
12764 }
12765 
12766 /**
12767  * Free HSTMT.
12768  * @param stmt statement handle
12769  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
12770  * @result ODBC error code
12771  */
12772 
12773 SQLRETURN SQL_API
SQLFreeStmt(SQLHSTMT stmt,SQLUSMALLINT opt)12774 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
12775 {
12776     return drvfreestmt(stmt, opt);
12777 }
12778 
12779 /**
12780  * Cancel HSTMT closing cursor.
12781  * @param stmt statement handle
12782  * @result ODBC error code
12783  */
12784 
12785 SQLRETURN SQL_API
SQLCancel(SQLHSTMT stmt)12786 SQLCancel(SQLHSTMT stmt)
12787 {
12788     if (stmt != SQL_NULL_HSTMT) {
12789 	DBC *d = (DBC *) ((STMT *) stmt)->dbc;
12790 #if defined(_WIN32) || defined(_WIN64)
12791 	/* interrupt when other thread owns critical section */
12792 	if (d->magic == DBC_MAGIC && d->owner != GetCurrentThreadId() &&
12793 	    d->owner != 0) {
12794 	    d->busyint = 1;
12795 	    sqlite4_interrupt(d->sqlite);
12796 	    return SQL_SUCCESS;
12797 	}
12798 #else
12799 	if (d->magic == DBC_MAGIC) {
12800 	    d->busyint = 1;
12801 	    sqlite4_interrupt(d->sqlite);
12802 	}
12803 #endif
12804     }
12805     return drvfreestmt(stmt, SQL_CLOSE);
12806 }
12807 
12808 /**
12809  * Internal function to get cursor name of STMT.
12810  * @param stmt statement handle
12811  * @param cursor output buffer
12812  * @param buflen length of output buffer
12813  * @param lenp output length
12814  * @result ODBC error code
12815  */
12816 
12817 static SQLRETURN
drvgetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)12818 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
12819 		 SQLSMALLINT *lenp)
12820 {
12821     STMT *s;
12822 
12823     if (stmt == SQL_NULL_HSTMT) {
12824 	return SQL_INVALID_HANDLE;
12825     }
12826     s = (STMT *) stmt;
12827     if (lenp && !cursor) {
12828 	*lenp = strlen((char *) s->cursorname);
12829 	return SQL_SUCCESS;
12830     }
12831     if (cursor) {
12832 	if (buflen > 0) {
12833 	    strncpy((char *) cursor, (char *) s->cursorname, buflen - 1);
12834 	    cursor[buflen - 1] = '\0';
12835 	}
12836 	if (lenp) {
12837 	    *lenp = min(strlen((char *) s->cursorname), buflen - 1);
12838 	}
12839     }
12840     return SQL_SUCCESS;
12841 }
12842 
12843 #ifndef WINTERFACE
12844 /**
12845  * Get cursor name of STMT.
12846  * @param stmt statement handle
12847  * @param cursor output buffer
12848  * @param buflen length of output buffer
12849  * @param lenp output length
12850  * @result ODBC error code
12851  */
12852 
12853 SQLRETURN SQL_API
SQLGetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)12854 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
12855 		 SQLSMALLINT *lenp)
12856 {
12857     SQLRETURN ret;
12858 #if defined(_WIN32) || defined(_WIN64)
12859     SQLSMALLINT len = 0;
12860 #endif
12861 
12862     HSTMT_LOCK(stmt);
12863 #if defined(_WIN32) || defined(_WIN64)
12864     if (!((STMT *) stmt)->oemcp[0]) {
12865 	ret = drvgetcursorname(stmt, cursor, buflen, lenp);
12866 	goto done;
12867     }
12868     ret = drvgetcursorname(stmt, cursor, buflen, &len);
12869     if (ret == SQL_SUCCESS) {
12870 	char *c = NULL;
12871 
12872 	if (cursor) {
12873 	    c = utf_to_wmb((char *) cursor, len);
12874 	    if (!c) {
12875 		ret = nomem((STMT *) stmt);
12876 		goto done;
12877 	    }
12878 	    c[len] = 0;
12879 	    len = strlen(c);
12880 	    if (buflen > 0) {
12881 		strncpy((char *) cursor, c, buflen - 1);
12882 		cursor[buflen - 1] = 0;
12883 	    }
12884 	    uc_free(c);
12885 	}
12886 	if (lenp) {
12887 	    *lenp = min(len, buflen - 1);
12888 	}
12889     }
12890 done:
12891     ;
12892 #else
12893     ret = drvgetcursorname(stmt, cursor, buflen, lenp);
12894 #endif
12895     HSTMT_UNLOCK(stmt);
12896     return ret;
12897 }
12898 #endif
12899 
12900 #ifdef WINTERFACE
12901 /**
12902  * Get cursor name of STMT (UNICODE version).
12903  * @param stmt statement handle
12904  * @param cursor output buffer
12905  * @param buflen length of output buffer
12906  * @param lenp output length
12907  * @result ODBC error code
12908  */
12909 
12910 SQLRETURN SQL_API
SQLGetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)12911 SQLGetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT buflen,
12912 		  SQLSMALLINT *lenp)
12913 {
12914     SQLRETURN ret;
12915     SQLSMALLINT len = 0;
12916 
12917     HSTMT_LOCK(stmt);
12918     ret = drvgetcursorname(stmt, (SQLCHAR *) cursor, buflen, &len);
12919     if (ret == SQL_SUCCESS) {
12920 	SQLWCHAR *c = NULL;
12921 
12922 	if (cursor) {
12923 	    c = uc_from_utf((SQLCHAR *) cursor, len);
12924 	    if (!c) {
12925 		ret = nomem((STMT *) stmt);
12926 		goto done;
12927 	    }
12928 	    c[len] = 0;
12929 	    len = uc_strlen(c);
12930 	    if (buflen > 0) {
12931 		uc_strncpy(cursor, c, buflen - 1);
12932 		cursor[buflen - 1] = 0;
12933 	    }
12934 	    uc_free(c);
12935 	}
12936 	if (lenp) {
12937 	    *lenp = min(len, buflen - 1);
12938 	}
12939     }
12940 done:
12941     HSTMT_UNLOCK(stmt);
12942     return ret;
12943 }
12944 #endif
12945 
12946 /**
12947  * Internal function to set cursor name on STMT.
12948  * @param stmt statement handle
12949  * @param cursor new cursor name
12950  * @param len length of cursor name or SQL_NTS
12951  * @result ODBC error code
12952  */
12953 
12954 static SQLRETURN
drvsetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)12955 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
12956 {
12957     STMT *s;
12958 
12959     if (stmt == SQL_NULL_HSTMT) {
12960 	return SQL_INVALID_HANDLE;
12961     }
12962     s = (STMT *) stmt;
12963     if (!cursor ||
12964 	!((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
12965 	  (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
12966 	setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
12967 	return SQL_ERROR;
12968     }
12969     if (len == SQL_NTS) {
12970 	len = sizeof (s->cursorname) - 1;
12971     } else {
12972 	len = min(sizeof (s->cursorname) - 1, len);
12973     }
12974     strncpy((char *) s->cursorname, (char *) cursor, len);
12975     s->cursorname[len] = '\0';
12976     return SQL_SUCCESS;
12977 }
12978 
12979 #ifndef WINTERFACE
12980 /**
12981  * Set cursor name on STMT.
12982  * @param stmt statement handle
12983  * @param cursor new cursor name
12984  * @param len length of cursor name or SQL_NTS
12985  * @result ODBC error code
12986  */
12987 
12988 SQLRETURN SQL_API
SQLSetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)12989 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
12990 {
12991 #if defined(_WIN32) || defined(_WIN64)
12992     char *c = NULL;
12993 #endif
12994     SQLRETURN ret;
12995 
12996     HSTMT_LOCK(stmt);
12997 #if defined(_WIN32) || defined(_WIN64)
12998     if (!((STMT *) stmt)->oemcp[0]) {
12999 	ret = drvsetcursorname(stmt, cursor, len);
13000 	goto done2;
13001     }
13002     if (cursor) {
13003 	c = wmb_to_utf_c((char *) cursor, len);
13004 	if (!c) {
13005 	    ret = nomem((STMT *) stmt);
13006 	    goto done;
13007 	}
13008     }
13009     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
13010 #else
13011     ret = drvsetcursorname(stmt, cursor, len);
13012 #endif
13013 #if defined(_WIN32) || defined(_WIN64)
13014 done:
13015     uc_free(c);
13016 done2:
13017     ;
13018 #endif
13019     HSTMT_UNLOCK(stmt);
13020     return ret;
13021 }
13022 #endif
13023 
13024 #ifdef WINTERFACE
13025 /**
13026  * Set cursor name on STMT (UNICODE version).
13027  * @param stmt statement handle
13028  * @param cursor new cursor name
13029  * @param len length of cursor name or SQL_NTS
13030  * @result ODBC error code
13031  */
13032 
13033 SQLRETURN SQL_API
SQLSetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT len)13034 SQLSetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT len)
13035 {
13036     char *c = NULL;
13037     SQLRETURN ret;
13038 
13039     HSTMT_LOCK(stmt);
13040     if (cursor) {
13041 	c = uc_to_utf_c(cursor, len);
13042 	if (!c) {
13043 	    ret = nomem((STMT *) stmt);
13044 	    goto done;
13045 	}
13046     }
13047     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
13048 done:
13049     uc_free(c);
13050     HSTMT_UNLOCK(stmt);
13051     return ret;
13052 }
13053 #endif
13054 
13055 /**
13056  * Close open cursor.
13057  * @param stmt statement handle
13058  * @return ODBC error code
13059  */
13060 
13061 SQLRETURN SQL_API
SQLCloseCursor(SQLHSTMT stmt)13062 SQLCloseCursor(SQLHSTMT stmt)
13063 {
13064     return drvfreestmt(stmt, SQL_CLOSE);
13065 }
13066 
13067 /**
13068  * Allocate a HENV, HDBC, or HSTMT handle.
13069  * @param type handle type
13070  * @param input input handle (HENV, HDBC)
13071  * @param output pointer to output handle (HENV, HDBC, HSTMT)
13072  * @result ODBC error code
13073  */
13074 
13075 SQLRETURN SQL_API
SQLAllocHandle(SQLSMALLINT type,SQLHANDLE input,SQLHANDLE * output)13076 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
13077 {
13078     SQLRETURN ret;
13079 
13080     switch (type) {
13081     case SQL_HANDLE_ENV:
13082 	ret = drvallocenv((SQLHENV *) output);
13083 	if (ret == SQL_SUCCESS) {
13084 	    ENV *e = (ENV *) *output;
13085 
13086 	    if (e && e->magic == ENV_MAGIC) {
13087 		e->ov3 = 1;
13088 	    }
13089 	}
13090 	return ret;
13091     case SQL_HANDLE_DBC:
13092 	return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
13093     case SQL_HANDLE_STMT:
13094 	HDBC_LOCK((SQLHDBC) input);
13095 	ret = drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
13096 	HDBC_UNLOCK((SQLHDBC) input);
13097 	return ret;
13098     }
13099     return SQL_ERROR;
13100 }
13101 
13102 /**
13103  * Free a HENV, HDBC, or HSTMT handle.
13104  * @param type handle type
13105  * @param h handle (HENV, HDBC, or HSTMT)
13106  * @result ODBC error code
13107  */
13108 
13109 SQLRETURN SQL_API
SQLFreeHandle(SQLSMALLINT type,SQLHANDLE h)13110 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
13111 {
13112     switch (type) {
13113     case SQL_HANDLE_ENV:
13114 	return drvfreeenv((SQLHENV) h);
13115     case SQL_HANDLE_DBC:
13116 	return drvfreeconnect((SQLHDBC) h);
13117     case SQL_HANDLE_STMT:
13118 	return drvfreestmt((SQLHSTMT) h, SQL_DROP);
13119     }
13120     return SQL_ERROR;
13121 }
13122 
13123 /**
13124  * Free dynamically allocated column descriptions of STMT.
13125  * @param s statement pointer
13126  */
13127 
13128 static void
freedyncols(STMT * s)13129 freedyncols(STMT *s)
13130 {
13131     if (s->dyncols) {
13132 	int i;
13133 
13134 	for (i = 0; i < s->dcols; i++) {
13135 	    freep(&s->dyncols[i].typename);
13136 	}
13137 	if (s->cols == s->dyncols) {
13138 	    s->cols = NULL;
13139 	    s->ncols = 0;
13140 	    s->one_tbl = -1;
13141 	    s->has_pk = -1;
13142 	}
13143 	freep(&s->dyncols);
13144     }
13145     s->dcols = 0;
13146 }
13147 
13148 /**
13149  * Free statement's result.
13150  * @param s statement pointer
13151  * @param clrcols flag to clear column information
13152  *
13153  * The result rows are free'd using the rowfree function pointer.
13154  * If clrcols is greater than zero, then column bindings and dynamic column
13155  * descriptions are free'd.
13156  * If clrcols is less than zero, then dynamic column descriptions are free'd.
13157  */
13158 
13159 static void
freeresult(STMT * s,int clrcols)13160 freeresult(STMT *s, int clrcols)
13161 {
13162     freep(&s->bincache);
13163     s->bincell = NULL;
13164     s->binlen = 0;
13165     if (s->rows) {
13166 	if (s->rowfree) {
13167 	    s->rowfree(s->rows);
13168 	    s->rowfree = NULL;
13169 	}
13170 	s->rows = NULL;
13171     }
13172     s->nrows = -1;
13173     if (clrcols > 0) {
13174 	freep(&s->bindcols);
13175 	s->nbindcols = 0;
13176     }
13177     if (clrcols) {
13178 	freedyncols(s);
13179 	s->cols = NULL;
13180 	s->ncols = 0;
13181 	s->nowchar[1] = 0;
13182 	s->one_tbl = -1;
13183 	s->has_pk = -1;
13184 	s->has_rowid = -1;
13185     }
13186 }
13187 
13188 /**
13189  * Reset bound columns to unbound state.
13190  * @param s statement pointer
13191  */
13192 
13193 static void
unbindcols(STMT * s)13194 unbindcols(STMT *s)
13195 {
13196     int i;
13197 
13198     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
13199 	s->bindcols[i].type = SQL_UNKNOWN_TYPE;
13200 	s->bindcols[i].max = 0;
13201 	s->bindcols[i].lenp = NULL;
13202 	s->bindcols[i].valp = NULL;
13203 	s->bindcols[i].index = i;
13204 	s->bindcols[i].offs = 0;
13205     }
13206 }
13207 
13208 /**
13209  * Reallocate space for bound columns.
13210  * @param s statement pointer
13211  * @param ncols number of columns
13212  * @result ODBC error code
13213  */
13214 
13215 static SQLRETURN
mkbindcols(STMT * s,int ncols)13216 mkbindcols(STMT *s, int ncols)
13217 {
13218     if (s->bindcols) {
13219 	if (s->nbindcols < ncols) {
13220 	    int i;
13221 	    BINDCOL *bindcols =
13222 		xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
13223 
13224 	    if (!bindcols) {
13225 		return nomem(s);
13226 	    }
13227 	    for (i = s->nbindcols; i < ncols; i++) {
13228 		bindcols[i].type = SQL_UNKNOWN_TYPE;
13229 		bindcols[i].max = 0;
13230 		bindcols[i].lenp = NULL;
13231 		bindcols[i].valp = NULL;
13232 		bindcols[i].index = i;
13233 		bindcols[i].offs = 0;
13234 	    }
13235 	    s->bindcols = bindcols;
13236 	    s->nbindcols = ncols;
13237 	}
13238     } else if (ncols > 0) {
13239 	s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
13240 	if (!s->bindcols) {
13241 	    return nomem(s);
13242 	}
13243 	s->nbindcols = ncols;
13244 	unbindcols(s);
13245     }
13246     return SQL_SUCCESS;
13247 }
13248 
13249 /**
13250  * Internal function to retrieve row data, used by SQLFetch() and
13251  * friends and SQLGetData().
13252  * @param s statement pointer
13253  * @param col column number, 0 based
13254  * @param otype output data type
13255  * @param val output buffer
13256  * @param len length of output buffer
13257  * @param lenp output length
13258  * @param partial flag for partial data retrieval
13259  * @result ODBC error code
13260  */
13261 
13262 static SQLRETURN
getrowdata(STMT * s,SQLUSMALLINT col,SQLSMALLINT otype,SQLPOINTER val,SQLINTEGER len,SQLLEN * lenp,int partial)13263 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
13264 	   SQLPOINTER val, SQLINTEGER len, SQLLEN *lenp, int partial)
13265 {
13266     char **data, valdummy[16];
13267     SQLLEN dummy;
13268     SQLINTEGER *ilenp = NULL;
13269     int valnull = 0;
13270     int type = otype;
13271     SQLRETURN sret = SQL_NO_DATA;
13272 
13273     if (!lenp) {
13274 	lenp = &dummy;
13275     }
13276     /* workaround for JDK 1.7.0 on x86_64 */
13277     if (((SQLINTEGER *) lenp) + 1 == (SQLINTEGER *) val) {
13278 	ilenp = (SQLINTEGER *) lenp;
13279 	lenp = &dummy;
13280     }
13281     if (col >= s->ncols) {
13282 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
13283 	return SQL_ERROR;
13284     }
13285     if (s->retr_data != SQL_RD_ON) {
13286 	return SQL_SUCCESS;
13287     }
13288     if (!s->rows) {
13289 	*lenp = SQL_NULL_DATA;
13290 	goto done;
13291     }
13292     if (s->rowp < 0 || s->rowp >= s->nrows) {
13293 	*lenp = SQL_NULL_DATA;
13294 	goto done;
13295     }
13296     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0,
13297 		      s->nowchar[0]);
13298 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
13299     /* MS Access hack part 3 (map SQL_C_DEFAULT to SQL_C_CHAR) */
13300     if (type == SQL_C_WCHAR && otype == SQL_C_DEFAULT) {
13301 	type = SQL_C_CHAR;
13302     }
13303 #endif
13304     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
13305     if (!val) {
13306 	valnull = 1;
13307 	val = (SQLPOINTER) valdummy;
13308     }
13309     if (*data == NULL) {
13310 	*lenp = SQL_NULL_DATA;
13311 	switch (type) {
13312 	case SQL_C_UTINYINT:
13313 	case SQL_C_TINYINT:
13314 	case SQL_C_STINYINT:
13315 #ifdef SQL_BIT
13316 	case SQL_C_BIT:
13317 #endif
13318 	    *((SQLCHAR *) val) = 0;
13319 	    break;
13320 	case SQL_C_USHORT:
13321 	case SQL_C_SHORT:
13322 	case SQL_C_SSHORT:
13323 	    *((SQLSMALLINT *) val) = 0;
13324 	    break;
13325 	case SQL_C_ULONG:
13326 	case SQL_C_LONG:
13327 	case SQL_C_SLONG:
13328 	    *((SQLINTEGER *) val) = 0;
13329 	    break;
13330 #ifdef SQL_BIGINT
13331 	case SQL_C_SBIGINT:
13332 	case SQL_C_UBIGINT:
13333 	    *((SQLBIGINT *) val) = 0;
13334 	    break;
13335 #endif
13336 	case SQL_C_FLOAT:
13337 	    *((float *) val) = 0;
13338 	    break;
13339 	case SQL_C_DOUBLE:
13340 	    *((double *) val) = 0;
13341 	    break;
13342 	case SQL_C_BINARY:
13343 	case SQL_C_CHAR:
13344 	    if (len > 0) {
13345 		*((SQLCHAR *) val) = '\0';
13346 	    }
13347 	    break;
13348 #ifdef WCHARSUPPORT
13349 	case SQL_C_WCHAR:
13350 	    if (len > 0) {
13351 		*((SQLWCHAR *) val) = '\0';
13352 	    }
13353 	    break;
13354 #endif
13355 #ifdef SQL_C_TYPE_DATE
13356 	case SQL_C_TYPE_DATE:
13357 #endif
13358 	case SQL_C_DATE:
13359 	    memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
13360 	    break;
13361 #ifdef SQL_C_TYPE_TIME
13362 	case SQL_C_TYPE_TIME:
13363 #endif
13364 	case SQL_C_TIME:
13365 	    memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
13366 	    break;
13367 #ifdef SQL_C_TYPE_TIMESTAMP
13368 	case SQL_C_TYPE_TIMESTAMP:
13369 #endif
13370 	case SQL_C_TIMESTAMP:
13371 	    memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
13372 	    break;
13373 	default:
13374 	    return SQL_ERROR;
13375 	}
13376     } else {
13377 	char *endp = NULL;
13378 #if defined(_WIN32) || defined(_WIN64)
13379 #ifdef SQL_BIGINT
13380 	char endc;
13381 #endif
13382 #endif
13383 
13384 	switch (type) {
13385 	case SQL_C_UTINYINT:
13386 	case SQL_C_TINYINT:
13387 	case SQL_C_STINYINT:
13388 	    *((SQLCHAR *) val) = strtol(*data, &endp, 0);
13389 	    if (endp && endp == *data) {
13390 		*lenp = SQL_NULL_DATA;
13391 	    } else {
13392 		*lenp = sizeof (SQLCHAR);
13393 	    }
13394 	    break;
13395 #ifdef SQL_BIT
13396 	case SQL_C_BIT:
13397 	    *((SQLCHAR *) val) = getbool(*data);
13398 	    *lenp = sizeof (SQLCHAR);
13399 	    break;
13400 #endif
13401 	case SQL_C_USHORT:
13402 	case SQL_C_SHORT:
13403 	case SQL_C_SSHORT:
13404 	    *((SQLSMALLINT *) val) = strtol(*data, &endp, 0);
13405 	    if (endp && endp == *data) {
13406 		*lenp = SQL_NULL_DATA;
13407 	    } else {
13408 		*lenp = sizeof (SQLSMALLINT);
13409 	    }
13410 	    break;
13411 	case SQL_C_ULONG:
13412 	case SQL_C_LONG:
13413 	case SQL_C_SLONG:
13414 	    *((SQLINTEGER *) val) = strtol(*data, &endp, 0);
13415 	    if (endp && endp == *data) {
13416 		*lenp = SQL_NULL_DATA;
13417 	    } else {
13418 		*lenp = sizeof (SQLINTEGER);
13419 	    }
13420 	    break;
13421 #ifdef SQL_BIGINT
13422 	case SQL_C_UBIGINT:
13423 #if defined(_WIN32) || defined(_WIN64)
13424 	    if (sscanf(*data, "%I64u%c", (SQLUBIGINT *) val, &endc) != 1) {
13425 		*lenp = SQL_NULL_DATA;
13426 	    } else {
13427 		*lenp = sizeof (SQLUBIGINT);
13428 	    }
13429 #else
13430 #ifdef __osf__
13431 	    *((SQLUBIGINT *) val) = strtoul(*data, &endp, 0);
13432 #else
13433 	    *((SQLUBIGINT *) val) = strtoull(*data, &endp, 0);
13434 #endif
13435 	    if (endp && endp == *data) {
13436 		*lenp = SQL_NULL_DATA;
13437 	    } else {
13438 		*lenp = sizeof (SQLUBIGINT);
13439 	    }
13440 #endif
13441 	    break;
13442 	case SQL_C_SBIGINT:
13443 #if defined(_WIN32) || defined(_WIN64)
13444 	    if (sscanf(*data, "%I64d%c", (SQLBIGINT *) val, &endc) != 1) {
13445 		*lenp = SQL_NULL_DATA;
13446 	    } else {
13447 		*lenp = sizeof (SQLBIGINT);
13448 	    }
13449 #else
13450 #ifdef __osf__
13451 	    *((SQLBIGINT *) val) = strtol(*data, &endp, 0);
13452 #else
13453 	    *((SQLBIGINT *) val) = strtoll(*data, &endp, 0);
13454 #endif
13455 	    if (endp && endp == *data) {
13456 		*lenp = SQL_NULL_DATA;
13457 	    } else {
13458 		*lenp = sizeof (SQLBIGINT);
13459 	    }
13460 #endif
13461 	    break;
13462 #endif
13463 	case SQL_C_FLOAT:
13464 	    *((float *) val) = ln_strtod(*data, &endp);
13465 	    if (endp && endp == *data) {
13466 		*lenp = SQL_NULL_DATA;
13467 	    } else {
13468 		*lenp = sizeof (float);
13469 	    }
13470 	    break;
13471 	case SQL_C_DOUBLE:
13472 	    *((double *) val) = ln_strtod(*data, &endp);
13473 	    if (endp && endp == *data) {
13474 		*lenp = SQL_NULL_DATA;
13475 	    } else {
13476 		*lenp = sizeof (double);
13477 	    }
13478 	    break;
13479 	case SQL_C_BINARY: {
13480 	    int dlen, offs = 0;
13481 	    char *bin;
13482 
13483 	    if (valnull) {
13484 		freep(&s->bincache);
13485 		s->binlen = 0;
13486 		goto doCHAR;
13487 	    }
13488 	    if (*data == s->bincell) {
13489 		if (s->bincache) {
13490 		    bin = s->bincache;
13491 		    dlen = s->binlen;
13492 		} else {
13493 		    goto doCHAR;
13494 		}
13495 	    } else {
13496 		char *dp;
13497 		int i;
13498 
13499 		freep(&s->bincache);
13500 		dp = *data;
13501 		dlen = strlen(dp);
13502 		s->bincell = dp;
13503 		s->binlen = 0;
13504 		if (!(dp[0] == 'x' || dp[0] == 'X') || dp[1] != '\'' ||
13505 		    dp[dlen - 1] != '\'') {
13506 		    goto doCHAR;
13507 		}
13508 		dlen -= 2;
13509 		dp += 2;
13510 		dlen = dlen / 2;
13511 		s->bincache = bin = xmalloc(dlen + 1);
13512 		if (!bin) {
13513 		    return nomem(s);
13514 		}
13515 		s->binlen = dlen;
13516 		memset(bin, 0, dlen);
13517 		bin[dlen] = '\0';	/* terminator, just in case */
13518 		for (i = 0; i < dlen; i++) {
13519 		    char *x;
13520 		    int v;
13521 
13522 		    if (!*dp || !(x = strchr(xdigits, *dp))) {
13523 			goto converr;
13524 		    }
13525 		    v = x - xdigits;
13526 		    bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
13527 		    ++dp;
13528 		    if (!*dp || !(x = strchr(xdigits, *dp))) {
13529 converr:
13530 			freep(&s->bincache);
13531 			s->binlen = 0;
13532 			setstat(s, -1, "conversion error",
13533 				(*s->ov3) ? "HY000" : "S1000");
13534 			return SQL_ERROR;
13535 		    }
13536 		    v = x - xdigits;
13537 		    bin[i] |= (v >= 16) ? (v - 6) : v;
13538 		    ++dp;
13539 		}
13540 		bin = s->bincache;
13541 	    }
13542 	    if (partial && len && s->bindcols) {
13543 		if (s->bindcols[col].offs >= dlen) {
13544 		    *lenp = 0;
13545 		    if (!dlen && s->bindcols[col].offs == dlen) {
13546 			s->bindcols[col].offs = 1;
13547 			sret = SQL_SUCCESS;
13548 			goto done;
13549 		    }
13550 		    s->bindcols[col].offs = 0;
13551 		    sret = SQL_NO_DATA;
13552 		    goto done;
13553 		}
13554 		offs = s->bindcols[col].offs;
13555 		dlen -= offs;
13556 	    }
13557 	    if (val && len) {
13558 		memcpy(val, bin + offs, min(len, dlen));
13559 	    }
13560 	    if (len < 1) {
13561 		*lenp = dlen;
13562 	    } else {
13563 		*lenp = min(len, dlen);
13564 		if (*lenp == len && *lenp != dlen) {
13565 		    *lenp = SQL_NO_TOTAL;
13566 		}
13567 	    }
13568 	    if (partial && len && s->bindcols) {
13569 		if (*lenp == SQL_NO_TOTAL) {
13570 		    *lenp = dlen;
13571 		    s->bindcols[col].offs += len;
13572 		    setstat(s, -1, "data right truncated", "01004");
13573 		    if (s->bindcols[col].lenp) {
13574 			*s->bindcols[col].lenp = dlen;
13575 		    }
13576 		    sret = SQL_SUCCESS_WITH_INFO;
13577 		    goto done;
13578 		}
13579 		s->bindcols[col].offs += *lenp;
13580 	    }
13581 	    if (*lenp == SQL_NO_TOTAL) {
13582 		*lenp = dlen;
13583 		setstat(s, -1, "data right truncated", "01004");
13584 		sret = SQL_SUCCESS_WITH_INFO;
13585 		goto done;
13586 	    }
13587 	    break;
13588 	}
13589 	doCHAR:
13590 #ifdef WCHARSUPPORT
13591 	case SQL_C_WCHAR:
13592 #endif
13593 	case SQL_C_CHAR: {
13594 	    int doz, zlen = len - 1;
13595 	    int dlen = strlen(*data);
13596 	    int offs = 0;
13597 #ifdef WCHARSUPPORT
13598 	    SQLWCHAR *ucdata = NULL;
13599 	    SQLCHAR *cdata = (SQLCHAR *) *data;
13600 #endif
13601 
13602 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
13603 	    /* MS Access hack part 2 (reserved error -7748) */
13604 	    if (!valnull &&
13605 		(s->cols == statSpec2P || s->cols == statSpec3P) &&
13606 		type == SQL_C_WCHAR) {
13607 		if (len > 0 && len <= sizeof (SQLWCHAR)) {
13608 		    ((char *) val)[0] = data[0][0];
13609 		    memset((char *) val + 1, 0, len - 1);
13610 		    *lenp = 1;
13611 		    sret = SQL_SUCCESS;
13612 		    goto done;
13613 		}
13614 	    }
13615 #endif
13616 
13617 #ifdef WCHARSUPPORT
13618 	    switch (type) {
13619 	    case SQL_C_CHAR:
13620 		doz = 1;
13621 		break;
13622 	    case SQL_C_WCHAR:
13623 		doz = sizeof (SQLWCHAR);
13624 		break;
13625 	    default:
13626 		doz = 0;
13627 		break;
13628 	    }
13629 	    if (type == SQL_C_WCHAR) {
13630 		ucdata = uc_from_utf(cdata, dlen);
13631 		if (!ucdata) {
13632 		    return nomem(s);
13633 		}
13634 		dlen = uc_strlen(ucdata) * sizeof (SQLWCHAR);
13635 	    }
13636 #if defined(_WIN32) || defined(_WIN64)
13637 	    else if (*s->oemcp && type == SQL_C_CHAR) {
13638 		ucdata = (SQLWCHAR *) utf_to_wmb((char *) cdata, dlen);
13639 		if (!ucdata) {
13640 		    return nomem(s);
13641 		}
13642 		cdata = (SQLCHAR *) ucdata;
13643 		dlen = strlen((char *) cdata);
13644 	    }
13645 #endif
13646 #else
13647 	    doz = (type == SQL_C_CHAR) ? 1 : 0;
13648 #endif
13649 	    if (partial && len && s->bindcols) {
13650 		if (s->bindcols[col].offs >= dlen) {
13651 #ifdef WCHARSUPPORT
13652 		    uc_free(ucdata);
13653 #endif
13654 		    *lenp = 0;
13655 		    if (doz && val) {
13656 #ifdef WCHARSUPPORT
13657 			if (type == SQL_C_WCHAR) {
13658 			    ((SQLWCHAR *) val)[0] = 0;
13659 			} else {
13660 			    ((char *) val)[0] = '\0';
13661 			}
13662 #else
13663 			((char *) val)[0] = '\0';
13664 #endif
13665 		    }
13666 		    if (!dlen && s->bindcols[col].offs == dlen) {
13667 			s->bindcols[col].offs = 1;
13668 			sret = SQL_SUCCESS;
13669 			goto done;
13670 		    }
13671 		    s->bindcols[col].offs = 0;
13672 		    sret = SQL_NO_DATA;
13673 		    goto done;
13674 		}
13675 		offs = s->bindcols[col].offs;
13676 		dlen -= offs;
13677 	    }
13678 	    if (val && !valnull && len) {
13679 #ifdef WCHARSUPPORT
13680 		if (type == SQL_C_WCHAR) {
13681 		    uc_strncpy(val, ucdata + offs / sizeof (SQLWCHAR),
13682 			       (len - doz) / sizeof (SQLWCHAR));
13683 		} else {
13684 		    strncpy(val, (char *) cdata + offs, len - doz);
13685 		}
13686 #else
13687 		strncpy(val, *data + offs, len - doz);
13688 #endif
13689 	    }
13690 	    if (valnull || len < 1) {
13691 		*lenp = dlen;
13692 	    } else {
13693 		*lenp = min(len - doz, dlen);
13694 		if (*lenp == len - doz && *lenp != dlen) {
13695 		    *lenp = SQL_NO_TOTAL;
13696 		} else if (*lenp < zlen) {
13697 		    zlen = *lenp;
13698 		}
13699 	    }
13700 	    if (len && !valnull && doz) {
13701 #ifdef WCHARSUPPORT
13702 		if (type == SQL_C_WCHAR) {
13703 		    ((SQLWCHAR *) val)[zlen / sizeof (SQLWCHAR)] = 0;
13704 		} else {
13705 		    ((char *) val)[zlen] = '\0';
13706 		}
13707 #else
13708 		((char *) val)[zlen] = '\0';
13709 #endif
13710 	    }
13711 #ifdef WCHARSUPPORT
13712 	    uc_free(ucdata);
13713 #endif
13714 	    if (partial && len && s->bindcols) {
13715 		if (*lenp == SQL_NO_TOTAL) {
13716 		    *lenp = dlen;
13717 		    s->bindcols[col].offs += len - doz;
13718 		    setstat(s, -1, "data right truncated", "01004");
13719 		    if (s->bindcols[col].lenp) {
13720 			*s->bindcols[col].lenp = dlen;
13721 		    }
13722 		    sret = SQL_SUCCESS_WITH_INFO;
13723 		    goto done;
13724 		}
13725 		s->bindcols[col].offs += *lenp;
13726 	    }
13727 	    if (*lenp == SQL_NO_TOTAL) {
13728 		*lenp = dlen;
13729 		setstat(s, -1, "data right truncated", "01004");
13730 		sret = SQL_SUCCESS_WITH_INFO;
13731 		goto done;
13732 	    }
13733 	    break;
13734 	}
13735 #ifdef SQL_C_TYPE_DATE
13736 	case SQL_C_TYPE_DATE:
13737 #endif
13738 	case SQL_C_DATE:
13739 	    if (str2date(*data, (DATE_STRUCT *) val) < 0) {
13740 		*lenp = SQL_NULL_DATA;
13741 	    } else {
13742 		*lenp = sizeof (DATE_STRUCT);
13743 	    }
13744 	    break;
13745 #ifdef SQL_C_TYPE_TIME
13746 	case SQL_C_TYPE_TIME:
13747 #endif
13748 	case SQL_C_TIME:
13749 	    if (str2time(*data, (TIME_STRUCT *) val) < 0) {
13750 		*lenp = SQL_NULL_DATA;
13751 	    } else {
13752 		*lenp = sizeof (TIME_STRUCT);
13753 	    }
13754 	    break;
13755 #ifdef SQL_C_TYPE_TIMESTAMP
13756 	case SQL_C_TYPE_TIMESTAMP:
13757 #endif
13758 	case SQL_C_TIMESTAMP:
13759 	    if (str2timestamp(*data, (TIMESTAMP_STRUCT *) val) < 0) {
13760 		*lenp = SQL_NULL_DATA;
13761 	    } else {
13762 		*lenp = sizeof (TIMESTAMP_STRUCT);
13763 	    }
13764 	    switch (s->cols[col].prec) {
13765 	    case 0:
13766 		((TIMESTAMP_STRUCT *) val)->fraction = 0;
13767 		break;
13768 	    case 1:
13769 		((TIMESTAMP_STRUCT *) val)->fraction /= 100000000;
13770 		((TIMESTAMP_STRUCT *) val)->fraction *= 100000000;
13771 		break;
13772 	    case 2:
13773 		((TIMESTAMP_STRUCT *) val)->fraction /= 10000000;
13774 		((TIMESTAMP_STRUCT *) val)->fraction *= 10000000;
13775 		break;
13776 	    }
13777 	    break;
13778 	default:
13779 	    return SQL_ERROR;
13780 	}
13781     }
13782     sret = SQL_SUCCESS;
13783 done:
13784     if (ilenp) {
13785 	*ilenp = *lenp;
13786     }
13787     return sret;
13788 }
13789 
13790 /**
13791  * Interal bind C variable to column of result set.
13792  * @param stmt statement handle
13793  * @param col column number, starting at 1
13794  * @param type output type
13795  * @param val output buffer
13796  * @param max length of output buffer
13797  * @param lenp output length pointer
13798  * @result ODBC error code
13799  */
13800 
13801 static SQLRETURN
drvbindcol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)13802 drvbindcol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
13803 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
13804 {
13805     STMT *s;
13806     int sz = 0;
13807 
13808     if (stmt == SQL_NULL_HSTMT) {
13809 	return SQL_INVALID_HANDLE;
13810     }
13811     s = (STMT *) stmt;
13812     if (col < 1) {
13813 	if (col == 0 && s->bkmrk == SQL_UB_ON &&
13814 	    type == SQL_C_BOOKMARK) {
13815 	    s->bkmrkcol.type = val ? type : SQL_UNKNOWN_TYPE;
13816 	    s->bkmrkcol.max = val ? sizeof (SQLINTEGER) : 0;
13817 	    s->bkmrkcol.lenp = val ? lenp : 0;
13818 	    s->bkmrkcol.valp = val;
13819 	    s->bkmrkcol.offs = 0;
13820 	    if (val && lenp) {
13821 		*lenp = 0;
13822 	    }
13823 	    return SQL_SUCCESS;
13824 	} else if (col == 0 && s->bkmrk == SQL_UB_VARIABLE &&
13825 		   type == SQL_C_VARBOOKMARK &&
13826 		   max >= sizeof (sqlite4_int64)) {
13827 	    s->bkmrkcol.type = val ? type : SQL_UNKNOWN_TYPE;
13828 	    s->bkmrkcol.max = val ? max : 0;
13829 	    s->bkmrkcol.lenp = val ? lenp : 0;
13830 	    s->bkmrkcol.valp = val;
13831 	    s->bkmrkcol.offs = 0;
13832 	    if (val && lenp) {
13833 		*lenp = 0;
13834 	    }
13835 	    return SQL_SUCCESS;
13836 	}
13837 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
13838 	return SQL_ERROR;
13839     }
13840     if (mkbindcols(s, col) != SQL_SUCCESS) {
13841 	return SQL_ERROR;
13842     }
13843     --col;
13844     if (type == SQL_C_DEFAULT) {
13845 	type = mapdeftype(type, s->cols[col].type, 0,
13846 			  s->nowchar[0] || s->nowchar[1]);
13847     }
13848     switch (type) {
13849     case SQL_C_LONG:
13850     case SQL_C_ULONG:
13851     case SQL_C_SLONG:
13852 	sz = sizeof (SQLINTEGER);
13853 	break;
13854     case SQL_C_TINYINT:
13855     case SQL_C_UTINYINT:
13856     case SQL_C_STINYINT:
13857 	sz = sizeof (SQLCHAR);
13858 	break;
13859     case SQL_C_SHORT:
13860     case SQL_C_USHORT:
13861     case SQL_C_SSHORT:
13862 	sz = sizeof (SQLSMALLINT);
13863 	break;
13864     case SQL_C_FLOAT:
13865 	sz = sizeof (SQLFLOAT);
13866 	break;
13867     case SQL_C_DOUBLE:
13868 	sz = sizeof (SQLDOUBLE);
13869 	break;
13870     case SQL_C_TIMESTAMP:
13871 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
13872 	break;
13873     case SQL_C_TIME:
13874 	sz = sizeof (SQL_TIME_STRUCT);
13875 	break;
13876     case SQL_C_DATE:
13877 	sz = sizeof (SQL_DATE_STRUCT);
13878 	break;
13879     case SQL_C_CHAR:
13880 	break;
13881 #ifdef WCHARSUPPORT
13882     case SQL_C_WCHAR:
13883 	break;
13884 #endif
13885 #ifdef SQL_C_TYPE_DATE
13886     case SQL_C_TYPE_DATE:
13887 	sz = sizeof (SQL_DATE_STRUCT);
13888 	break;
13889 #endif
13890 #ifdef SQL_C_TYPE_TIME
13891     case SQL_C_TYPE_TIME:
13892 	sz = sizeof (SQL_TIME_STRUCT);
13893 	break;
13894 #endif
13895 #ifdef SQL_C_TYPE_TIMESTAMP
13896     case SQL_C_TYPE_TIMESTAMP:
13897 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
13898 	break;
13899 #endif
13900 #ifdef SQL_BIT
13901     case SQL_C_BIT:
13902 	sz = sizeof (SQLCHAR);
13903 	break;
13904 #endif
13905     case SQL_C_BINARY:
13906 	break;
13907 #ifdef SQL_BIGINT
13908     case SQL_C_SBIGINT:
13909     case SQL_C_UBIGINT:
13910 	sz = sizeof (SQLBIGINT);
13911 	break;
13912 #endif
13913     default:
13914 	if (val == NULL) {
13915 	    /* fall through, unbinding column */
13916 	    break;
13917 	}
13918 	setstat(s, -1, "invalid type %d", "HY003", type);
13919 	return SQL_ERROR;
13920     }
13921     if (val == NULL) {
13922 	/* unbind column */
13923 	s->bindcols[col].type = SQL_UNKNOWN_TYPE;
13924 	s->bindcols[col].max = 0;
13925 	s->bindcols[col].lenp = NULL;
13926 	s->bindcols[col].valp = NULL;
13927 	s->bindcols[col].offs = 0;
13928     } else {
13929 	if (sz == 0 && max < 0) {
13930 	    setstat(s, -1, "invalid length", "HY090");
13931 	    return SQL_ERROR;
13932 	}
13933 	s->bindcols[col].type = type;
13934 	s->bindcols[col].max = (sz == 0) ? max : sz;
13935 	s->bindcols[col].lenp = lenp;
13936 	s->bindcols[col].valp = val;
13937 	s->bindcols[col].offs = 0;
13938 	if (lenp) {
13939 	    *lenp = 0;
13940 	}
13941     }
13942     return SQL_SUCCESS;
13943 }
13944 
13945 /**
13946  * Bind C variable to column of result set.
13947  * @param stmt statement handle
13948  * @param col column number, starting at 1
13949  * @param type output type
13950  * @param val output buffer
13951  * @param max length of output buffer
13952  * @param lenp output length pointer
13953  * @result ODBC error code
13954  */
13955 
13956 SQLRETURN SQL_API
SQLBindCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)13957 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
13958 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
13959 {
13960     SQLRETURN ret;
13961 
13962     HSTMT_LOCK(stmt);
13963     ret = drvbindcol(stmt, col, type, val, max, lenp);
13964     HSTMT_UNLOCK(stmt);
13965     return ret;
13966 }
13967 
13968 /**
13969  * Columns for result set of SQLTables().
13970  */
13971 
13972 static COL tableSpec2[] = {
13973     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
13974     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
13975     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
13976     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
13977     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
13978 };
13979 
13980 static COL tableSpec3[] = {
13981     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
13982     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
13983     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
13984     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
13985     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
13986 };
13987 
13988 /**
13989  * Retrieve information on tables and/or views.
13990  * @param stmt statement handle
13991  * @param cat catalog name/pattern or NULL
13992  * @param catLen length of catalog name/pattern or SQL_NTS
13993  * @param schema schema name/pattern or NULL
13994  * @param schemaLen length of schema name/pattern or SQL_NTS
13995  * @param table table name/pattern or NULL
13996  * @param tableLen length of table name/pattern or SQL_NTS
13997  * @param type types of tables string or NULL
13998  * @param typeLen length of types of tables string or SQL_NTS
13999  * @result ODBC error code
14000  */
14001 
14002 static SQLRETURN
drvtables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)14003 drvtables(SQLHSTMT stmt,
14004 	  SQLCHAR *cat, SQLSMALLINT catLen,
14005 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
14006 	  SQLCHAR *table, SQLSMALLINT tableLen,
14007 	  SQLCHAR *type, SQLSMALLINT typeLen)
14008 {
14009     SQLRETURN ret;
14010     STMT *s;
14011     DBC *d;
14012     int ncols, asize, rc, size, npatt;
14013     char *errp = NULL, *sql, tname[512];
14014     char *where = "(type = 'table' or type = 'view')";
14015 
14016     ret = mkresultset(stmt, tableSpec2, array_size(tableSpec2),
14017 		      tableSpec3, array_size(tableSpec3), &asize);
14018     if (ret != SQL_SUCCESS) {
14019 	return ret;
14020     }
14021     s = (STMT *) stmt;
14022     d = (DBC *) s->dbc;
14023     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
14024 	int size = 3 * asize;
14025 
14026 	s->rows = xmalloc(size * sizeof (char *));
14027 	if (!s->rows) {
14028 	    s->nrows = 0;
14029 	    return nomem(s);
14030 	}
14031 	memset(s->rows, 0, sizeof (char *) * size);
14032 	s->ncols = asize;
14033 	s->rows[s->ncols + 0] = "";
14034 	s->rows[s->ncols + 1] = "";
14035 	s->rows[s->ncols + 2] = "";
14036 	s->rows[s->ncols + 3] = "TABLE";
14037 	s->rows[s->ncols + 5] = "";
14038 	s->rows[s->ncols + 6] = "";
14039 	s->rows[s->ncols + 7] = "";
14040 	s->rows[s->ncols + 8] = "VIEW";
14041 #ifdef MEMORY_DEBUG
14042 	s->rowfree = xfree__;
14043 #else
14044 	s->rowfree = sqlite4_free;
14045 #endif
14046 	s->nrows = 2;
14047 	s->rowp = s->rowprs = -1;
14048 	return SQL_SUCCESS;
14049     }
14050     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
14051 	table = NULL;
14052 	goto doit;
14053     }
14054     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
14055 	schema[0] == '%') {
14056 	if ((!cat || catLen == 0 || !cat[0]) &&
14057 	    (!table || tableLen == 0 || !table[0])) {
14058 	    table = NULL;
14059 	    goto doit;
14060 	}
14061     }
14062     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] != '\0') {
14063 	char tmp[256], *t;
14064 	int with_view = 0, with_table = 0;
14065 
14066 	if (typeLen == SQL_NTS) {
14067 	    strncpy(tmp, (char *) type, sizeof (tmp));
14068 	    tmp[sizeof (tmp) - 1] = '\0';
14069 	} else {
14070 	    int len = min(sizeof (tmp) - 1, typeLen);
14071 
14072 	    strncpy(tmp, (char *) type, len);
14073 	    tmp[len] = '\0';
14074 	}
14075 	t = tmp;
14076 	while (*t) {
14077 	    *t = TOLOWER(*t);
14078 	    t++;
14079 	}
14080 	t = tmp;
14081 	unescpat(t);
14082 	while (t) {
14083 	    if (t[0] == '\'') {
14084 		++t;
14085 	    }
14086 	    if (strncmp(t, "table", 5) == 0) {
14087 		with_table++;
14088 	    } else if (strncmp(t, "view", 4) == 0) {
14089 		with_view++;
14090 	    }
14091 	    t = strchr(t, ',');
14092 	    if (t) {
14093 		++t;
14094 	    }
14095 	}
14096 	if (with_view && with_table) {
14097 	    /* where is already preset */
14098 	} else if (with_view && !with_table) {
14099 	    where = "type = 'view'";
14100 	} else if (!with_view && with_table) {
14101 	    where = "type = 'table'";
14102 	} else {
14103 	    return SQL_SUCCESS;
14104 	}
14105     }
14106 doit:
14107     if (!table) {
14108 	size = 1;
14109 	tname[0] = '%';
14110     } else {
14111 	if (tableLen == SQL_NTS) {
14112 	    size = sizeof (tname) - 1;
14113 	} else {
14114 	    size = min(sizeof (tname) - 1, tableLen);
14115 	}
14116 	strncpy(tname, (char *) table, size);
14117     }
14118     tname[size] = '\0';
14119     npatt = unescpat(tname);
14120 #if defined(_WIN32) || defined(_WIN64)
14121     if (npatt) {
14122 	sql = sqlite4_mprintf(0, "select %s as 'TABLE_QUALIFIER', "
14123 			      "%s as 'TABLE_OWNER', "
14124 			      "tbl_name as 'TABLE_NAME', "
14125 			      "upper(type) as 'TABLE_TYPE', "
14126 			      "NULL as 'REMARKS' "
14127 			      "from sqlite_master where %s "
14128 			      "and tbl_name like %Q",
14129 			      d->xcelqrx ? "'main'" : "NULL",
14130 			      d->xcelqrx ? "''" : "NULL",
14131 			      where, tname);
14132     } else {
14133 	sql = sqlite4_mprintf(0, "select %s as 'TABLE_QUALIFIER', "
14134 			      "%s as 'TABLE_OWNER', "
14135 			      "tbl_name as 'TABLE_NAME', "
14136 			      "upper(type) as 'TABLE_TYPE', "
14137 			      "NULL as 'REMARKS' "
14138 			      "from sqlite_master where %s "
14139 			      "and lower(tbl_name) = lower(%Q)",
14140 			      d->xcelqrx ? "'main'" : "NULL",
14141 			      d->xcelqrx ? "''" : "NULL",
14142 			      where, tname);
14143     }
14144 #else
14145     if (npatt) {
14146 	sql = sqlite4_mprintf(0, "select NULL as 'TABLE_QUALIFIER', "
14147 			      "NULL as 'TABLE_OWNER', "
14148 			      "tbl_name as 'TABLE_NAME', "
14149 			      "upper(type) as 'TABLE_TYPE', "
14150 			      "NULL as 'REMARKS' "
14151 			      "from sqlite_master where %s "
14152 			      "and tbl_name like %Q", where, tname);
14153     } else {
14154 	sql = sqlite4_mprintf(0, "select NULL as 'TABLE_QUALIFIER', "
14155 			      "NULL as 'TABLE_OWNER', "
14156 			      "tbl_name as 'TABLE_NAME', "
14157 			      "upper(type) as 'TABLE_TYPE', "
14158 			      "NULL as 'REMARKS' "
14159 			      "from sqlite_master where %s "
14160 			      "and lower(tbl_name) = lower(%Q)", where, tname);
14161     }
14162 #endif
14163     if (!sql) {
14164 	return nomem(s);
14165     }
14166     ret = starttran(s);
14167     if (ret != SQL_SUCCESS) {
14168 	sqlite4_free(0, sql);
14169 	return ret;
14170     }
14171     dbtraceapi(d, "sqlite4_get_table", sql);
14172     rc = sqlite4_get_table(d->sqlite, sql, &s->rows, &s->nrows, &ncols, &errp);
14173     sqlite4_free(0, sql);
14174     if (rc == SQLITE4_OK) {
14175 	if (ncols != s->ncols) {
14176 	    freeresult(s, 0);
14177 	    s->nrows = 0;
14178 	} else {
14179 	    s->rowfree = freerows;
14180 	}
14181     } else {
14182 	s->nrows = 0;
14183 	s->rows = NULL;
14184 	s->rowfree = NULL;
14185     }
14186     if (errp) {
14187 	sqlite4_free(0, errp);
14188 	errp = NULL;
14189     }
14190     s->rowp = s->rowprs = -1;
14191     return SQL_SUCCESS;
14192 }
14193 
14194 #ifndef WINTERFACE
14195 /**
14196  * Retrieve information on tables and/or views.
14197  * @param stmt statement handle
14198  * @param cat catalog name/pattern or NULL
14199  * @param catLen length of catalog name/pattern or SQL_NTS
14200  * @param schema schema name/pattern or NULL
14201  * @param schemaLen length of schema name/pattern or SQL_NTS
14202  * @param table table name/pattern or NULL
14203  * @param tableLen length of table name/pattern or SQL_NTS
14204  * @param type types of tables string or NULL
14205  * @param typeLen length of types of tables string or SQL_NTS
14206  * @result ODBC error code
14207  */
14208 
14209 SQLRETURN SQL_API
SQLTables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)14210 SQLTables(SQLHSTMT stmt,
14211 	  SQLCHAR *cat, SQLSMALLINT catLen,
14212 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
14213 	  SQLCHAR *table, SQLSMALLINT tableLen,
14214 	  SQLCHAR *type, SQLSMALLINT typeLen)
14215 {
14216 #if defined(_WIN32) || defined(_WIN64)
14217     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
14218 #endif
14219     SQLRETURN ret;
14220 
14221     HSTMT_LOCK(stmt);
14222 #if defined(_WIN32) || defined(_WIN64)
14223     if (!((STMT *) stmt)->oemcp[0]) {
14224 	ret = drvtables(stmt, cat, catLen, schema, schemaLen,
14225 			table, tableLen, type, typeLen);
14226 	goto done2;
14227     }
14228     if (cat) {
14229 	c = wmb_to_utf_c((char *) cat, catLen);
14230 	if (!c) {
14231 	    ret = nomem((STMT *) stmt);
14232 	    goto done;
14233 	}
14234     }
14235     if (schema) {
14236 	s = wmb_to_utf_c((char *) schema, schemaLen);
14237 	if (!s) {
14238 	    ret = nomem((STMT *) stmt);
14239 	    goto done;
14240 	}
14241     }
14242     if (table) {
14243 	t = wmb_to_utf_c((char *) table, tableLen);
14244 	if (!t) {
14245 	    ret = nomem((STMT *) stmt);
14246 	    goto done;
14247 	}
14248     }
14249     if (type) {
14250 	y = wmb_to_utf_c((char *) type, typeLen);
14251 	if (!y) {
14252 	    ret = nomem((STMT *) stmt);
14253 	    goto done;
14254 	}
14255     }
14256     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14257 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
14258 #else
14259     ret = drvtables(stmt, cat, catLen, schema, schemaLen,
14260 		    table, tableLen, type, typeLen);
14261 #endif
14262 #if defined(_WIN32) || defined(_WIN64)
14263 done:
14264     uc_free(y);
14265     uc_free(t);
14266     uc_free(s);
14267     uc_free(c);
14268 done2:
14269     ;
14270 #endif
14271     HSTMT_UNLOCK(stmt);
14272     return ret;
14273 }
14274 #endif
14275 
14276 #ifdef WINTERFACE
14277 /**
14278  * Retrieve information on tables and/or views.
14279  * @param stmt statement handle
14280  * @param cat catalog name/pattern or NULL
14281  * @param catLen length of catalog name/pattern or SQL_NTS
14282  * @param schema schema name/pattern or NULL
14283  * @param schemaLen length of schema name/pattern or SQL_NTS
14284  * @param table table name/pattern or NULL
14285  * @param tableLen length of table name/pattern or SQL_NTS
14286  * @param type types of tables string or NULL
14287  * @param typeLen length of types of tables string or SQL_NTS
14288  * @result ODBC error code
14289  */
14290 
14291 SQLRETURN SQL_API
SQLTablesW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * type,SQLSMALLINT typeLen)14292 SQLTablesW(SQLHSTMT stmt,
14293 	   SQLWCHAR *cat, SQLSMALLINT catLen,
14294 	   SQLWCHAR *schema, SQLSMALLINT schemaLen,
14295 	   SQLWCHAR *table, SQLSMALLINT tableLen,
14296 	   SQLWCHAR *type, SQLSMALLINT typeLen)
14297 {
14298     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
14299     SQLRETURN ret;
14300 
14301     HSTMT_LOCK(stmt);
14302     if (cat) {
14303 	c = uc_to_utf_c(cat, catLen);
14304 	if (!c) {
14305 	    ret = nomem((STMT *) stmt);
14306 	    goto done;
14307 	}
14308     }
14309     if (schema) {
14310 	s = uc_to_utf_c(schema, schemaLen);
14311 	if (!s) {
14312 	    ret = nomem((STMT *) stmt);
14313 	    goto done;
14314 	}
14315     }
14316     if (table) {
14317 	t = uc_to_utf_c(table, tableLen);
14318 	if (!t) {
14319 	    ret = nomem((STMT *) stmt);
14320 	    goto done;
14321 	}
14322     }
14323     if (type) {
14324 	y = uc_to_utf_c(type, typeLen);
14325 	if (!y) {
14326 	    ret = nomem((STMT *) stmt);
14327 	    goto done;
14328 	}
14329     }
14330     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14331 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
14332 done:
14333     uc_free(y);
14334     uc_free(t);
14335     uc_free(s);
14336     uc_free(c);
14337     HSTMT_UNLOCK(stmt);
14338     return ret;
14339 }
14340 #endif
14341 
14342 /**
14343  * Columns for result set of SQLColumns().
14344  */
14345 
14346 static COL colSpec2[] = {
14347     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
14348     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
14349     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
14350     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
14351     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
14352     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
14353     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
14354     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
14355     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
14356     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
14357     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
14358     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
14359     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
14360     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
14361     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
14362     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
14363     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
14364     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
14365 };
14366 
14367 static COL colSpec3[] = {
14368     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
14369     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
14370     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
14371     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
14372     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
14373     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
14374     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
14375     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
14376     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_SMALLINT, 50 },
14377     { "SYSTEM", "COLUMN", "NUM_PREC_RADIX", SQL_SMALLINT, 50 },
14378     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
14379     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
14380     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
14381     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
14382     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
14383     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
14384     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
14385     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
14386 };
14387 
14388 /**
14389  * Internal retrieve column information on table.
14390  * @param stmt statement handle
14391  * @param cat catalog name/pattern or NULL
14392  * @param catLen length of catalog name/pattern or SQL_NTS
14393  * @param schema schema name/pattern or NULL
14394  * @param schemaLen length of schema name/pattern or SQL_NTS
14395  * @param table table name/pattern or NULL
14396  * @param tableLen length of table name/pattern or SQL_NTS
14397  * @param col column name/pattern or NULL
14398  * @param colLen length of column name/pattern or SQL_NTS
14399  * @result ODBC error code
14400  */
14401 
14402 static SQLRETURN
drvcolumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)14403 drvcolumns(SQLHSTMT stmt,
14404 	   SQLCHAR *cat, SQLSMALLINT catLen,
14405 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
14406 	   SQLCHAR *table, SQLSMALLINT tableLen,
14407 	   SQLCHAR *col, SQLSMALLINT colLen)
14408 {
14409     SQLRETURN sret;
14410     STMT *s;
14411     DBC *d;
14412     int ret, nrows, ncols, asize, i, k, roffs, namec;
14413     int tnrows, tncols, npatt;
14414     PTRDIFF_T size;
14415     char *errp = NULL, *sql, tname[512], cname[512], **rowp, **trows;
14416 
14417     sret = mkresultset(stmt, colSpec2, array_size(colSpec2),
14418 		       colSpec3, array_size(colSpec3), &asize);
14419     if (sret != SQL_SUCCESS) {
14420 	return sret;
14421     }
14422     s = (STMT *) stmt;
14423     d = (DBC *) s->dbc;
14424     if (!table) {
14425 	size = 1;
14426 	tname[0] = '%';
14427     } else {
14428 	if (tableLen == SQL_NTS) {
14429 	    size = sizeof (tname) - 1;
14430 	} else {
14431 	    size = min(sizeof (tname) - 1, tableLen);
14432 	}
14433 	strncpy(tname, (char *) table, size);
14434     }
14435     tname[size] = '\0';
14436     npatt = unescpat(tname);
14437     size = 0;
14438     if (col) {
14439 	if (colLen == SQL_NTS) {
14440 	    size = sizeof (cname) - 1;
14441 	} else {
14442 	    size = min(sizeof (cname) - 1, colLen);
14443 	}
14444 	strncpy(cname, (char *) col, size);
14445     }
14446     cname[size] = '\0';
14447     if (!strcmp(cname, "%")) {
14448 	cname[0] = '\0';
14449     }
14450     if (npatt) {
14451 	sql = sqlite4_mprintf(0, "select tbl_name from sqlite_master where "
14452 			      "(type = 'table' or type = 'view') "
14453 			      "and tbl_name like %Q", tname);
14454     } else {
14455 	sql = sqlite4_mprintf(0, "select tbl_name from sqlite_master where "
14456 			      "(type = 'table' or type = 'view') "
14457 			      "and lower(tbl_name) = lower(%Q)", tname);
14458     }
14459     if (!sql) {
14460 	return nomem(s);
14461     }
14462     sret = starttran(s);
14463     if (sret != SQL_SUCCESS) {
14464 	sqlite4_free(0, sql);
14465 	return sret;
14466     }
14467     dbtraceapi(d, "sqlite4_get_table", sql);
14468     ret = sqlite4_get_table(d->sqlite, sql, &trows, &tnrows, &tncols, &errp);
14469     sqlite4_free(0, sql);
14470     if (ret != SQLITE4_OK) {
14471 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
14472 		errp ? errp : "unknown error", ret);
14473 	if (errp) {
14474 	    sqlite4_free(0, errp);
14475 	    errp = NULL;
14476 	}
14477 	return SQL_ERROR;
14478     }
14479     if (errp) {
14480 	sqlite4_free(0, errp);
14481 	errp = NULL;
14482     }
14483     /* pass 1: compute number of rows of result set */
14484     if (tncols * tnrows <= 0) {
14485 	freerows(trows);
14486 	return SQL_SUCCESS;
14487     }
14488     size = 0;
14489     for (i = 1; i <= tnrows; i++) {
14490 	sql = sqlite4_mprintf(0, "PRAGMA table_info(%Q)", trows[i]);
14491 	if (!sql) {
14492 	    freerows(trows);
14493 	    return nomem(s);
14494 	}
14495 	dbtraceapi(d, "sqlite4_get_table", sql);
14496 	ret = sqlite4_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
14497 	sqlite4_free(0, sql);
14498 	if (ret != SQLITE4_OK) {
14499 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
14500 		    errp ? errp : "unknown error", ret);
14501 	    if (errp) {
14502 		sqlite4_free(0, errp);
14503 		errp = NULL;
14504 	    }
14505 	    freerows(trows);
14506 	    return SQL_ERROR;
14507 	}
14508 	if (errp) {
14509 	    sqlite4_free(0, errp);
14510 	    errp = NULL;
14511 	}
14512 	if (ncols * nrows > 0) {
14513 	    namec = -1;
14514 	    for (k = 0; k < ncols; k++) {
14515 		if (strcmp(rowp[k], "name") == 0) {
14516 		    namec = k;
14517 		    break;
14518 		}
14519 	    }
14520 	    if (cname[0]) {
14521 		if (namec >= 0) {
14522 		    for (k = 1; k <= nrows; k++) {
14523 			if (namematch(rowp[k * ncols + namec], cname, 1)) {
14524 			    size++;
14525 			}
14526 		    }
14527 		}
14528 	    } else {
14529 		size += nrows;
14530 	    }
14531 	}
14532 	freerows(rowp);
14533     }
14534     /* pass 2: fill result set */
14535     if (size <= 0) {
14536 	freerows(trows);
14537 	return SQL_SUCCESS;
14538     }
14539     s->nrows = size;
14540     size = (size + 1) * asize;
14541     s->rows = xmalloc((size + 1) * sizeof (char *));
14542     if (!s->rows) {
14543 	s->nrows = 0;
14544 	freerows(trows);
14545 	return nomem(s);
14546     }
14547     s->rows[0] = (char *) size;
14548     s->rows += 1;
14549     memset(s->rows, 0, sizeof (char *) * size);
14550     s->rowfree = freerows;
14551     roffs = 1;
14552     for (i = 1; i <= tnrows; i++) {
14553 	sql = sqlite4_mprintf(0, "PRAGMA table_info(%Q)", trows[i]);
14554 	if (!sql) {
14555 	    freerows(trows);
14556 	    return nomem(s);
14557 	}
14558 	dbtraceapi(d, "sqlite4_get_table", sql);
14559 	ret = sqlite4_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
14560 	sqlite4_free(0, sql);
14561 	if (ret != SQLITE4_OK) {
14562 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
14563 		    errp ? errp : "unknown error", ret);
14564 	    if (errp) {
14565 		sqlite4_free(0, errp);
14566 		errp = NULL;
14567 	    }
14568 	    freerows(trows);
14569 	    return SQL_ERROR;
14570 	}
14571 	if (errp) {
14572 	    sqlite4_free(0, errp);
14573 	    errp = NULL;
14574 	}
14575 	if (ncols * nrows > 0) {
14576 	    int m, mr, nr = nrows;
14577 
14578 	    namec = -1;
14579 	    for (k = 0; k < ncols; k++) {
14580 		if (strcmp(rowp[k], "name") == 0) {
14581 		    namec = k;
14582 		    break;
14583 		}
14584 	    }
14585 	    if (cname[0]) {
14586 		nr = 0;
14587 		if (namec >= 0) {
14588 		    for (k = 1; k <= nrows; k++) {
14589 			if (namematch(rowp[k * ncols + namec], cname, 1)) {
14590 			    nr++;
14591 			}
14592 		    }
14593 		}
14594 	    }
14595 	    for (k = 0; k < nr; k++) {
14596 		m = asize * (roffs + k);
14597 #if defined(_WIN32) || defined(_WIN64)
14598 		s->rows[m + 0] = xstrdup(d->xcelqrx ? "main" : "");
14599 		s->rows[m + 1] = xstrdup("");
14600 #else
14601 		s->rows[m + 0] = xstrdup("");
14602 		s->rows[m + 1] = xstrdup("");
14603 #endif
14604 		s->rows[m + 2] = xstrdup(trows[i]);
14605 		s->rows[m + 8] = xstrdup("10");
14606 		s->rows[m + 9] = xstrdup("0");
14607 		s->rows[m + 15] = xstrdup("16384");
14608 	    }
14609 	    for (k = 0; nr && k < ncols; k++) {
14610 		if (strcmp(rowp[k], "cid") == 0) {
14611 		    for (mr = 0, m = 1; m <= nrows; m++) {
14612 			char buf[256];
14613 			int ir, coln = k;
14614 
14615 			if (cname[0] &&
14616 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
14617 			    continue;
14618 			}
14619 			ir = asize * (roffs + mr);
14620 			sscanf(rowp[m * ncols + k], "%d", &coln);
14621 			sprintf(buf, "%d", coln + 1);
14622 			s->rows[ir + 16] = xstrdup(buf);
14623 			++mr;
14624 		    }
14625 		} else if (k == namec) {
14626 		    for (mr = 0, m = 1; m <= nrows; m++) {
14627 			int ir;
14628 
14629 			if (cname[0] &&
14630 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
14631 			    continue;
14632 			}
14633 			ir = asize * (roffs + mr);
14634 			s->rows[ir + 3] = xstrdup(rowp[m * ncols + k]);
14635 			++mr;
14636 		    }
14637 		} else if (strcmp(rowp[k], "notnull") == 0) {
14638 		    for (mr = 0, m = 1; m <= nrows; m++) {
14639 			int ir;
14640 
14641 			if (cname[0] &&
14642 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
14643 			    continue;
14644 			}
14645 			ir = asize * (roffs + mr);
14646 			if (*rowp[m * ncols + k] != '0') {
14647 			    s->rows[ir + 10] = xstrdup(stringify(SQL_FALSE));
14648 			} else {
14649 			    s->rows[ir + 10] = xstrdup(stringify(SQL_TRUE));
14650 			}
14651 			s->rows[ir + 17] =
14652 			    xstrdup((*rowp[m * ncols + k] != '0') ?
14653 				    "NO" : "YES");
14654 			++mr;
14655 		    }
14656 		} else if (strcmp(rowp[k], "dflt_value") == 0) {
14657 		    for (mr = 0, m = 1; m <= nrows; m++) {
14658 			char *dflt = unquote(rowp[m * ncols + k]);
14659 			int ir;
14660 
14661 			if (cname[0] &&
14662 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
14663 			    continue;
14664 			}
14665 			ir = asize * (roffs + mr);
14666 			s->rows[ir + 12] = xstrdup(dflt ? dflt : "NULL");
14667 			++mr;
14668 		    }
14669 		} else if (strcmp(rowp[k], "type") == 0) {
14670 		    for (mr = 0, m = 1; m <= nrows; m++) {
14671 			char *typename = rowp[m * ncols + k];
14672 			int sqltype, mm, dd, ir;
14673 			char buf[256];
14674 
14675 			if (cname[0] &&
14676 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
14677 			    continue;
14678 			}
14679 			ir = asize * (roffs + mr);
14680 			s->rows[ir + 5] = xstrdup(typename);
14681 			sqltype = mapsqltype(typename, NULL, *s->ov3,
14682 					     s->nowchar[0], s->dobigint);
14683 			getmd(typename, sqltype, &mm, &dd);
14684 #ifdef SQL_LONGVARCHAR
14685 			if (sqltype == SQL_VARCHAR && mm > 255) {
14686 			    sqltype = SQL_LONGVARCHAR;
14687 			}
14688 #endif
14689 #ifdef WINTERFACE
14690 #ifdef SQL_WLONGVARCHAR
14691 			if (sqltype == SQL_WVARCHAR && mm > 255) {
14692 			    sqltype = SQL_WLONGVARCHAR;
14693 			}
14694 #endif
14695 #endif
14696 			if (sqltype == SQL_VARBINARY && mm > 255) {
14697 			    sqltype = SQL_LONGVARBINARY;
14698 			}
14699 			sprintf(buf, "%d", sqltype);
14700 			s->rows[ir + 4] = xstrdup(buf);
14701 			s->rows[ir + 13] = xstrdup(buf);
14702 			sprintf(buf, "%d", mm);
14703 			s->rows[ir + 7] = xstrdup(buf);
14704 			sprintf(buf, "%d", dd);
14705 			s->rows[ir + 6] = xstrdup(buf);
14706 			++mr;
14707 		    }
14708 		}
14709 	    }
14710 	    roffs += nr;
14711 	}
14712 	freerows(rowp);
14713     }
14714     freerows(trows);
14715     return SQL_SUCCESS;
14716 }
14717 
14718 #ifndef WINTERFACE
14719 /**
14720  * Retrieve column information on table.
14721  * @param stmt statement handle
14722  * @param cat catalog name/pattern or NULL
14723  * @param catLen length of catalog name/pattern or SQL_NTS
14724  * @param schema schema name/pattern or NULL
14725  * @param schemaLen length of schema name/pattern or SQL_NTS
14726  * @param table table name/pattern or NULL
14727  * @param tableLen length of table name/pattern or SQL_NTS
14728  * @param col column name/pattern or NULL
14729  * @param colLen length of column name/pattern or SQL_NTS
14730  * @result ODBC error code
14731  */
14732 
14733 SQLRETURN SQL_API
SQLColumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)14734 SQLColumns(SQLHSTMT stmt,
14735 	   SQLCHAR *cat, SQLSMALLINT catLen,
14736 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
14737 	   SQLCHAR *table, SQLSMALLINT tableLen,
14738 	   SQLCHAR *col, SQLSMALLINT colLen)
14739 {
14740 #if defined(_WIN32) || defined(_WIN64)
14741     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
14742 #endif
14743     SQLRETURN ret;
14744 
14745     HSTMT_LOCK(stmt);
14746 #if defined(_WIN32) || defined(_WIN64)
14747     if (!((STMT *) stmt)->oemcp[0]) {
14748 	ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
14749 			 table, tableLen, col, colLen);
14750 	goto done2;
14751     }
14752     if (cat) {
14753 	c = wmb_to_utf_c((char *) cat, catLen);
14754 	if (!c) {
14755 	    ret = nomem((STMT *) stmt);
14756 	    goto done;
14757 	}
14758     }
14759     if (schema) {
14760 	s = wmb_to_utf_c((char *) schema, schemaLen);
14761 	if (!s) {
14762 	    ret = nomem((STMT *) stmt);
14763 	    goto done;
14764 	}
14765     }
14766     if (table) {
14767 	t = wmb_to_utf_c((char *) table, tableLen);
14768 	if (!t) {
14769 	    ret = nomem((STMT *) stmt);
14770 	    goto done;
14771 	}
14772     }
14773     if (col) {
14774 	k = wmb_to_utf_c((char *) col, colLen);
14775 	if (!k) {
14776 	    ret = nomem((STMT *) stmt);
14777 	    goto done;
14778 	}
14779     }
14780     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14781 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
14782 #else
14783     ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
14784 		     table, tableLen, col, colLen);
14785 #endif
14786 #if defined(_WIN32) || defined(_WIN64)
14787 done:
14788     uc_free(k);
14789     uc_free(t);
14790     uc_free(s);
14791     uc_free(c);
14792 done2:
14793     ;
14794 #endif
14795     HSTMT_UNLOCK(stmt);
14796     return ret;
14797 }
14798 #endif
14799 
14800 #ifdef WINTERFACE
14801 /**
14802  * Retrieve column information on table (UNICODE version).
14803  * @param stmt statement handle
14804  * @param cat catalog name/pattern or NULL
14805  * @param catLen length of catalog name/pattern or SQL_NTS
14806  * @param schema schema name/pattern or NULL
14807  * @param schemaLen length of schema name/pattern or SQL_NTS
14808  * @param table table name/pattern or NULL
14809  * @param tableLen length of table name/pattern or SQL_NTS
14810  * @param col column name/pattern or NULL
14811  * @param colLen length of column name/pattern or SQL_NTS
14812  * @result ODBC error code
14813  */
14814 
14815 SQLRETURN SQL_API
SQLColumnsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * col,SQLSMALLINT colLen)14816 SQLColumnsW(SQLHSTMT stmt,
14817 	    SQLWCHAR *cat, SQLSMALLINT catLen,
14818 	    SQLWCHAR *schema, SQLSMALLINT schemaLen,
14819 	    SQLWCHAR *table, SQLSMALLINT tableLen,
14820 	    SQLWCHAR *col, SQLSMALLINT colLen)
14821 {
14822     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
14823     SQLRETURN ret;
14824 
14825     HSTMT_LOCK(stmt);
14826     if (cat) {
14827 	c = uc_to_utf_c(cat, catLen);
14828 	if (!c) {
14829 	    ret = nomem((STMT *) stmt);
14830 	    goto done;
14831 	}
14832     }
14833     if (schema) {
14834 	s = uc_to_utf_c(schema, schemaLen);
14835 	if (!s) {
14836 	    ret = nomem((STMT *) stmt);
14837 	    goto done;
14838 	}
14839     }
14840     if (table) {
14841 	t = uc_to_utf_c(table, tableLen);
14842 	if (!t) {
14843 	    ret = nomem((STMT *) stmt);
14844 	    goto done;
14845 	}
14846     }
14847     if (col) {
14848 	k = uc_to_utf_c(col, colLen);
14849 	if (!k) {
14850 	    ret = nomem((STMT *) stmt);
14851 	    goto done;
14852 	}
14853     }
14854     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
14855 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
14856 done:
14857     uc_free(k);
14858     uc_free(t);
14859     uc_free(s);
14860     uc_free(c);
14861     HSTMT_UNLOCK(stmt);
14862     return ret;
14863 
14864 }
14865 #endif
14866 
14867 /**
14868  * Columns for result set of SQLGetTypeInfo().
14869  */
14870 
14871 static COL typeSpec2[] = {
14872     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
14873     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
14874     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 9 },
14875     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
14876     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
14877     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
14878     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
14879     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
14880     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
14881     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
14882     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
14883     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
14884     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
14885     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
14886     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
14887 };
14888 
14889 static COL typeSpec3[] = {
14890     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
14891     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
14892     { "SYSTEM", "TYPE", "COLUMN_SIZE", SQL_INTEGER, 9 },
14893     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
14894     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
14895     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
14896     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
14897     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
14898     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
14899     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
14900     { "SYSTEM", "TYPE", "FIXED_PREC_SCALE", SQL_SMALLINT, 2 },
14901     { "SYSTEM", "TYPE", "AUTO_UNIQUE_VALUE", SQL_SMALLINT, 2 },
14902     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
14903     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
14904     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 },
14905     { "SYSTEM", "TYPE", "SQL_DATA_TYPE", SQL_SMALLINT, 2 },
14906     { "SYSTEM", "TYPE", "SQL_DATETIME_SUB", SQL_SMALLINT, 2 },
14907     { "SYSTEM", "TYPE", "NUM_PREC_RADIX", SQL_INTEGER, 4 },
14908     { "SYSTEM", "TYPE", "INTERVAL_PRECISION", SQL_SMALLINT, 2 }
14909 };
14910 
14911 /**
14912  * Internal function to build up data type information as row in result set.
14913  * @param s statement pointer
14914  * @param row row number
14915  * @param asize number of items in a row
14916  * @param typename name of type
14917  * @param type integer SQL type
14918  * @param tind type index
14919  */
14920 
14921 static void
mktypeinfo(STMT * s,int row,int asize,char * typename,int type,int tind)14922 mktypeinfo(STMT *s, int row, int asize, char *typename, int type, int tind)
14923 {
14924     int offs = row * asize;
14925     char *tcode, *crpar = NULL, *sign = stringify(SQL_FALSE);
14926     char *quote[2] = { NULL, NULL };
14927     static char tcodes[32 * 32];
14928 
14929     if (tind <= 0) {
14930 	tind = row;
14931     }
14932     tcode = tcodes + tind * 32;
14933     sprintf(tcode, "%d", type);
14934     s->rows[offs + 0] = typename;
14935     s->rows[offs + 1] = tcode;
14936     if (asize >= 17) {
14937 	s->rows[offs + 15] = tcode;
14938 	s->rows[offs + 16] = "0";
14939     }
14940     switch (type) {
14941     default:
14942 #ifdef SQL_LONGVARCHAR
14943     case SQL_LONGVARCHAR:
14944 #ifdef WINTERFACE
14945     case SQL_WLONGVARCHAR:
14946 #endif
14947 	crpar = "length";
14948 	quote[0] = quote[1] = "'";
14949 	sign = NULL;
14950 	s->rows[offs + 2] = "65536";
14951 	break;
14952 #endif
14953 #ifdef SQL_BIT
14954     case SQL_BIT:
14955 	sign = NULL;
14956 	s->rows[offs + 2] = "1";
14957 	break;
14958 #endif
14959     case SQL_CHAR:
14960     case SQL_VARCHAR:
14961 #ifdef WINTERFACE
14962     case SQL_WCHAR:
14963     case SQL_WVARCHAR:
14964 #endif
14965 	s->rows[offs + 2] = "255";
14966 	crpar = "length";
14967 	quote[0] = quote[1] = "'";
14968 	sign = NULL;
14969 	break;
14970     case SQL_TINYINT:
14971 	s->rows[offs + 2] = "3";
14972 	break;
14973     case SQL_SMALLINT:
14974 	s->rows[offs + 2] = "5";
14975 	break;
14976     case SQL_INTEGER:
14977 	s->rows[offs + 2] = "9";
14978 	break;
14979 #ifdef SQL_BIGINT
14980     case SQL_BIGINT:
14981 	s->rows[offs + 2] = "19";
14982 	break;
14983 #endif
14984     case SQL_FLOAT:
14985 	s->rows[offs + 2] = "7";
14986 	break;
14987     case SQL_DOUBLE:
14988 	s->rows[offs + 2] = "15";
14989 	break;
14990 #ifdef SQL_TYPE_DATE
14991     case SQL_TYPE_DATE:
14992 #endif
14993     case SQL_DATE:
14994 	s->rows[offs + 2] = "10";
14995 	quote[0] = quote[1] = "'";
14996 	sign = NULL;
14997 	break;
14998 #ifdef SQL_TYPE_TIME
14999     case SQL_TYPE_TIME:
15000 #endif
15001     case SQL_TIME:
15002 	s->rows[offs + 2] = "8";
15003 	quote[0] = quote[1] = "'";
15004 	sign = NULL;
15005 	break;
15006 #ifdef SQL_TYPE_TIMESTAMP
15007     case SQL_TYPE_TIMESTAMP:
15008 #endif
15009     case SQL_TIMESTAMP:
15010 	s->rows[offs + 2] = "32";
15011 	quote[0] = quote[1] = "'";
15012 	sign = NULL;
15013 	break;
15014     case SQL_VARBINARY:
15015 	quote[0] = "0x";
15016 	sign = NULL;
15017 	s->rows[offs + 2] = "255";
15018 	break;
15019     case SQL_LONGVARBINARY:
15020 	quote[0] = "0x";
15021 	sign = NULL;
15022 	s->rows[offs + 2] = "65536";
15023 	break;
15024     }
15025     s->rows[offs + 3] = quote[0];
15026     s->rows[offs + 4] = quote[1];
15027     s->rows[offs + 5] = crpar;
15028     s->rows[offs + 6] = stringify(SQL_NULLABLE);
15029     s->rows[offs + 7] = stringify(SQL_FALSE);
15030     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
15031     s->rows[offs + 9] = sign;
15032     s->rows[offs + 10] = stringify(SQL_FALSE);
15033     s->rows[offs + 11] = stringify(SQL_FALSE);
15034     s->rows[offs + 12] = typename;
15035     switch (type) {
15036     case SQL_DATE:
15037     case SQL_TIME:
15038 	s->rows[offs + 13] = "0";
15039 	s->rows[offs + 14] = "0";
15040 	break;
15041 #ifdef SQL_TYPE_TIMESTAMP
15042     case SQL_TYPE_TIMESTAMP:
15043 #endif
15044     case SQL_TIMESTAMP:
15045 	s->rows[offs + 13] = "0";
15046 	s->rows[offs + 14] = "3";
15047 	break;
15048     default:
15049 	s->rows[offs + 13] = NULL;
15050 	s->rows[offs + 14] = NULL;
15051 	break;
15052     }
15053 }
15054 
15055 /**
15056  * Helper function to sort type information.
15057  * Callback for qsort().
15058  * @param a first item to compare
15059  * @param b second item to compare
15060  * @result ==0, <0, >0 according to data type number
15061  */
15062 
15063 static int
typeinfosort(const void * a,const void * b)15064 typeinfosort(const void *a, const void *b)
15065 {
15066     char **pa = (char **) a;
15067     char **pb = (char **) b;
15068     int na, nb;
15069 
15070     na = strtol(pa[1], NULL, 0);
15071     nb = strtol(pb[1], NULL, 0);
15072     return na - nb;
15073 }
15074 
15075 /**
15076  * Internal return data type information.
15077  * @param stmt statement handle
15078  * @param sqltype which type to retrieve
15079  * @result ODBC error code
15080  */
15081 
15082 static SQLRETURN
drvgettypeinfo(SQLHSTMT stmt,SQLSMALLINT sqltype)15083 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
15084 {
15085     SQLRETURN ret;
15086     STMT *s;
15087     int asize;
15088 
15089     ret = mkresultset(stmt, typeSpec2, array_size(typeSpec2),
15090 		      typeSpec3, array_size(typeSpec3), &asize);
15091     if (ret != SQL_SUCCESS) {
15092 	return ret;
15093     }
15094     s = (STMT *) stmt;
15095 #ifdef SQL_LONGVARCHAR
15096     s->nrows = (sqltype == SQL_ALL_TYPES) ? 13 : 1;
15097 #else
15098     s->nrows = (sqltype == SQL_ALL_TYPES) ? 12 : 1;
15099 #endif
15100     if (sqltype == SQL_ALL_TYPES) {
15101 #ifdef WINTERFACE
15102 	s->nrows += 2;
15103 #ifdef SQL_WLONGVARCHAR
15104 	s->nrows += 2;
15105 #endif
15106 #endif
15107     }
15108     if (sqltype == SQL_ALL_TYPES) {
15109 	s->nrows += 2;
15110 #ifdef SQL_BIT
15111 	s->nrows += 1;
15112 #endif
15113 #ifdef SQL_BIGINT
15114 	s->nrows += 1;
15115 #endif
15116     }
15117     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1) * asize);
15118     if (!s->rows) {
15119 	s->nrows = 0;
15120 	return nomem(s);
15121     }
15122 #ifdef MEMORY_DEBUG
15123     s->rowfree = xfree__;
15124 #else
15125     s->rowfree = sqlite4_free;
15126 #endif
15127     memset(s->rows, 0, sizeof (char *) * (s->nrows + 1) * asize);
15128     if (sqltype == SQL_ALL_TYPES) {
15129 	int cc = 1;
15130 
15131 	mktypeinfo(s, cc++, asize, "varchar", SQL_VARCHAR, 0);
15132 	mktypeinfo(s, cc++, asize, "tinyint", SQL_TINYINT, 0);
15133 	mktypeinfo(s, cc++, asize, "smallint", SQL_SMALLINT, 0);
15134 	mktypeinfo(s, cc++, asize, "integer", SQL_INTEGER, 0);
15135 	mktypeinfo(s, cc++, asize, "float", SQL_FLOAT, 0);
15136 	mktypeinfo(s, cc++, asize, "double", SQL_DOUBLE, 0);
15137 #ifdef SQL_TYPE_DATE
15138 	mktypeinfo(s, cc++, asize, "date",
15139 		   (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
15140 #else
15141 	mktypeinfo(s, cc++, asize, "date", SQL_DATE, 0);
15142 #endif
15143 #ifdef SQL_TYPE_TIME
15144 	mktypeinfo(s, cc++, asize, "time",
15145 		   (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
15146 #else
15147 	mktypeinfo(s, cc++, asize, "time", SQL_TIME, 0);
15148 #endif
15149 #ifdef SQL_TYPE_TIMESTAMP
15150 	mktypeinfo(s, cc++, asize, "timestamp",
15151 		   (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
15152 #else
15153 	mktypeinfo(s, cc++, asize, "timestamp", SQL_TIMESTAMP, 0);
15154 #endif
15155 	mktypeinfo(s, cc++, asize, "char", SQL_CHAR, 0);
15156 	mktypeinfo(s, cc++, asize, "numeric", SQL_DOUBLE, 0);
15157 #ifdef SQL_LONGVARCHAR
15158 	mktypeinfo(s, cc++, asize, "text", SQL_LONGVARCHAR, 0);
15159 	mktypeinfo(s, cc++, asize, "longvarchar", SQL_LONGVARCHAR, 0);
15160 #else
15161 	mktypeinfo(s, cc++, asize, "text", SQL_VARCHAR, 0);
15162 #endif
15163 	mktypeinfo(s, cc++, asize, "varbinary", SQL_VARBINARY, 0);
15164 	mktypeinfo(s, cc++, asize, "longvarbinary", SQL_LONGVARBINARY, 0);
15165 #ifdef SQL_BIT
15166 	mktypeinfo(s, cc++, asize, "bit", SQL_BIT, 0);
15167 #endif
15168 #ifdef SQL_BIGINT
15169 	mktypeinfo(s, cc++, asize, "bigint", SQL_BIGINT, 0);
15170 #endif
15171 #ifdef WINTERFACE
15172 	mktypeinfo(s, cc++, asize, "wvarchar", SQL_WVARCHAR, 0);
15173 	mktypeinfo(s, cc++, asize, "wchar", SQL_WCHAR, 0);
15174 #ifdef SQL_WLONGVARCHAR
15175 	mktypeinfo(s, cc++, asize, "wtext", SQL_WLONGVARCHAR, 0);
15176 	mktypeinfo(s, cc++, asize, "longwvarchar", SQL_WLONGVARCHAR, 0);
15177 #endif
15178 #endif
15179 	qsort(s->rows + asize, s->nrows, sizeof (char *) * asize,
15180 	      typeinfosort);
15181     } else {
15182 	switch (sqltype) {
15183 	case SQL_CHAR:
15184 	    mktypeinfo(s, 1, asize, "char", SQL_CHAR, 10);
15185 	    break;
15186 	case SQL_VARCHAR:
15187 	    mktypeinfo(s, 1, asize, "varchar", SQL_VARCHAR, 1);
15188 	    break;
15189 	case SQL_TINYINT:
15190 	    mktypeinfo(s, 1, asize, "tinyint", SQL_TINYINT, 2);
15191 	    break;
15192 	case SQL_SMALLINT:
15193 	    mktypeinfo(s, 1, asize, "smallint", SQL_SMALLINT, 3);
15194 	    break;
15195 	case SQL_INTEGER:
15196 	    mktypeinfo(s, 1, asize, "integer", SQL_INTEGER, 4);
15197 	    break;
15198 	case SQL_FLOAT:
15199 	    mktypeinfo(s, 1, asize, "float", SQL_FLOAT, 5);
15200 	    break;
15201 	case SQL_DOUBLE:
15202 	    mktypeinfo(s, 1, asize, "double", SQL_DOUBLE, 6);
15203 	    break;
15204 #ifdef SQL_TYPE_DATE
15205 	case SQL_TYPE_DATE:
15206 	    mktypeinfo(s, 1, asize, "date", SQL_TYPE_DATE, 25);
15207 	    break;
15208 #endif
15209 	case SQL_DATE:
15210 	    mktypeinfo(s, 1, asize, "date", SQL_DATE, 7);
15211 	    break;
15212 #ifdef SQL_TYPE_TIME
15213 	case SQL_TYPE_TIME:
15214 	    mktypeinfo(s, 1, asize, "time", SQL_TYPE_TIME, 26);
15215 	    break;
15216 #endif
15217 	case SQL_TIME:
15218 	    mktypeinfo(s, 1, asize, "time", SQL_TIME, 8);
15219 	    break;
15220 #ifdef SQL_TYPE_TIMESTAMP
15221 	case SQL_TYPE_TIMESTAMP:
15222 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TYPE_TIMESTAMP, 27);
15223 	    break;
15224 #endif
15225 	case SQL_TIMESTAMP:
15226 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TIMESTAMP, 9);
15227 	    break;
15228 #ifdef SQL_LONGVARCHAR
15229 	case SQL_LONGVARCHAR:
15230 	    mktypeinfo(s, 1, asize, "longvarchar", SQL_LONGVARCHAR, 12);
15231 	    break;
15232 #endif
15233 	case SQL_VARBINARY:
15234 	    mktypeinfo(s, 1, asize, "varbinary", SQL_VARBINARY, 30);
15235 	    break;
15236 	case SQL_LONGVARBINARY:
15237 	    mktypeinfo(s, 1, asize, "longvarbinary", SQL_LONGVARBINARY, 31);
15238 	    break;
15239 #ifdef SQL_BIT
15240 	case SQL_BIT:
15241 	    mktypeinfo(s, 1, asize, "bit", SQL_BIT, 29);
15242 	    break;
15243 #endif
15244 #ifdef SQL_BIGINT
15245 	case SQL_BIGINT:
15246 	    mktypeinfo(s, 1, asize, "bigint", SQL_BIGINT, 28);
15247 	    break;
15248 #endif
15249 #ifdef WINTERFACE
15250 #ifdef SQL_WCHAR
15251 	case SQL_WCHAR:
15252 	    mktypeinfo(s, 1, asize, "wchar", SQL_WCHAR, 18);
15253 	    break;
15254 #endif
15255 #ifdef SQL_WVARCHAR
15256 	case SQL_WVARCHAR:
15257 	    mktypeinfo(s, 1, asize, "wvarchar", SQL_WVARCHAR, 19);
15258 	    break;
15259 #endif
15260 #ifdef SQL_WLONGVARCHAR
15261 	case SQL_WLONGVARCHAR:
15262 	    mktypeinfo(s, 1, asize, "longwvarchar", SQL_WLONGVARCHAR, 20);
15263 	    break;
15264 #endif
15265 #endif
15266 	default:
15267 	    s->nrows = 0;
15268 	}
15269     }
15270     return SQL_SUCCESS;
15271 }
15272 
15273 #ifndef WINTERFACE
15274 /**
15275  * Return data type information.
15276  * @param stmt statement handle
15277  * @param sqltype which type to retrieve
15278  * @result ODBC error code
15279  */
15280 
15281 SQLRETURN SQL_API
SQLGetTypeInfo(SQLHSTMT stmt,SQLSMALLINT sqltype)15282 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
15283 {
15284     SQLRETURN ret;
15285 
15286     HSTMT_LOCK(stmt);
15287     ret = drvgettypeinfo(stmt, sqltype);
15288     HSTMT_UNLOCK(stmt);
15289     return ret;
15290 }
15291 #endif
15292 
15293 #ifdef WINTERFACE
15294 /**
15295  * Return data type information (UNICODE version).
15296  * @param stmt statement handle
15297  * @param sqltype which type to retrieve
15298  * @result ODBC error code
15299  */
15300 
15301 SQLRETURN SQL_API
SQLGetTypeInfoW(SQLHSTMT stmt,SQLSMALLINT sqltype)15302 SQLGetTypeInfoW(SQLHSTMT stmt, SQLSMALLINT sqltype)
15303 {
15304     SQLRETURN ret;
15305 
15306     HSTMT_LOCK(stmt);
15307     ret = drvgettypeinfo(stmt, sqltype);
15308     HSTMT_UNLOCK(stmt);
15309     return ret;
15310 }
15311 #endif
15312 
15313 /**
15314  * Columns for result set of SQLStatistics().
15315  */
15316 
15317 static COL statSpec2[] = {
15318     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
15319     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
15320     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
15321     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
15322     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
15323     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
15324     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
15325     { "SYSTEM", "STATISTICS", "SEQ_IN_INDEX", SQL_SMALLINT, 50 },
15326     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
15327     { "SYSTEM", "STATISTICS", "COLLATION", SCOL_CHAR, 1 },
15328     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
15329     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
15330     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
15331 };
15332 
15333 static COL statSpec3[] = {
15334     { "SYSTEM", "STATISTICS", "TABLE_CAT", SCOL_VARCHAR, 50 },
15335     { "SYSTEM", "STATISTICS", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
15336     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
15337     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
15338     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
15339     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
15340     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
15341     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
15342     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
15343     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
15344     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
15345     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
15346     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
15347 };
15348 
15349 /**
15350  * Internal return statistic information on table indices.
15351  * @param stmt statement handle
15352  * @param cat catalog name/pattern or NULL
15353  * @param catLen length of catalog name/pattern or SQL_NTS
15354  * @param schema schema name/pattern or NULL
15355  * @param schemaLen length of schema name/pattern or SQL_NTS
15356  * @param table table name/pattern or NULL
15357  * @param tableLen length of table name/pattern or SQL_NTS
15358  * @param itype type of index information
15359  * @param resv reserved
15360  * @result ODBC error code
15361  */
15362 
15363 static SQLRETURN
drvstatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)15364 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
15365 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
15366 	      SQLCHAR *table, SQLSMALLINT tableLen,
15367 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
15368 {
15369     SQLRETURN sret;
15370     STMT *s;
15371     DBC *d;
15372     int i, asize, ret, nrows, ncols, offs, namec, uniquec, addipk = 0;
15373     PTRDIFF_T size;
15374     char **rowp, *errp = NULL, *sql, tname[512];
15375 
15376     sret = mkresultset(stmt, statSpec2, array_size(statSpec2),
15377 		       statSpec3, array_size(statSpec3), &asize);
15378     if (sret != SQL_SUCCESS) {
15379 	return sret;
15380     }
15381     s = (STMT *) stmt;
15382     d = (DBC *) s->dbc;
15383     if (!table || table[0] == '\0' || table[0] == '%') {
15384 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
15385 	return SQL_ERROR;
15386     }
15387     if (tableLen == SQL_NTS) {
15388 	size = sizeof (tname) - 1;
15389     } else {
15390 	size = min(sizeof (tname) - 1, tableLen);
15391     }
15392     strncpy(tname, (char *) table, size);
15393     tname[size] = '\0';
15394     unescpat(tname);
15395     sret = starttran(s);
15396     if (sret != SQL_SUCCESS) {
15397 	return sret;
15398     }
15399     /*
15400      * Try integer primary key (autoincrement) first
15401      */
15402     if (itype == SQL_INDEX_UNIQUE || itype == SQL_INDEX_ALL) {
15403 	rowp = 0;
15404 	ret = SQLITE4_ERROR;
15405 	sql = sqlite4_mprintf(0, "PRAGMA table_info(%Q)", tname);
15406 	if (sql) {
15407 	    dbtraceapi(d, "sqlite4_get_table", sql);
15408 	    ret = sqlite4_get_table(d->sqlite, sql, &rowp,
15409 				    &nrows, &ncols, NULL);
15410 	    sqlite4_free(0, sql);
15411 	}
15412 	if (ret == SQLITE4_OK) {
15413 	    int colid, typec, npk = 0, npkint = 0;
15414 
15415 	    namec = findcol(rowp, ncols, "name");
15416 	    uniquec = findcol(rowp, ncols, "pk");
15417 	    typec = findcol(rowp, ncols, "type");
15418 	    colid = findcol(rowp, ncols, "cid");
15419 	    if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
15420 		goto noipk;
15421 	    }
15422 	    for (i = 1; i <= nrows; i++) {
15423 		if (*rowp[i * ncols + uniquec] != '0') {
15424 		    npk++;
15425 		    if (strlen(rowp[i * ncols + typec]) == 7 &&
15426 			strncasecmp(rowp[i * ncols + typec], "integer", 7)
15427 			== 0) {
15428 			npkint++;
15429 		    }
15430 		}
15431 	    }
15432 	    if (npkint == 1 && npk == nkpint) {
15433 		addipk = 1;
15434 	    }
15435 	}
15436 noipk:
15437 	freerows(rowp);
15438     }
15439     sql = sqlite4_mprintf(0, "PRAGMA index_list(%Q)", tname);
15440     if (!sql) {
15441 	return nomem(s);
15442     }
15443     dbtraceapi(d, "sqlite4_get_table", sql);
15444     ret = sqlite4_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, &errp);
15445     sqlite4_free(0, sql);
15446     if (ret != SQLITE4_OK) {
15447 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
15448 		errp ? errp : "unknown error", ret);
15449 	if (errp) {
15450 	    sqlite4_free(0, errp);
15451 	    errp = NULL;
15452 	}
15453 	return SQL_ERROR;
15454     }
15455     if (errp) {
15456 	sqlite4_free(0, errp);
15457 	errp = NULL;
15458     }
15459     size = 0;
15460     namec = findcol(rowp, ncols, "name");
15461     uniquec = findcol(rowp, ncols, "unique");
15462     if (namec < 0 || uniquec < 0) {
15463 	goto nodata;
15464     }
15465     for (i = 1; i <= nrows; i++) {
15466 	int nnrows, nncols;
15467 	char **rowpp;
15468 	int isuniq;
15469 
15470 	isuniq = *rowp[i * ncols + uniquec] != '0';
15471 	if (isuniq || itype == SQL_INDEX_ALL) {
15472 	    ret = SQLITE4_ERROR;
15473 	    sql = sqlite4_mprintf(0, "PRAGMA index_info(%Q)",
15474 				  rowp[i * ncols + namec]);
15475 	    if (sql) {
15476 		dbtraceapi(d, "sqlite4_get_table", sql);
15477 		ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
15478 					&nnrows, &nncols, NULL);
15479 		sqlite4_free(0, sql);
15480 	    }
15481 	    if (ret == SQLITE4_OK) {
15482 		size += nnrows;
15483 		freerows(rowpp);
15484 	    }
15485 	}
15486     }
15487 nodata:
15488     if (addipk) {
15489 	size++;
15490     }
15491     if (size == 0) {
15492 	freerows(rowp);
15493 	return SQL_SUCCESS;
15494     }
15495     s->nrows = size;
15496     size = (size + 1) * asize;
15497     s->rows = xmalloc((size + 1) * sizeof (char *));
15498     if (!s->rows) {
15499 	s->nrows = 0;
15500 	return nomem(s);
15501     }
15502     s->rows[0] = (char *) size;
15503     s->rows += 1;
15504     memset(s->rows, 0, sizeof (char *) * size);
15505     s->rowfree = freerows;
15506     offs = 0;
15507     if (addipk) {
15508 	char **rowpp = 0;
15509 	int nrows2, ncols2;
15510 
15511 	sql = sqlite4_mprintf(0, "PRAGMA table_info(%Q)", tname);
15512 	if (sql) {
15513 	    dbtraceapi(d, "sqlite4_get_table", sql);
15514 	    ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
15515 				    &nrows2, &ncols2, NULL);
15516 	    sqlite4_free(0, sql);
15517 	}
15518 	if (ret == SQLITE4_OK) {
15519 	    int colid, typec, roffs, namecc, uniquecc;
15520 
15521 	    namecc = findcol(rowpp, ncols2, "name");
15522 	    uniquecc = findcol(rowpp, ncols2, "pk");
15523 	    typec = findcol(rowpp, ncols2, "type");
15524 	    colid = findcol(rowpp, ncols2, "cid");
15525 	    if (namecc < 0 || uniquecc < 0 || typec < 0 || colid < 0) {
15526 		addipk = 0;
15527 		s->nrows--;
15528 		goto nodata2;
15529 	    }
15530 	    for (i = 1; i <= nrows2; i++) {
15531 		if (*rowpp[i * ncols2 + uniquecc] != '0' &&
15532 		    strlen(rowpp[i * ncols2 + typec]) == 7 &&
15533 		    strncasecmp(rowpp[i * ncols2 + typec], "integer", 7)
15534 		    == 0) {
15535 		    break;
15536 		}
15537 	    }
15538 	    if (i > nrows2) {
15539 		addipk = 0;
15540 		s->nrows--;
15541 		goto nodata2;
15542 	    }
15543 	    roffs = s->ncols;
15544 #if defined(_WIN32) || defined(_WIN64)
15545 	    s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
15546 	    s->rows[roffs + 1] = xstrdup("");
15547 #else
15548 	    s->rows[roffs + 0] = xstrdup("");
15549 	    s->rows[roffs + 1] = xstrdup("");
15550 #endif
15551 	    s->rows[roffs + 2] = xstrdup(tname);
15552 	    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
15553 	    s->rows[roffs + 5] = xstrdup("sqlite_autoindex_0");
15554 	    s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
15555 	    s->rows[roffs + 7] = xstrdup("1");
15556 	    s->rows[roffs + 8] = xstrdup(rowpp[i * ncols2 + namecc]);
15557 	    s->rows[roffs + 9] = xstrdup("A");
15558 	}
15559 nodata2:
15560 	freerows(rowpp);
15561     }
15562     for (i = 1; i <= nrows; i++) {
15563 	int nnrows, nncols;
15564 	char **rowpp = 0;
15565 
15566 	if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
15567 	    int k;
15568 
15569 	    ret = SQLITE4_ERROR;
15570 	    sql = sqlite4_mprintf(0, "PRAGMA index_info(%Q)",
15571 				  rowp[i * ncols + namec]);
15572 	    if (sql) {
15573 		dbtraceapi(d, "sqlite4_get_table", sql);
15574 		ret = sqlite4_get_table(d->sqlite, sql, &rowpp,
15575 					&nnrows, &nncols, NULL);
15576 		sqlite4_free(0, sql);
15577 	    }
15578 	    if (ret != SQLITE4_OK) {
15579 		continue;
15580 	    }
15581 	    for (k = 0; nnrows && k < nncols; k++) {
15582 		if (strcmp(rowpp[k], "name") == 0) {
15583 		    int m;
15584 
15585 		    for (m = 1; m <= nnrows; m++) {
15586 			int roffs = (offs + addipk + m) * s->ncols;
15587 			int isuniq;
15588 
15589 			isuniq = *rowp[i * ncols + uniquec] != '0';
15590 			s->rows[roffs + 0] = xstrdup("");
15591 			s->rows[roffs + 1] = xstrdup("");
15592 			s->rows[roffs + 2] = xstrdup(tname);
15593 			if (isuniq) {
15594 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
15595 			} else {
15596 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
15597 			}
15598 			s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
15599 			s->rows[roffs + 6] =
15600 			    xstrdup(stringify(SQL_INDEX_OTHER));
15601 			s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
15602 			s->rows[roffs + 9] = xstrdup("A");
15603 		    }
15604 		} else if (strcmp(rowpp[k], "seqno") == 0) {
15605 		    int m;
15606 
15607 		    for (m = 1; m <= nnrows; m++) {
15608 			int roffs = (offs + addipk + m) * s->ncols;
15609 			int pos = m - 1;
15610 			char buf[32];
15611 
15612 			sscanf(rowpp[m * nncols + k], "%d", &pos);
15613 			sprintf(buf, "%d", pos + 1);
15614 			s->rows[roffs + 7] = xstrdup(buf);
15615 		    }
15616 		}
15617 	    }
15618 	    offs += nnrows;
15619 	    freerows(rowpp);
15620 	}
15621     }
15622     freerows(rowp);
15623     return SQL_SUCCESS;
15624 }
15625 
15626 #ifndef WINTERFACE
15627 /**
15628  * Return statistic information on table indices.
15629  * @param stmt statement handle
15630  * @param cat catalog name/pattern or NULL
15631  * @param catLen length of catalog name/pattern or SQL_NTS
15632  * @param schema schema name/pattern or NULL
15633  * @param schemaLen length of schema name/pattern or SQL_NTS
15634  * @param table table name/pattern or NULL
15635  * @param tableLen length of table name/pattern or SQL_NTS
15636  * @param itype type of index information
15637  * @param resv reserved
15638  * @result ODBC error code
15639  */
15640 
15641 SQLRETURN SQL_API
SQLStatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)15642 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
15643 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
15644 	      SQLCHAR *table, SQLSMALLINT tableLen,
15645 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
15646 {
15647 #if defined(_WIN32) || defined(_WIN64)
15648     char *c = NULL, *s = NULL, *t = NULL;
15649 #endif
15650     SQLRETURN ret;
15651 
15652     HSTMT_LOCK(stmt);
15653 #if defined(_WIN32) || defined(_WIN64)
15654     if (!((STMT *) stmt)->oemcp[0]) {
15655 	ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
15656 			    table, tableLen, itype, resv);
15657 	goto done2;
15658     }
15659     if (cat) {
15660 	c = wmb_to_utf_c((char *) cat, catLen);
15661 	if (!c) {
15662 	    ret = nomem((STMT *) stmt);
15663 	    goto done;
15664 	}
15665     }
15666     if (schema) {
15667 	s = wmb_to_utf_c((char *) schema, schemaLen);
15668 	if (!s) {
15669 	    ret = nomem((STMT *) stmt);
15670 	    goto done;
15671 	}
15672     }
15673     if (table) {
15674 	t = wmb_to_utf_c((char *) table, tableLen);
15675 	if (!t) {
15676 	    ret = nomem((STMT *) stmt);
15677 	    goto done;
15678 	}
15679     }
15680     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
15681 			(SQLCHAR *) t, SQL_NTS, itype, resv);
15682 #else
15683     ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
15684 			table, tableLen, itype, resv);
15685 #endif
15686 #if defined(_WIN32) || defined(_WIN64)
15687 done:
15688     uc_free(t);
15689     uc_free(s);
15690     uc_free(c);
15691 done2:
15692     ;
15693 #endif
15694     HSTMT_UNLOCK(stmt);
15695     return ret;
15696 }
15697 #endif
15698 
15699 #ifdef WINTERFACE
15700 /**
15701  * Return statistic information on table indices (UNICODE version).
15702  * @param stmt statement handle
15703  * @param cat catalog name/pattern or NULL
15704  * @param catLen length of catalog name/pattern or SQL_NTS
15705  * @param schema schema name/pattern or NULL
15706  * @param schemaLen length of schema name/pattern or SQL_NTS
15707  * @param table table name/pattern or NULL
15708  * @param tableLen length of table name/pattern or SQL_NTS
15709  * @param itype type of index information
15710  * @param resv reserved
15711  * @result ODBC error code
15712  */
15713 
15714 SQLRETURN SQL_API
SQLStatisticsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)15715 SQLStatisticsW(SQLHSTMT stmt, SQLWCHAR *cat, SQLSMALLINT catLen,
15716 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
15717 	       SQLWCHAR *table, SQLSMALLINT tableLen,
15718 	       SQLUSMALLINT itype, SQLUSMALLINT resv)
15719 {
15720     char *c = NULL, *s = NULL, *t = NULL;
15721     SQLRETURN ret;
15722 
15723     HSTMT_LOCK(stmt);
15724     if (cat) {
15725 	c = uc_to_utf_c(cat, catLen);
15726 	if (!c) {
15727 	    ret = nomem((STMT *) stmt);
15728 	    goto done;
15729 	}
15730     }
15731     if (schema) {
15732 	s = uc_to_utf_c(schema, schemaLen);
15733 	if (!s) {
15734 	    ret = nomem((STMT *) stmt);
15735 	    goto done;
15736 	}
15737     }
15738     if (table) {
15739 	t = uc_to_utf_c(table, tableLen);
15740 	if (!t) {
15741 	    ret = nomem((STMT *) stmt);
15742 	    goto done;
15743 	}
15744     }
15745     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
15746 			(SQLCHAR *) t, SQL_NTS, itype, resv);
15747 done:
15748     uc_free(t);
15749     uc_free(s);
15750     uc_free(c);
15751     HSTMT_UNLOCK(stmt);
15752     return ret;
15753 }
15754 #endif
15755 
15756 /**
15757  * Retrieve row data after fetch.
15758  * @param stmt statement handle
15759  * @param col column number, starting at 1
15760  * @param type output type
15761  * @param val output buffer
15762  * @param len length of output buffer
15763  * @param lenp output length
15764  * @result ODBC error code
15765  */
15766 
15767 SQLRETURN SQL_API
SQLGetData(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN len,SQLLEN * lenp)15768 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
15769 	   SQLPOINTER val, SQLLEN len, SQLLEN *lenp)
15770 {
15771     STMT *s;
15772     SQLRETURN ret = SQL_ERROR;
15773 
15774     HSTMT_LOCK(stmt);
15775     if (stmt == SQL_NULL_HSTMT) {
15776 	return SQL_INVALID_HANDLE;
15777     }
15778     s = (STMT *) stmt;
15779     if (col == 0 && s->bkmrk != SQL_UB_OFF) {
15780 	if (s->bkmrk == SQL_UB_ON && type == SQL_C_BOOKMARK) {
15781 	    *((SQLINTEGER *) val) = s->rowp;
15782 	    if (lenp) {
15783 		*lenp = sizeof (SQLINTEGER);
15784 	    }
15785 	    ret = SQL_SUCCESS;
15786 	    goto done;
15787 	} else if (s->bkmrk == SQL_UB_VARIABLE && type == SQL_C_VARBOOKMARK) {
15788 	    if (s->has_rowid >= 0) {
15789 		char **data, *endp = 0;
15790 
15791 		data = s->rows + s->ncols + (s->rowp * s->ncols)
15792 		     + s->has_rowid;
15793 #ifdef __osf__
15794 		*((sqlite4_int64 *) val) = strtol(*data, &endp, 0);
15795 #else
15796 		*((sqlite4_int64 *) val) = strtoll(*data, &endp, 0);
15797 #endif
15798 	    } else {
15799 		*((sqlite4_int64 *) val) = s->rowp;
15800 	    }
15801 	    if (lenp) {
15802 		*lenp = sizeof (sqlite4_int64);
15803 	    }
15804 	    ret = SQL_SUCCESS;
15805 	    goto done;
15806 	}
15807     }
15808     if (col < 1 || col > s->ncols) {
15809 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
15810 	goto done;
15811     }
15812     --col;
15813     ret = getrowdata(s, col, type, val, len, lenp, 1);
15814 done:
15815     HSTMT_UNLOCK(stmt);
15816     return ret;
15817 }
15818 
15819 /**
15820  * Internal: fetch and bind from statement's current row
15821  * @param s statement pointer
15822  * @param rsi rowset index
15823  * @result ODBC error code
15824  */
15825 
15826 static SQLRETURN
dofetchbind(STMT * s,int rsi)15827 dofetchbind(STMT *s, int rsi)
15828 {
15829     int ret, i, withinfo = 0;
15830 
15831     s->row_status0[rsi] = SQL_ROW_SUCCESS;
15832     if (s->bkmrk != SQL_UB_OFF && s->bkmrkcol.valp) {
15833 	int bsize = sizeof (SQLINTEGER);
15834 
15835 	if (s->bkmrkcol.type == SQL_C_VARBOOKMARK) {
15836 	    SQLPOINTER *val;
15837 
15838 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
15839 		val = (SQLPOINTER)
15840 		    ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
15841 	    } else {
15842 		val = (SQLPOINTER)
15843 		    ((char *) s->bkmrkcol.valp + s->bkmrkcol.max * rsi);
15844 	    }
15845 	    if (s->bind_offs) {
15846 		val = (SQLPOINTER) ((char *) val + *s->bind_offs);
15847 	    }
15848 	    if (s->has_rowid >= 0) {
15849 		char **data, *endp = 0;
15850 
15851 		data = s->rows + s->ncols + (s->rowp * s->ncols)
15852 		     + s->has_rowid;
15853 #ifdef __osf__
15854 		*(sqlite4_int64 *) val = strtol(*data, &endp, 0);
15855 #else
15856 		*(sqlite4_int64 *) val = strtoll(*data, &endp, 0);
15857 #endif
15858 	    } else {
15859 		*(sqlite4_int64 *) val = s->rowp;
15860 	    }
15861 	    bsize = sizeof (sqlite4_int64);
15862 	} else {
15863 	    SQLINTEGER *val;
15864 
15865 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
15866 		val = (SQLINTEGER *)
15867 		    ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
15868 	    } else {
15869 		val = (SQLINTEGER *) s->bkmrkcol.valp + rsi;
15870 	    }
15871 	    if (s->bind_offs) {
15872 		val = (SQLINTEGER *) ((char *) val + *s->bind_offs);
15873 	    }
15874 	    *val = s->rowp;
15875 	}
15876 	if (s->bkmrkcol.lenp) {
15877 	    SQLLEN *ival;
15878 
15879 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
15880 		ival = (SQLLEN *)
15881 		    ((char *) s->bkmrkcol.lenp + s->bind_type * rsi);
15882 	    } else {
15883 		ival = &s->bkmrkcol.lenp[rsi];
15884 	    }
15885 	    if (s->bind_offs) {
15886 		ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
15887 	    }
15888 	    *ival = bsize;
15889 	}
15890     }
15891     ret = SQL_SUCCESS;
15892     for (i = 0; s->bindcols && i < s->ncols; i++) {
15893 	BINDCOL *b = &s->bindcols[i];
15894 	SQLPOINTER dp = 0;
15895 	SQLLEN *lp = 0;
15896 
15897 	b->offs = 0;
15898 	if (b->valp) {
15899 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
15900 		dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
15901 	    } else {
15902 		dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
15903 	    }
15904 	    if (s->bind_offs) {
15905 		dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
15906 	    }
15907 	}
15908 	if (b->lenp) {
15909 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
15910 		lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
15911 	    } else {
15912 		lp = b->lenp + rsi;
15913 	    }
15914 	    if (s->bind_offs) {
15915 		lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
15916 	    }
15917 	}
15918 	if (dp || lp) {
15919 	    ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
15920 	    if (!SQL_SUCCEEDED(ret)) {
15921 		s->row_status0[rsi] = SQL_ROW_ERROR;
15922 		break;
15923 	    }
15924 	    if (ret != SQL_SUCCESS) {
15925 		withinfo = 1;
15926 #ifdef SQL_ROW_SUCCESS_WITH_INFO
15927 		s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
15928 #endif
15929 	    }
15930 	}
15931     }
15932     if (SQL_SUCCEEDED(ret)) {
15933 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
15934     }
15935     return ret;
15936 }
15937 
15938 /**
15939  * Internal fetch function for SQLFetchScroll() and SQLExtendedFetch().
15940  * @param stmt statement handle
15941  * @param orient fetch direction
15942  * @param offset offset for fetch direction
15943  * @result ODBC error code
15944  */
15945 
15946 static SQLRETURN
drvfetchscroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLINTEGER offset)15947 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
15948 {
15949     STMT *s;
15950     int i, withinfo = 0;
15951     SQLRETURN ret;
15952 
15953     if (stmt == SQL_NULL_HSTMT) {
15954 	return SQL_INVALID_HANDLE;
15955     }
15956     s = (STMT *) stmt;
15957     for (i = 0; i < s->rowset_size; i++) {
15958 	s->row_status0[i] = SQL_ROW_NOROW;
15959     }
15960     if (s->row_status) {
15961 	memcpy(s->row_status, s->row_status0,
15962 	       sizeof (SQLUSMALLINT) * s->rowset_size);
15963     }
15964     s->row_count0 = 0;
15965     if (s->row_count) {
15966 	*s->row_count = s->row_count0;
15967     }
15968     if (!s->bindcols) {
15969 	for (i = 0; i < s->rowset_size; i++) {
15970 	    s->row_status0[i] = SQL_ROW_ERROR;
15971 	}
15972 	ret = SQL_ERROR;
15973 	i = 0;
15974 	goto done2;
15975     }
15976     if (s->isselect != 1 && s->isselect != -1) {
15977 	setstat(s, -1, "no result set available", "24000");
15978 	ret = SQL_ERROR;
15979 	i = s->nrows;
15980 	goto done2;
15981     }
15982     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
15983 	setstat(s, -1, "wrong fetch direction", "01000");
15984 	ret = SQL_ERROR;
15985 	i = 0;
15986 	goto done2;
15987     }
15988     ret = SQL_SUCCESS;
15989     i = 0;
15990     if (((DBC *) (s->dbc))->cur_s4stmt == s && s->s4stmt) {
15991 	s->rowp = s->rowprs = 0;
15992 	for (; i < s->rowset_size; i++) {
15993 	    if (s->max_rows && s->s4stmt_rownum + 1 >= s->max_rows) {
15994 		ret = (i == 0) ? SQL_NO_DATA : SQL_SUCCESS;
15995 		break;
15996 	    }
15997 	    ret = s4stmt_step(s);
15998 	    if (ret != SQL_SUCCESS) {
15999 		s->row_status0[i] = SQL_ROW_ERROR;
16000 		break;
16001 	    }
16002 	    if (s->nrows < 1) {
16003 		break;
16004 	    }
16005 	    ret = dofetchbind(s, i);
16006 	    if (!SQL_SUCCEEDED(ret)) {
16007 		break;
16008 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
16009 		withinfo = 1;
16010 	    }
16011 	}
16012     } else if (s->rows) {
16013 	switch (orient) {
16014 	case SQL_FETCH_NEXT:
16015 	    if (s->nrows < 1) {
16016 		return SQL_NO_DATA;
16017 	    }
16018 	    if (s->rowp < 0) {
16019 		s->rowp = -1;
16020 	    }
16021 	    if (s->rowp >= s->nrows) {
16022 		s->rowp = s->rowprs = s->nrows;
16023 		return SQL_NO_DATA;
16024 	    }
16025 	    break;
16026 	case SQL_FETCH_PRIOR:
16027 	    if (s->nrows < 1 || s->rowp <= 0) {
16028 		s->rowp = s->rowprs = -1;
16029 		return SQL_NO_DATA;
16030 	    }
16031 	    s->rowp -= s->rowset_size + 1;
16032 	    if (s->rowp < -1) {
16033 		s->rowp = s->rowprs = -1;
16034 		return SQL_NO_DATA;
16035 	    }
16036 	    break;
16037 	case SQL_FETCH_FIRST:
16038 	    if (s->nrows < 1) {
16039 		return SQL_NO_DATA;
16040 	    }
16041 	    s->rowp = -1;
16042 	    break;
16043 	case SQL_FETCH_LAST:
16044 	    if (s->nrows < 1) {
16045 		return SQL_NO_DATA;
16046 	    }
16047 	    s->rowp = s->nrows - s->rowset_size;
16048 	    if (--s->rowp < -1) {
16049 		s->rowp = -1;
16050 	    }
16051 	    break;
16052 	case SQL_FETCH_ABSOLUTE:
16053 	    if (offset == 0) {
16054 		s->rowp = s->rowprs = -1;
16055 		return SQL_NO_DATA;
16056 	    } else if (offset < 0) {
16057 		if (0 - offset <= s->nrows) {
16058 		    s->rowp = s->nrows + offset - 1;
16059 		    break;
16060 		}
16061 		s->rowp = s->rowprs = -1;
16062 		return SQL_NO_DATA;
16063 	    } else if (offset > s->nrows) {
16064 		s->rowp = s->rowprs = s->nrows;
16065 		return SQL_NO_DATA;
16066 	    }
16067 	    s->rowp = offset - 1 - 1;
16068 	    break;
16069 	case SQL_FETCH_RELATIVE:
16070 	    if (offset >= 0) {
16071 		s->rowp += offset * s->rowset_size - 1;
16072 		if (s->rowp >= s->nrows) {
16073 		    s->rowp = s->rowprs = s->nrows;
16074 		    return SQL_NO_DATA;
16075 		}
16076 	    } else {
16077 		s->rowp += offset * s->rowset_size - 1;
16078 		if (s->rowp < -1) {
16079 		    s->rowp = s->rowprs = -1;
16080 		    return SQL_NO_DATA;
16081 		}
16082 	    }
16083 	    break;
16084 	case SQL_FETCH_BOOKMARK:
16085 	    if (s->bkmrk == SQL_UB_ON && !s->bkmrkptr) {
16086 		if (offset < 0 || offset >= s->nrows) {
16087 		    return SQL_NO_DATA;
16088 		}
16089 		s->rowp = offset - 1;
16090 		break;
16091 	    }
16092 	    if (s->bkmrk != SQL_UB_OFF && s->bkmrkptr) {
16093 		int rowp;
16094 
16095 		if (s->bkmrk == SQL_UB_VARIABLE) {
16096 		    if (s->has_rowid >= 0) {
16097 			sqlite4_int64 bkmrk, rowid;
16098 
16099 			bkmrk = *(sqlite4_int64 *) s->bkmrkptr;
16100 			for (rowp = 0; rowp < s->nrows; rowp++) {
16101 			    char **data, *endp = 0;
16102 
16103 			    data = s->rows + s->ncols + (rowp * s->ncols)
16104 				 + s->has_rowid;
16105 #ifdef __osf__
16106 			    rowid = strtol(*data, &endp, 0);
16107 #else
16108 			    rowid = strtoll(*data, &endp, 0);
16109 #endif
16110 			    if (rowid == bkmrk) {
16111 				break;
16112 			    }
16113 			}
16114 		    } else {
16115 			rowp = *(sqlite4_int64 *) s->bkmrkptr;
16116 		    }
16117 		} else {
16118 		    rowp = *(int *) s->bkmrkptr;
16119 		}
16120 		if (rowp + offset < 0 || rowp + offset >= s->nrows) {
16121 		    return SQL_NO_DATA;
16122 		}
16123 		s->rowp = rowp + offset - 1;
16124 		break;
16125 	    }
16126 	    /* fall through */
16127 	default:
16128 	    s->row_status0[0] = SQL_ROW_ERROR;
16129 	    ret = SQL_ERROR;
16130 	    goto done;
16131 	}
16132 	s->rowprs = s->rowp + 1;
16133 	for (; i < s->rowset_size; i++) {
16134 	    ++s->rowp;
16135 	    if (s->rowp < 0 || s->rowp >= s->nrows) {
16136 		break;
16137 	    }
16138 	    ret = dofetchbind(s, i);
16139 	    if (!SQL_SUCCEEDED(ret)) {
16140 		break;
16141 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
16142 		withinfo = 1;
16143 	    }
16144 	}
16145     }
16146 done:
16147     if (i == 0) {
16148 	if (SQL_SUCCEEDED(ret)) {
16149 	    return SQL_NO_DATA;
16150 	}
16151 	return ret;
16152     }
16153     if (SQL_SUCCEEDED(ret)) {
16154 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
16155     }
16156 done2:
16157     if (s->row_status) {
16158 	memcpy(s->row_status, s->row_status0,
16159 	       sizeof (SQLUSMALLINT) * s->rowset_size);
16160     }
16161     s->row_count0 = i;
16162     if (s->row_count) {
16163 	*s->row_count = s->row_count0;
16164     }
16165     return ret;
16166 }
16167 
16168 /**
16169  * Fetch next result row.
16170  * @param stmt statement handle
16171  * @result ODBC error code
16172  */
16173 
16174 SQLRETURN SQL_API
SQLFetch(SQLHSTMT stmt)16175 SQLFetch(SQLHSTMT stmt)
16176 {
16177     SQLRETURN ret;
16178 
16179     HSTMT_LOCK(stmt);
16180     ret = drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
16181     HSTMT_UNLOCK(stmt);
16182     return ret;
16183 }
16184 
16185 /**
16186  * Fetch result row with scrolling.
16187  * @param stmt statement handle
16188  * @param orient fetch direction
16189  * @param offset offset for fetch direction
16190  * @result ODBC error code
16191  */
16192 
16193 SQLRETURN SQL_API
SQLFetchScroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLLEN offset)16194 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLLEN offset)
16195 {
16196     SQLRETURN ret;
16197 
16198     HSTMT_LOCK(stmt);
16199     ret = drvfetchscroll(stmt, orient, offset);
16200     HSTMT_UNLOCK(stmt);
16201     return ret;
16202 }
16203 
16204 /**
16205  * Fetch result row with scrolling and row status.
16206  * @param stmt statement handle
16207  * @param orient fetch direction
16208  * @param offset offset for fetch direction
16209  * @param rowcount output number of fetched rows
16210  * @param rowstatus array for row stati
16211  * @result ODBC error code
16212  */
16213 
16214 SQLRETURN SQL_API
SQLExtendedFetch(SQLHSTMT stmt,SQLUSMALLINT orient,SQLROWOFFSET offset,SQLROWSETSIZE * rowcount,SQLUSMALLINT * rowstatus)16215 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLROWOFFSET offset,
16216 		 SQLROWSETSIZE *rowcount, SQLUSMALLINT *rowstatus)
16217 {
16218     STMT *s;
16219     SQLRETURN ret;
16220     SQLUSMALLINT *rst;
16221     SQLINTEGER *bkmrkptr;
16222 
16223     HSTMT_LOCK(stmt);
16224     if (stmt == SQL_NULL_HSTMT) {
16225 	return SQL_INVALID_HANDLE;
16226     }
16227     s = (STMT *) stmt;
16228     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
16229     rst = s->row_status;
16230     s->row_status = 0;
16231     bkmrkptr = s->bkmrkptr;
16232     s->bkmrkptr = 0;
16233     ret = drvfetchscroll(stmt, orient, offset);
16234     s->row_status = rst;
16235     s->bkmrkptr = bkmrkptr;
16236     if (rowstatus) {
16237 	memcpy(rowstatus, s->row_status0,
16238 	       sizeof (SQLUSMALLINT) * s->rowset_size);
16239     }
16240     if (rowcount) {
16241 	*rowcount = s->row_count0;
16242     }
16243     HSTMT_UNLOCK(stmt);
16244     return ret;
16245 }
16246 
16247 /**
16248  * Return number of affected rows of HSTMT.
16249  * @param stmt statement handle
16250  * @param nrows output number of rows
16251  * @result ODBC error code
16252  */
16253 
16254 SQLRETURN SQL_API
SQLRowCount(SQLHSTMT stmt,SQLLEN * nrows)16255 SQLRowCount(SQLHSTMT stmt, SQLLEN *nrows)
16256 {
16257     STMT *s;
16258 
16259     HSTMT_LOCK(stmt);
16260     if (stmt == SQL_NULL_HSTMT) {
16261 	return SQL_INVALID_HANDLE;
16262     }
16263     s = (STMT *) stmt;
16264     if (nrows) {
16265 	*nrows = s->isselect ? 0 : s->nrows;
16266     }
16267     HSTMT_UNLOCK(stmt);
16268     return SQL_SUCCESS;
16269 }
16270 
16271 /**
16272  * Return number of columns of result set given HSTMT.
16273  * @param stmt statement handle
16274  * @param ncols output number of columns
16275  * @result ODBC error code
16276  */
16277 
16278 SQLRETURN SQL_API
SQLNumResultCols(SQLHSTMT stmt,SQLSMALLINT * ncols)16279 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
16280 {
16281     STMT *s;
16282 
16283     HSTMT_LOCK(stmt);
16284     if (stmt == SQL_NULL_HSTMT) {
16285 	return SQL_INVALID_HANDLE;
16286     }
16287     s = (STMT *) stmt;
16288     if (ncols) {
16289 	*ncols = s->ncols;
16290     }
16291     HSTMT_UNLOCK(stmt);
16292     return SQL_SUCCESS;
16293 }
16294 
16295 /**
16296  * Internal describe column information.
16297  * @param stmt statement handle
16298  * @param col column number, starting at 1
16299  * @param name buffer for column name
16300  * @param nameMax length of name buffer
16301  * @param nameLen output length of column name
16302  * @param type output SQL type
16303  * @param size output column size
16304  * @param digits output number of digits
16305  * @param nullable output NULL allowed indicator
16306  * @result ODBC error code
16307  */
16308 
16309 static SQLRETURN
drvdescribecol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)16310 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
16311 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
16312 	       SQLSMALLINT *type, SQLULEN *size,
16313 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
16314 {
16315     STMT *s;
16316     COL *c;
16317     int didname = 0;
16318 
16319     if (stmt == SQL_NULL_HSTMT) {
16320 	return SQL_INVALID_HANDLE;
16321     }
16322     s = (STMT *) stmt;
16323     if (!s->cols) {
16324 	setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
16325 	return SQL_ERROR;
16326     }
16327     if (col < 1 || col > s->ncols) {
16328 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
16329 	return SQL_ERROR;
16330     }
16331     c = s->cols + col - 1;
16332     if (name && nameMax > 0) {
16333 	strncpy((char *) name, c->column, nameMax);
16334 	name[nameMax - 1] = '\0';
16335 	didname = 1;
16336     }
16337     if (nameLen) {
16338 	if (didname) {
16339 	    *nameLen = strlen((char *) name);
16340 	} else {
16341 	    *nameLen = strlen(c->column);
16342 	}
16343     }
16344     if (type) {
16345 	*type = c->type;
16346 #ifdef WINTERFACE
16347 	if (s->nowchar[0] || s->nowchar[1]) {
16348 	    switch (c->type) {
16349 	    case SQL_WCHAR:
16350 		*type = SQL_CHAR;
16351 		break;
16352 	    case SQL_WVARCHAR:
16353 		*type = SQL_VARCHAR;
16354 		break;
16355 #ifdef SQL_LONGVARCHAR
16356 	    case SQL_WLONGVARCHAR:
16357 		*type = SQL_LONGVARCHAR;
16358 		break;
16359 #endif
16360 	    }
16361 	}
16362 #endif
16363     }
16364     if (size) {
16365 	*size = c->size;
16366     }
16367     if (digits) {
16368 	*digits = 0;
16369     }
16370     if (nullable) {
16371 	*nullable = 1;
16372     }
16373     return SQL_SUCCESS;
16374 }
16375 
16376 #ifndef WINTERFACE
16377 /**
16378  * Describe column information.
16379  * @param stmt statement handle
16380  * @param col column number, starting at 1
16381  * @param name buffer for column name
16382  * @param nameMax length of name buffer
16383  * @param nameLen output length of column name
16384  * @param type output SQL type
16385  * @param size output column size
16386  * @param digits output number of digits
16387  * @param nullable output NULL allowed indicator
16388  * @result ODBC error code
16389  */
16390 
16391 SQLRETURN SQL_API
SQLDescribeCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)16392 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
16393 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
16394 	       SQLSMALLINT *type, SQLULEN *size,
16395 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
16396 {
16397 #if defined(_WIN32) || defined(_WIN64)
16398     SQLSMALLINT len = 0;
16399 #endif
16400     SQLRETURN ret;
16401 
16402     HSTMT_LOCK(stmt);
16403 #if defined(_WIN32) || defined(_WIN64)
16404     if (!((STMT *) stmt)->oemcp[0]) {
16405 	ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
16406 			     type, size, digits, nullable);
16407 	goto done;
16408     }
16409     ret = drvdescribecol(stmt, col, name, nameMax,
16410 			 &len, type, size, digits, nullable);
16411     if (ret == SQL_SUCCESS) {
16412 	if (name) {
16413 	    if (len > 0) {
16414 		SQLCHAR *n = NULL;
16415 
16416 		n = (SQLCHAR *) utf_to_wmb((char *) name, len);
16417 		if (n) {
16418 		    strncpy((char *) name, (char *) n, nameMax);
16419 		    n[len] = 0;
16420 		    len = min(nameMax, strlen((char *) n));
16421 		    uc_free(n);
16422 		} else {
16423 		    len = 0;
16424 		}
16425 	    }
16426 	    if (len <= 0) {
16427 		len = 0;
16428 		if (nameMax > 0) {
16429 		    name[0] = 0;
16430 		}
16431 	    }
16432 	} else {
16433 	    STMT *s = (STMT *) stmt;
16434 	    COL *c = s->cols + col - 1;
16435 
16436 	    len = 0;
16437 	    if (c->column) {
16438 		len = strlen(c->column);
16439 	    }
16440 	}
16441 	if (nameLen) {
16442 	    *nameLen = len;
16443 	}
16444     }
16445 done:
16446     ;
16447 #else
16448     ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
16449 			 type, size, digits, nullable);
16450 #endif
16451     HSTMT_UNLOCK(stmt);
16452     return ret;
16453 }
16454 #endif
16455 
16456 #ifdef WINTERFACE
16457 /**
16458  * Describe column information (UNICODE version).
16459  * @param stmt statement handle
16460  * @param col column number, starting at 1
16461  * @param name buffer for column name
16462  * @param nameMax length of name buffer
16463  * @param nameLen output length of column name
16464  * @param type output SQL type
16465  * @param size output column size
16466  * @param digits output number of digits
16467  * @param nullable output NULL allowed indicator
16468  * @result ODBC error code
16469  */
16470 
16471 SQLRETURN SQL_API
SQLDescribeColW(SQLHSTMT stmt,SQLUSMALLINT col,SQLWCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)16472 SQLDescribeColW(SQLHSTMT stmt, SQLUSMALLINT col, SQLWCHAR *name,
16473 		SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
16474 		SQLSMALLINT *type, SQLULEN *size,
16475 		SQLSMALLINT *digits, SQLSMALLINT *nullable)
16476 {
16477     SQLRETURN ret;
16478     SQLSMALLINT len = 0;
16479 
16480     HSTMT_LOCK(stmt);
16481     ret = drvdescribecol(stmt, col, (SQLCHAR *) name,
16482 			 (SQLSMALLINT) (nameMax * sizeof (SQLWCHAR)),
16483 			 &len, type, size, digits, nullable);
16484     if (ret == SQL_SUCCESS) {
16485 	if (name) {
16486 	    if (len > 0) {
16487 		SQLWCHAR *n = NULL;
16488 
16489 		n = uc_from_utf((SQLCHAR *) name, len);
16490 		if (n) {
16491 		    uc_strncpy(name, n, nameMax);
16492 		    n[len] = 0;
16493 		    len = min(nameMax, uc_strlen(n));
16494 		    uc_free(n);
16495 		} else {
16496 		    len = 0;
16497 		}
16498 	    }
16499 	    if (len <= 0) {
16500 		len = 0;
16501 		if (nameMax > 0) {
16502 		    name[0] = 0;
16503 		}
16504 	    }
16505 	} else {
16506 	    STMT *s = (STMT *) stmt;
16507 	    COL *c = s->cols + col - 1;
16508 
16509 	    len = 0;
16510 	    if (c->column) {
16511 		len = strlen(c->column);
16512 	    }
16513 	}
16514 	if (nameLen) {
16515 	    *nameLen = len;
16516 	}
16517     }
16518     HSTMT_UNLOCK(stmt);
16519     return ret;
16520 }
16521 #endif
16522 
16523 /**
16524  * Internal retrieve column attributes.
16525  * @param stmt statement handle
16526  * @param col column number, starting at 1
16527  * @param id attribute id
16528  * @param val output buffer
16529  * @param valMax length of output buffer
16530  * @param valLen output length
16531  * @param val2 integer output buffer
16532  * @result ODBC error code
16533  */
16534 
16535 static SQLRETURN
drvcolattributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)16536 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
16537 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
16538 		 SQLLEN *val2)
16539 {
16540     STMT *s;
16541     COL *c;
16542     SQLSMALLINT dummy;
16543     char *valc = (char *) val;
16544 
16545     if (stmt == SQL_NULL_HSTMT) {
16546 	return SQL_INVALID_HANDLE;
16547     }
16548     s = (STMT *) stmt;
16549     if (!s->cols) {
16550 	return SQL_ERROR;
16551     }
16552     if (!valLen) {
16553 	valLen = &dummy;
16554     }
16555     if (id == SQL_COLUMN_COUNT) {
16556 	if (val2) {
16557 	    *val2 = s->ncols;
16558 	}
16559 	*valLen = sizeof (int);
16560 	return SQL_SUCCESS;
16561     }
16562     if (id == SQL_COLUMN_TYPE && col == 0) {
16563 	if (val2) {
16564 	    *val2 = SQL_INTEGER;
16565 	}
16566 	*valLen = sizeof (int);
16567 	return SQL_SUCCESS;
16568     }
16569 #ifdef SQL_DESC_OCTET_LENGTH
16570     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
16571 	if (val2) {
16572 	    *val2 = 4;
16573 	}
16574 	*valLen = sizeof (int);
16575 	return SQL_SUCCESS;
16576     }
16577 #endif
16578     if (col < 1 || col > s->ncols) {
16579 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
16580 	return SQL_ERROR;
16581     }
16582     c = s->cols + col - 1;
16583 
16584     switch (id) {
16585     case SQL_COLUMN_LABEL:
16586 	if (c->label) {
16587 	    if (valc && valMax > 0) {
16588 		strncpy(valc, c->label, valMax);
16589 		valc[valMax - 1] = '\0';
16590 	    }
16591 	    *valLen = strlen(c->label);
16592 	    goto checkLen;
16593 	}
16594 	/* fall through */
16595     case SQL_COLUMN_NAME:
16596     case SQL_DESC_NAME:
16597 	if (valc && valMax > 0) {
16598 	    strncpy(valc, c->column, valMax);
16599 	    valc[valMax - 1] = '\0';
16600 	}
16601 	*valLen = strlen(c->column);
16602 checkLen:
16603 	if (*valLen >= valMax) {
16604 	    setstat(s, -1, "data right truncated", "01004");
16605 	    return SQL_SUCCESS_WITH_INFO;
16606 	}
16607 	return SQL_SUCCESS;
16608 #ifdef SQL_DESC_BASE_COLUMN_NAME
16609     case SQL_DESC_BASE_COLUMN_NAME:
16610 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
16611 	    if (valc && valMax > 0) {
16612 		valc[0] = '\0';
16613 	    }
16614 	    *valLen = 0;
16615 	} else if (valc && valMax > 0) {
16616 	    strncpy(valc, c->column, valMax);
16617 	    valc[valMax - 1] = '\0';
16618 	    *valLen = strlen(c->column);
16619 	}
16620 	goto checkLen;
16621 #endif
16622     case SQL_COLUMN_TYPE:
16623     case SQL_DESC_TYPE:
16624 #ifdef WINTERFACE
16625 	{
16626 	    int type = c->type;
16627 
16628 	    if (s->nowchar[0] || s->nowchar[1]) {
16629 		switch (type) {
16630 		case SQL_WCHAR:
16631 		    type = SQL_CHAR;
16632 		    break;
16633 		case SQL_WVARCHAR:
16634 		    type = SQL_VARCHAR;
16635 		    break;
16636 #ifdef SQL_LONGVARCHAR
16637 		case SQL_WLONGVARCHAR:
16638 		    type = SQL_LONGVARCHAR;
16639 		    break;
16640 		}
16641 	    }
16642 	    if (val2) {
16643 		*val2 = type;
16644 	    }
16645 #endif
16646 	}
16647 #else
16648 	if (val2) {
16649 	    *val2 = c->type;
16650 	}
16651 #endif
16652 	*valLen = sizeof (int);
16653 	return SQL_SUCCESS;
16654     case SQL_COLUMN_DISPLAY_SIZE:
16655 	if (val2) {
16656 	    *val2 = c->size;
16657 	}
16658 	*valLen = sizeof (int);
16659 	return SQL_SUCCESS;
16660     case SQL_COLUMN_UNSIGNED:
16661 	if (val2) {
16662 	    *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
16663 	}
16664 	*valLen = sizeof (int);
16665 	return SQL_SUCCESS;
16666     case SQL_COLUMN_SCALE:
16667     case SQL_DESC_SCALE:
16668 	if (val2) {
16669 	    *val2 = c->scale;
16670 	}
16671 	*valLen = sizeof (int);
16672 	return SQL_SUCCESS;
16673     case SQL_COLUMN_PRECISION:
16674     case SQL_DESC_PRECISION:
16675 	if (val2) {
16676 	    switch (c->type) {
16677 	    case SQL_SMALLINT:
16678 		*val2 = 5;
16679 		break;
16680 	    case SQL_INTEGER:
16681 		*val2 = 10;
16682 		break;
16683 	    case SQL_FLOAT:
16684 	    case SQL_REAL:
16685 	    case SQL_DOUBLE:
16686 		*val2 = 15;
16687 		break;
16688 	    case SQL_DATE:
16689 		*val2 = 0;
16690 		break;
16691 	    case SQL_TIME:
16692 		*val2 = 0;
16693 		break;
16694 #ifdef SQL_TYPE_TIMESTAMP
16695 	    case SQL_TYPE_TIMESTAMP:
16696 #endif
16697 	    case SQL_TIMESTAMP:
16698 		*val2 = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
16699 		break;
16700 	    default:
16701 		*val2 = c->prec;
16702 		break;
16703 	    }
16704 	}
16705 	*valLen = sizeof (int);
16706 	return SQL_SUCCESS;
16707     case SQL_COLUMN_MONEY:
16708 	if (val2) {
16709 	    *val2 = SQL_FALSE;
16710 	}
16711 	*valLen = sizeof (int);
16712 	return SQL_SUCCESS;
16713     case SQL_COLUMN_AUTO_INCREMENT:
16714 	if (val2) {
16715 	    *val2 = c->autoinc;
16716 	}
16717 	*valLen = sizeof (int);
16718 	return SQL_SUCCESS;
16719     case SQL_COLUMN_LENGTH:
16720     case SQL_DESC_LENGTH:
16721 	if (val2) {
16722 	    *val2 = c->size;
16723 	}
16724 	*valLen = sizeof (int);
16725 	return SQL_SUCCESS;
16726     case SQL_COLUMN_NULLABLE:
16727     case SQL_DESC_NULLABLE:
16728 	if (val2) {
16729 	    *val2 = c->notnull;
16730 	}
16731 	*valLen = sizeof (int);
16732 	return SQL_SUCCESS;
16733     case SQL_COLUMN_SEARCHABLE:
16734 	if (val2) {
16735 	    *val2 = SQL_SEARCHABLE;
16736 	}
16737 	*valLen = sizeof (int);
16738 	return SQL_SUCCESS;
16739     case SQL_COLUMN_CASE_SENSITIVE:
16740 	if (val2) {
16741 	    *val2 = SQL_TRUE;
16742 	}
16743 	*valLen = sizeof (int);
16744 	return SQL_SUCCESS;
16745     case SQL_COLUMN_UPDATABLE:
16746 	if (val2) {
16747 	    *val2 = SQL_TRUE;
16748 	}
16749 	*valLen = sizeof (int);
16750 	return SQL_SUCCESS;
16751     case SQL_DESC_COUNT:
16752 	if (val2) {
16753 	    *val2 = s->ncols;
16754 	}
16755 	*valLen = sizeof (int);
16756 	return SQL_SUCCESS;
16757     case SQL_COLUMN_TYPE_NAME: {
16758 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
16759 
16760 #ifdef WINTERFACE
16761 	if (c->type == SQL_WCHAR ||
16762 	    c->type == SQL_WVARCHAR ||
16763 	    c->type == SQL_WLONGVARCHAR) {
16764 	    if (!(s->nowchar[0] || s->nowchar[1])) {
16765 		if (strcasecmp(tn, "varchar") == 0) {
16766 		    tn = "wvarchar";
16767 		}
16768 	    }
16769 	}
16770 #endif
16771 	if (valc && valMax > 0) {
16772 	    strncpy(valc, tn, valMax);
16773 	    valc[valMax - 1] = '\0';
16774 	    p = strchr(valc, '(');
16775 	    if (p) {
16776 		*p = '\0';
16777 		while (p > valc && ISSPACE(p[-1])) {
16778 		    --p;
16779 		    *p = '\0';
16780 		}
16781 	    }
16782 	    *valLen = strlen(valc);
16783 	} else {
16784 	    *valLen = strlen(tn);
16785 	    p = strchr(tn, '(');
16786 	    if (p) {
16787 		*valLen = p - tn;
16788 		while (p > tn && ISSPACE(p[-1])) {
16789 		    --p;
16790 		    *valLen -= 1;
16791 		}
16792 	    }
16793 	}
16794 	goto checkLen;
16795     }
16796     case SQL_COLUMN_OWNER_NAME:
16797     case SQL_COLUMN_QUALIFIER_NAME: {
16798 	char *z = "";
16799 
16800 	if (valc && valMax > 0) {
16801 	    strncpy(valc, z, valMax);
16802 	    valc[valMax - 1] = '\0';
16803 	}
16804 	*valLen = strlen(z);
16805 	goto checkLen;
16806     }
16807     case SQL_COLUMN_TABLE_NAME:
16808 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
16809     case SQL_DESC_TABLE_NAME:
16810 #endif
16811 #ifdef SQL_DESC_BASE_TABLE_NAME
16812     case SQL_DESC_BASE_TABLE_NAME:
16813 #endif
16814 	if (valc && valMax > 0) {
16815 	    strncpy(valc, c->table, valMax);
16816 	    valc[valMax - 1] = '\0';
16817 	}
16818 	*valLen = strlen(c->table);
16819 	goto checkLen;
16820 #ifdef SQL_DESC_NUM_PREC_RADIX
16821     case SQL_DESC_NUM_PREC_RADIX:
16822 	if (val2) {
16823 	    switch (c->type) {
16824 #ifdef WINTERFACE
16825 	    case SQL_WCHAR:
16826 	    case SQL_WVARCHAR:
16827 #ifdef SQL_LONGVARCHAR
16828 	    case SQL_WLONGVARCHAR:
16829 #endif
16830 #endif
16831 	    case SQL_CHAR:
16832 	    case SQL_VARCHAR:
16833 #ifdef SQL_LONGVARCHAR
16834 	    case SQL_LONGVARCHAR:
16835 #endif
16836 	    case SQL_BINARY:
16837 	    case SQL_VARBINARY:
16838 	    case SQL_LONGVARBINARY:
16839 		*val2 = 0;
16840 		break;
16841 	    default:
16842 		*val2 = 2;
16843 	    }
16844 	}
16845 	*valLen = sizeof (int);
16846 	return SQL_SUCCESS;
16847 #endif
16848     }
16849     setstat(s, -1, "unsupported column attributes %d", "HY091", id);
16850     return SQL_ERROR;
16851 }
16852 
16853 #ifndef WINTERFACE
16854 /**
16855  * Retrieve column attributes.
16856  * @param stmt statement handle
16857  * @param col column number, starting at 1
16858  * @param id attribute id
16859  * @param val output buffer
16860  * @param valMax length of output buffer
16861  * @param valLen output length
16862  * @param val2 integer output buffer
16863  * @result ODBC error code
16864  */
16865 
16866 SQLRETURN SQL_API
SQLColAttributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)16867 SQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
16868 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
16869 		 SQLLEN *val2)
16870 {
16871 #if defined(_WIN32) || defined(_WIN64)
16872     SQLSMALLINT len = 0;
16873 #endif
16874     SQLRETURN ret;
16875 
16876     HSTMT_LOCK(stmt);
16877 #if defined(_WIN32) || defined(_WIN64)
16878     if (!((STMT *) stmt)->oemcp[0]) {
16879 	ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
16880 	goto done;
16881     }
16882     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
16883     if (SQL_SUCCEEDED(ret)) {
16884 	char *v = NULL;
16885 
16886 	switch (id) {
16887 	case SQL_COLUMN_LABEL:
16888 	case SQL_COLUMN_NAME:
16889 	case SQL_DESC_NAME:
16890 	case SQL_COLUMN_TYPE_NAME:
16891 	case SQL_COLUMN_OWNER_NAME:
16892 	case SQL_COLUMN_QUALIFIER_NAME:
16893 	case SQL_COLUMN_TABLE_NAME:
16894 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
16895 	case SQL_DESC_TABLE_NAME:
16896 #endif
16897 #ifdef SQL_DESC_BASE_COLUMN_NAME
16898 	case SQL_DESC_BASE_COLUMN_NAME:
16899 #endif
16900 #ifdef SQL_DESC_BASE_TABLE_NAME
16901     case SQL_DESC_BASE_TABLE_NAME:
16902 #endif
16903 	    if (val && valMax > 0) {
16904 		int vmax = valMax;
16905 
16906 		v = utf_to_wmb((char *) val, SQL_NTS);
16907 		if (v) {
16908 		    strncpy(val, v, vmax);
16909 		    len = min(vmax, strlen(v));
16910 		    uc_free(v);
16911 		}
16912 		if (vmax > 0) {
16913 		    v = (char *) val;
16914 		    v[vmax - 1] = '\0';
16915 		}
16916 	    }
16917 	    if (len <= 0) {
16918 		len = 0;
16919 	    }
16920 	    break;
16921 	}
16922 	if (valLen) {
16923 	    *valLen = len;
16924 	}
16925     }
16926 done:
16927     ;
16928 #else
16929     ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
16930 #endif
16931     HSTMT_UNLOCK(stmt);
16932     return ret;
16933 }
16934 #endif
16935 
16936 #ifdef WINTERFACE
16937 /**
16938  * Retrieve column attributes (UNICODE version).
16939  * @param stmt statement handle
16940  * @param col column number, starting at 1
16941  * @param id attribute id
16942  * @param val output buffer
16943  * @param valMax length of output buffer
16944  * @param valLen output length
16945  * @param val2 integer output buffer
16946  * @result ODBC error code
16947  */
16948 
16949 SQLRETURN SQL_API
SQLColAttributesW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)16950 SQLColAttributesW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
16951 		  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
16952 		  SQLLEN *val2)
16953 {
16954     SQLRETURN ret;
16955     SQLSMALLINT len = 0;
16956 
16957     HSTMT_LOCK(stmt);
16958     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
16959     if (SQL_SUCCEEDED(ret)) {
16960 	SQLWCHAR *v = NULL;
16961 
16962 	switch (id) {
16963 	case SQL_COLUMN_LABEL:
16964 	case SQL_COLUMN_NAME:
16965 	case SQL_DESC_NAME:
16966 	case SQL_COLUMN_TYPE_NAME:
16967 	case SQL_COLUMN_OWNER_NAME:
16968 	case SQL_COLUMN_QUALIFIER_NAME:
16969 	case SQL_COLUMN_TABLE_NAME:
16970 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
16971 	case SQL_DESC_TABLE_NAME:
16972 #endif
16973 #ifdef SQL_DESC_BASE_COLUMN_NAME
16974 	case SQL_DESC_BASE_COLUMN_NAME:
16975 #endif
16976 #ifdef SQL_DESC_BASE_TABLE_NAME
16977     case SQL_DESC_BASE_TABLE_NAME:
16978 #endif
16979 	    if (val && valMax > 0) {
16980 		int vmax = valMax / sizeof (SQLWCHAR);
16981 
16982 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
16983 		if (v) {
16984 		    uc_strncpy(val, v, vmax);
16985 		    len = min(vmax, uc_strlen(v));
16986 		    uc_free(v);
16987 		    len *= sizeof (SQLWCHAR);
16988 		}
16989 		if (vmax > 0) {
16990 		    v = (SQLWCHAR *) val;
16991 		    v[vmax - 1] = '\0';
16992 		}
16993 	    }
16994 	    if (len <= 0) {
16995 		len = 0;
16996 	    }
16997 	    break;
16998 	}
16999 	if (valLen) {
17000 	    *valLen = len;
17001 	}
17002     }
17003     HSTMT_UNLOCK(stmt);
17004     return ret;
17005 }
17006 #endif
17007 
17008 /**
17009  * Internal retrieve column attributes.
17010  * @param stmt statement handle
17011  * @param col column number, starting at 1
17012  * @param id attribute id
17013  * @param val output buffer
17014  * @param valMax length of output buffer
17015  * @param valLen output length
17016  * @param val2 integer output buffer
17017  * @result ODBC error code
17018  */
17019 
17020 static SQLRETURN
drvcolattribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLPOINTER val2)17021 drvcolattribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17022 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17023 		SQLPOINTER val2)
17024 {
17025     STMT *s;
17026     COL *c;
17027     int v = 0;
17028     char *valc = (char *) val;
17029     SQLSMALLINT dummy;
17030 
17031     if (stmt == SQL_NULL_HSTMT) {
17032 	return SQL_INVALID_HANDLE;
17033     }
17034     s = (STMT *) stmt;
17035     if (!s->cols) {
17036 	return SQL_ERROR;
17037     }
17038     if (col < 1 || col > s->ncols) {
17039 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
17040 	return SQL_ERROR;
17041     }
17042     if (!valLen) {
17043 	valLen = &dummy;
17044     }
17045     c = s->cols + col - 1;
17046     switch (id) {
17047     case SQL_DESC_COUNT:
17048 	v = s->ncols;
17049 	break;
17050     case SQL_DESC_CATALOG_NAME:
17051 	if (valc && valMax > 0) {
17052 	    strncpy(valc, c->db, valMax);
17053 	    valc[valMax - 1] = '\0';
17054 	}
17055 	*valLen = strlen(c->db);
17056 checkLen:
17057 	if (*valLen >= valMax) {
17058 	    setstat(s, -1, "data right truncated", "01004");
17059 	    return SQL_SUCCESS_WITH_INFO;
17060 	}
17061 	break;
17062     case SQL_COLUMN_LENGTH:
17063     case SQL_DESC_LENGTH:
17064 	v = c->size;
17065 	break;
17066     case SQL_COLUMN_LABEL:
17067 	if (c->label) {
17068 	    if (valc && valMax > 0) {
17069 		strncpy(valc, c->label, valMax);
17070 		valc[valMax - 1] = '\0';
17071 	    }
17072 	    *valLen = strlen(c->label);
17073 	    goto checkLen;
17074 	}
17075 	/* fall through */
17076     case SQL_COLUMN_NAME:
17077     case SQL_DESC_NAME:
17078 	if (valc && valMax > 0) {
17079 	    strncpy(valc, c->column, valMax);
17080 	    valc[valMax - 1] = '\0';
17081 	}
17082 	*valLen = strlen(c->column);
17083 	goto checkLen;
17084     case SQL_DESC_SCHEMA_NAME: {
17085 	char *z = "";
17086 
17087 	if (valc && valMax > 0) {
17088 	    strncpy(valc, z, valMax);
17089 	    valc[valMax - 1] = '\0';
17090 	}
17091 	*valLen = strlen(z);
17092 	goto checkLen;
17093     }
17094 #ifdef SQL_DESC_BASE_COLUMN_NAME
17095     case SQL_DESC_BASE_COLUMN_NAME:
17096 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
17097 	    valc[0] = '\0';
17098 	    *valLen = 0;
17099 	} else if (valc && valMax > 0) {
17100 	    strncpy(valc, c->column, valMax);
17101 	    valc[valMax - 1] = '\0';
17102 	    *valLen = strlen(c->column);
17103 	}
17104 	goto checkLen;
17105 #endif
17106     case SQL_DESC_TYPE_NAME: {
17107 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
17108 
17109 #ifdef WINTERFACE
17110 	if (c->type == SQL_WCHAR ||
17111 	    c->type == SQL_WVARCHAR ||
17112 	    c->type == SQL_WLONGVARCHAR) {
17113 	    if (!(s->nowchar[0] || s->nowchar[1])) {
17114 		if (strcasecmp(tn, "varchar") == 0) {
17115 		    tn = "wvarchar";
17116 		}
17117 	    }
17118 	}
17119 #endif
17120 	if (valc && valMax > 0) {
17121 	    strncpy(valc, tn, valMax);
17122 	    valc[valMax - 1] = '\0';
17123 	    p = strchr(valc, '(');
17124 	    if (p) {
17125 		*p = '\0';
17126 		while (p > valc && ISSPACE(p[-1])) {
17127 		    --p;
17128 		    *p = '\0';
17129 		}
17130 	    }
17131 	    *valLen = strlen(valc);
17132 	} else {
17133 	    *valLen = strlen(tn);
17134 	    p = strchr(tn, '(');
17135 	    if (p) {
17136 		*valLen = p - tn;
17137 		while (p > tn && ISSPACE(p[-1])) {
17138 		    --p;
17139 		    *valLen -= 1;
17140 		}
17141 	    }
17142 	}
17143 	goto checkLen;
17144     }
17145     case SQL_DESC_OCTET_LENGTH:
17146 	v = c->size;
17147 #ifdef WINTERFACE
17148 	if (c->type == SQL_WCHAR ||
17149 	    c->type == SQL_WVARCHAR ||
17150 	    c->type == SQL_WLONGVARCHAR) {
17151 	    if (!(s->nowchar[0] || s->nowchar[1])) {
17152 		v *= sizeof (SQLWCHAR);
17153 	    }
17154 	}
17155 #endif
17156 	break;
17157 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
17158     case SQL_COLUMN_TABLE_NAME:
17159 #endif
17160 #ifdef SQL_DESC_BASE_TABLE_NAME
17161     case SQL_DESC_BASE_TABLE_NAME:
17162 #endif
17163     case SQL_DESC_TABLE_NAME:
17164 	if (valc && valMax > 0) {
17165 	    strncpy(valc, c->table, valMax);
17166 	    valc[valMax - 1] = '\0';
17167 	}
17168 	*valLen = strlen(c->table);
17169 	goto checkLen;
17170     case SQL_DESC_TYPE:
17171 	v = c->type;
17172 #ifdef WINTERFACE
17173 	if (s->nowchar[0] || s->nowchar[1]) {
17174 	    switch (v) {
17175 	    case SQL_WCHAR:
17176 		v = SQL_CHAR;
17177 		break;
17178 	    case SQL_WVARCHAR:
17179 		v = SQL_VARCHAR;
17180 		break;
17181 #ifdef SQL_LONGVARCHAR
17182 	    case SQL_WLONGVARCHAR:
17183 		v = SQL_LONGVARCHAR;
17184 		break;
17185 #endif
17186 	    }
17187 	}
17188 #endif
17189 	break;
17190     case SQL_DESC_CONCISE_TYPE:
17191 	switch (c->type) {
17192 	case SQL_INTEGER:
17193 	    v = SQL_C_LONG;
17194 	    break;
17195 	case SQL_TINYINT:
17196 	    v = SQL_C_TINYINT;
17197 	    break;
17198 	case SQL_SMALLINT:
17199 	    v = SQL_C_SHORT;
17200 	    break;
17201 	case SQL_FLOAT:
17202 	    v = SQL_C_FLOAT;
17203 	    break;
17204 	case SQL_DOUBLE:
17205 	    v = SQL_C_DOUBLE;
17206 	    break;
17207 	case SQL_TIMESTAMP:
17208 	    v = SQL_C_TIMESTAMP;
17209 	    break;
17210 	case SQL_TIME:
17211 	    v = SQL_C_TIME;
17212 	    break;
17213 	case SQL_DATE:
17214 	    v = SQL_C_DATE;
17215 	    break;
17216 #ifdef SQL_C_TYPE_TIMESTAMP
17217 	case SQL_TYPE_TIMESTAMP:
17218 	    v = SQL_C_TYPE_TIMESTAMP;
17219 	    break;
17220 #endif
17221 #ifdef SQL_C_TYPE_TIME
17222 	case SQL_TYPE_TIME:
17223 	    v = SQL_C_TYPE_TIME;
17224 	    break;
17225 #endif
17226 #ifdef SQL_C_TYPE_DATE
17227 	case SQL_TYPE_DATE:
17228 	    v = SQL_C_TYPE_DATE;
17229 	    break;
17230 #endif
17231 #ifdef SQL_BIT
17232 	case SQL_BIT:
17233 	    v = SQL_C_BIT;
17234 	    break;
17235 #endif
17236 #ifdef SQL_BIGINT
17237 	case SQL_BIGINT:
17238 	    v = SQL_C_SBIGINT;
17239 	    break;
17240 #endif
17241 	default:
17242 #ifdef WINTERFACE
17243 	    v = (s->nowchar[0] || s->nowchar[1]) ? SQL_C_CHAR : SQL_C_WCHAR;
17244 #else
17245 	    v = SQL_C_CHAR;
17246 #endif
17247 	    break;
17248 	}
17249 	break;
17250     case SQL_DESC_UPDATABLE:
17251 	v = SQL_TRUE;
17252 	break;
17253     case SQL_COLUMN_DISPLAY_SIZE:
17254 	v = c->size;
17255 	break;
17256     case SQL_COLUMN_UNSIGNED:
17257 	v = c->nosign ? SQL_TRUE : SQL_FALSE;
17258 	break;
17259     case SQL_COLUMN_SEARCHABLE:
17260 	v = SQL_SEARCHABLE;
17261 	break;
17262     case SQL_COLUMN_SCALE:
17263     case SQL_DESC_SCALE:
17264 	v = c->scale;
17265 	break;
17266     case SQL_COLUMN_PRECISION:
17267     case SQL_DESC_PRECISION:
17268 	switch (c->type) {
17269 	case SQL_SMALLINT:
17270 	    v = 5;
17271 	    break;
17272 	case SQL_INTEGER:
17273 	    v = 10;
17274 	    break;
17275 	case SQL_FLOAT:
17276 	case SQL_REAL:
17277 	case SQL_DOUBLE:
17278 	    v = 15;
17279 	    break;
17280 	case SQL_DATE:
17281 	    v = 0;
17282 	    break;
17283 	case SQL_TIME:
17284 	    v = 0;
17285 	    break;
17286 #ifdef SQL_TYPE_TIMESTAMP
17287 	case SQL_TYPE_TIMESTAMP:
17288 #endif
17289 	case SQL_TIMESTAMP:
17290 	    v = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
17291 	    break;
17292 	default:
17293 	    v = c->prec;
17294 	    break;
17295 	}
17296 	break;
17297     case SQL_COLUMN_MONEY:
17298 	v = SQL_FALSE;
17299 	break;
17300     case SQL_COLUMN_AUTO_INCREMENT:
17301 	v = c->autoinc;
17302 	break;
17303     case SQL_DESC_NULLABLE:
17304 	v = c->notnull;
17305 	break;
17306 #ifdef SQL_DESC_NUM_PREC_RADIX
17307     case SQL_DESC_NUM_PREC_RADIX:
17308 	switch (c->type) {
17309 #ifdef WINTERFACE
17310 	case SQL_WCHAR:
17311 	case SQL_WVARCHAR:
17312 #ifdef SQL_LONGVARCHAR
17313 	case SQL_WLONGVARCHAR:
17314 #endif
17315 #endif
17316 	case SQL_CHAR:
17317 	case SQL_VARCHAR:
17318 #ifdef SQL_LONGVARCHAR
17319 	case SQL_LONGVARCHAR:
17320 #endif
17321 	case SQL_BINARY:
17322 	case SQL_VARBINARY:
17323 	case SQL_LONGVARBINARY:
17324 	    v = 0;
17325 	    break;
17326 	default:
17327 	    v = 2;
17328 	}
17329 	break;
17330 #endif
17331     default:
17332 	setstat(s, -1, "unsupported column attribute %d", "HY091", id);
17333 	return SQL_ERROR;
17334     }
17335     if (val2) {
17336 	*(SQLLEN *) val2 = v;
17337     }
17338     return SQL_SUCCESS;
17339 }
17340 
17341 #ifndef WINTERFACE
17342 /**
17343  * Retrieve column attributes.
17344  * @param stmt statement handle
17345  * @param col column number, starting at 1
17346  * @param id attribute id
17347  * @param val output buffer
17348  * @param valMax length of output buffer
17349  * @param valLen output length
17350  * @param val2 integer output buffer
17351  * @result ODBC error code
17352  */
17353 
17354 SQLRETURN SQL_API
SQLColAttribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)17355 SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17356 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17357 		COLATTRIBUTE_LAST_ARG_TYPE val2)
17358 {
17359 #if defined(_WIN32) || defined(_WIN64)
17360     SQLSMALLINT len = 0;
17361 #endif
17362     SQLRETURN ret;
17363 
17364     HSTMT_LOCK(stmt);
17365 #if defined(_WIN32) || defined(_WIN64)
17366     if (!((STMT *) stmt)->oemcp[0]) {
17367 	ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
17368 			      (SQLPOINTER) val2);
17369 	goto done;
17370     }
17371     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
17372 			  (SQLPOINTER) val2);
17373     if (SQL_SUCCEEDED(ret)) {
17374 	char *v = NULL;
17375 
17376 	switch (id) {
17377 	case SQL_DESC_SCHEMA_NAME:
17378 	case SQL_DESC_CATALOG_NAME:
17379 	case SQL_COLUMN_LABEL:
17380 	case SQL_DESC_NAME:
17381 	case SQL_DESC_TABLE_NAME:
17382 #ifdef SQL_DESC_BASE_TABLE_NAME
17383 	case SQL_DESC_BASE_TABLE_NAME:
17384 #endif
17385 #ifdef SQL_DESC_BASE_COLUMN_NAME
17386 	case SQL_DESC_BASE_COLUMN_NAME:
17387 #endif
17388 	case SQL_DESC_TYPE_NAME:
17389 	    if (val && valMax > 0) {
17390 		int vmax = valMax;
17391 
17392 		v = utf_to_wmb((char *) val, SQL_NTS);
17393 		if (v) {
17394 		    strncpy(val, v, vmax);
17395 		    len = min(vmax, strlen(v));
17396 		    uc_free(v);
17397 		}
17398 		if (vmax > 0) {
17399 		    v = (char *) val;
17400 		    v[vmax - 1] = '\0';
17401 		}
17402 	    }
17403 	    if (len <= 0) {
17404 		len = 0;
17405 	    }
17406 	    break;
17407 	}
17408 	if (valLen) {
17409 	    *valLen = len;
17410 	}
17411     }
17412 done:
17413     ;
17414 #else
17415     ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
17416 			  (SQLPOINTER) val2);
17417 #endif
17418     HSTMT_UNLOCK(stmt);
17419     return ret;
17420 }
17421 #endif
17422 
17423 #ifdef WINTERFACE
17424 /**
17425  * Retrieve column attributes (UNICODE version).
17426  * @param stmt statement handle
17427  * @param col column number, starting at 1
17428  * @param id attribute id
17429  * @param val output buffer
17430  * @param valMax length of output buffer
17431  * @param valLen output length
17432  * @param val2 integer output buffer
17433  * @result ODBC error code
17434  */
17435 
17436 SQLRETURN SQL_API
SQLColAttributeW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)17437 SQLColAttributeW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
17438 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
17439 		 COLATTRIBUTE_LAST_ARG_TYPE val2)
17440 {
17441     SQLRETURN ret;
17442     SQLSMALLINT len = 0;
17443 
17444     HSTMT_LOCK(stmt);
17445     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
17446 			  (SQLPOINTER) val2);
17447     if (SQL_SUCCEEDED(ret)) {
17448 	SQLWCHAR *v = NULL;
17449 
17450 	switch (id) {
17451 	case SQL_DESC_SCHEMA_NAME:
17452 	case SQL_DESC_CATALOG_NAME:
17453 	case SQL_COLUMN_LABEL:
17454 	case SQL_DESC_NAME:
17455 	case SQL_DESC_TABLE_NAME:
17456 #ifdef SQL_DESC_BASE_TABLE_NAME
17457 	case SQL_DESC_BASE_TABLE_NAME:
17458 #endif
17459 #ifdef SQL_DESC_BASE_COLUMN_NAME
17460 	case SQL_DESC_BASE_COLUMN_NAME:
17461 #endif
17462 	case SQL_DESC_TYPE_NAME:
17463 	    if (val && valMax > 0) {
17464 		int vmax = valMax / sizeof (SQLWCHAR);
17465 
17466 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
17467 		if (v) {
17468 		    uc_strncpy(val, v, vmax);
17469 		    len = min(vmax, uc_strlen(v));
17470 		    uc_free(v);
17471 		    len *= sizeof (SQLWCHAR);
17472 		}
17473 		if (vmax > 0) {
17474 		    v = (SQLWCHAR *) val;
17475 		    v[vmax - 1] = '\0';
17476 		}
17477 	    }
17478 	    if (len <= 0) {
17479 		len = 0;
17480 	    }
17481 	    break;
17482 	}
17483 	if (valLen) {
17484 	    *valLen = len;
17485 	}
17486     }
17487     HSTMT_UNLOCK(stmt);
17488     return ret;
17489 }
17490 #endif
17491 
17492 /**
17493  * Internal return last HDBC or HSTMT error message.
17494  * @param env environment handle or NULL
17495  * @param dbc database connection handle or NULL
17496  * @param stmt statement handle or NULL
17497  * @param sqlState output buffer for SQL state
17498  * @param nativeErr output buffer for native error code
17499  * @param errmsg output buffer for error message
17500  * @param errmax length of output buffer for error message
17501  * @param errlen output length of error message
17502  * @result ODBC error code
17503  */
17504 
17505 static SQLRETURN
drverror(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)17506 drverror(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
17507 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
17508 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
17509 {
17510     SQLCHAR dummy0[6];
17511     SQLINTEGER dummy1;
17512     SQLSMALLINT dummy2;
17513 
17514     if (env == SQL_NULL_HENV &&
17515 	dbc == SQL_NULL_HDBC &&
17516 	stmt == SQL_NULL_HSTMT) {
17517 	return SQL_INVALID_HANDLE;
17518     }
17519     if (sqlState) {
17520 	sqlState[0] = '\0';
17521     } else {
17522 	sqlState = dummy0;
17523     }
17524     if (!nativeErr) {
17525 	nativeErr = &dummy1;
17526     }
17527     *nativeErr = 0;
17528     if (!errlen) {
17529 	errlen = &dummy2;
17530     }
17531     *errlen = 0;
17532     if (errmsg) {
17533 	if (errmax > 0) {
17534 	    errmsg[0] = '\0';
17535 	}
17536     } else {
17537 	errmsg = dummy0;
17538 	errmax = 0;
17539     }
17540     if (stmt) {
17541 	STMT *s = (STMT *) stmt;
17542 
17543 	HSTMT_LOCK(stmt);
17544 	if (s->logmsg[0] == '\0') {
17545 	    HSTMT_UNLOCK(stmt);
17546 	    goto noerr;
17547 	}
17548 	*nativeErr = s->naterr;
17549 	strcpy((char *) sqlState, s->sqlstate);
17550 	if (errmax == SQL_NTS) {
17551 	    strcpy((char *) errmsg, "[SQLite]");
17552 	    strcat((char *) errmsg, (char *) s->logmsg);
17553 	    *errlen = strlen((char *) errmsg);
17554 	} else {
17555 	    strncpy((char *) errmsg, "[SQLite]", errmax);
17556 	    if (errmax - 8 > 0) {
17557 		strncpy((char *) errmsg + 8, (char *) s->logmsg, errmax - 8);
17558 	    }
17559 	    *errlen = min(strlen((char *) s->logmsg) + 8, errmax);
17560 	}
17561 	s->logmsg[0] = '\0';
17562 	HSTMT_UNLOCK(stmt);
17563 	return SQL_SUCCESS;
17564     }
17565     if (dbc) {
17566 	DBC *d = (DBC *) dbc;
17567 
17568 	HDBC_LOCK(dbc);
17569 	if (d->magic != DBC_MAGIC || d->logmsg[0] == '\0') {
17570 	    HDBC_UNLOCK(dbc);
17571 	    goto noerr;
17572 	}
17573 	*nativeErr = d->naterr;
17574 	strcpy((char *) sqlState, d->sqlstate);
17575 	if (errmax == SQL_NTS) {
17576 	    strcpy((char *) errmsg, "[SQLite]");
17577 	    strcat((char *) errmsg, (char *) d->logmsg);
17578 	    *errlen = strlen((char *) errmsg);
17579 	} else {
17580 	    strncpy((char *) errmsg, "[SQLite]", errmax);
17581 	    if (errmax - 8 > 0) {
17582 		strncpy((char *) errmsg + 8, (char *) d->logmsg, errmax - 8);
17583 	    }
17584 	    *errlen = min(strlen((char *) d->logmsg) + 8, errmax);
17585 	}
17586 	d->logmsg[0] = '\0';
17587 	HDBC_UNLOCK(dbc);
17588 	return SQL_SUCCESS;
17589     }
17590 noerr:
17591     sqlState[0] = '\0';
17592     errmsg[0] = '\0';
17593     *nativeErr = 0;
17594     *errlen = 0;
17595     return SQL_NO_DATA;
17596 }
17597 
17598 #ifndef WINTERFACE
17599 /**
17600  * Return last HDBC or HSTMT error message.
17601  * @param env environment handle or NULL
17602  * @param dbc database connection handle or NULL
17603  * @param stmt statement handle or NULL
17604  * @param sqlState output buffer for SQL state
17605  * @param nativeErr output buffer for native error code
17606  * @param errmsg output buffer for error message
17607  * @param errmax length of output buffer for error message
17608  * @param errlen output length of error message
17609  * @result ODBC error code
17610  */
17611 
17612 SQLRETURN SQL_API
SQLError(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)17613 SQLError(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
17614 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
17615 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
17616 {
17617     return drverror(env, dbc, stmt, sqlState, nativeErr,
17618 		    errmsg, errmax, errlen);
17619 }
17620 #endif
17621 
17622 #ifdef WINTERFACE
17623 /**
17624  * Return last HDBC or HSTMT error message (UNICODE version).
17625  * @param env environment handle or NULL
17626  * @param dbc database connection handle or NULL
17627  * @param stmt statement handle or NULL
17628  * @param sqlState output buffer for SQL state
17629  * @param nativeErr output buffer for native error code
17630  * @param errmsg output buffer for error message
17631  * @param errmax length of output buffer for error message
17632  * @param errlen output length of error message
17633  * @result ODBC error code
17634  */
17635 
17636 SQLRETURN SQL_API
SQLErrorW(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLWCHAR * sqlState,SQLINTEGER * nativeErr,SQLWCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)17637 SQLErrorW(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
17638 	  SQLWCHAR *sqlState, SQLINTEGER *nativeErr,
17639 	  SQLWCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
17640 {
17641     char state[16];
17642     SQLSMALLINT len = 0;
17643     SQLRETURN ret;
17644 
17645     ret = drverror(env, dbc, stmt, (SQLCHAR *) state, nativeErr,
17646 		   (SQLCHAR *) errmsg, errmax, &len);
17647     if (ret == SQL_SUCCESS) {
17648 	if (sqlState) {
17649 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlState,
17650 			    6 * sizeof (SQLWCHAR));
17651 	}
17652 	if (errmsg) {
17653 	    if (len > 0) {
17654 		SQLWCHAR *e = NULL;
17655 
17656 		e = uc_from_utf((SQLCHAR *) errmsg, len);
17657 		if (e) {
17658 		    if (errmax > 0) {
17659 			uc_strncpy(errmsg, e, errmax);
17660 			e[len] = 0;
17661 			len = min(errmax, uc_strlen(e));
17662 		    } else {
17663 			len = uc_strlen(e);
17664 		    }
17665 		    uc_free(e);
17666 		} else {
17667 		    len = 0;
17668 		}
17669 	    }
17670 	    if (len <= 0) {
17671 		len = 0;
17672 		if (errmax > 0) {
17673 		    errmsg[0] = 0;
17674 		}
17675 	    }
17676 	} else {
17677 	    len = 0;
17678 	}
17679 	if (errlen) {
17680 	    *errlen = len;
17681 	}
17682     } else if (ret == SQL_NO_DATA) {
17683 	if (sqlState) {
17684 	    sqlState[0] = 0;
17685 	}
17686 	if (errmsg) {
17687 	    if (errmax > 0) {
17688 		errmsg[0] = 0;
17689 	    }
17690 	}
17691 	if (errlen) {
17692 	    *errlen = 0;
17693 	}
17694     }
17695     return ret;
17696 }
17697 #endif
17698 
17699 /**
17700  * Return information for more result sets.
17701  * @param stmt statement handle
17702  * @result ODBC error code
17703  */
17704 
17705 SQLRETURN SQL_API
SQLMoreResults(SQLHSTMT stmt)17706 SQLMoreResults(SQLHSTMT stmt)
17707 {
17708     HSTMT_LOCK(stmt);
17709     if (stmt == SQL_NULL_HSTMT) {
17710 	return SQL_INVALID_HANDLE;
17711     }
17712     HSTMT_UNLOCK(stmt);
17713     return SQL_NO_DATA;
17714 }
17715 
17716 /**
17717  * Internal function to setup column name/type information
17718  * @param s statement poiner
17719  * @param s4stmt sqlite4 statement pointer
17720  * @param ncolsp pointer to preinitialized number of columns
17721  * @result ODBC error code
17722  */
17723 
17724 static SQLRETURN
setupdyncols(STMT * s,sqlite4_stmt * s4stmt,int * ncolsp)17725 setupdyncols(STMT *s, sqlite4_stmt *s4stmt, int *ncolsp)
17726 {
17727     int ncols = *ncolsp, guessed_types = 0;
17728     SQLRETURN ret = SQL_SUCCESS;
17729 
17730     if (ncols > 0) {
17731 	int i;
17732 	PTRDIFF_T size;
17733 	char *p;
17734 	COL *dyncols;
17735 	DBC *d = (DBC *) s->dbc;
17736 	const char *colname, *typename;
17737 	char *tblname, *dbname;
17738 
17739 	for (i = size = 0; i < ncols; i++) {
17740 	    colname = sqlite4_column_name(s4stmt, i);
17741 	    size += 3 + 3 * strlen(colname);
17742 	}
17743 	tblname = (char *) size;
17744 	for (i = 0; i < ncols; i++) {
17745 	    p = (char *) sqlite4_column_table_name(s4stmt, i);
17746 	    size += 2 + (p ? strlen(p) : 0);
17747 	}
17748 	dbname = (char *) size;
17749 	for (i = 0; i < ncols; i++) {
17750 	    p = (char *) sqlite4_column_database_name(s4stmt, i);
17751 	    size += 2 + (p ? strlen(p) : 0);
17752 	}
17753 	dyncols = xmalloc(ncols * sizeof (COL) + size);
17754 	if (!dyncols) {
17755 	    freedyncols(s);
17756 	    *ncolsp = 0;
17757 	    ret = SQL_ERROR;
17758 	} else {
17759 	    p = (char *) (dyncols + ncols);
17760 	    tblname = p + (PTRDIFF_T) tblname;
17761 	    dbname = p + (PTRDIFF_T) dbname;
17762 	    for (i = 0; i < ncols; i++) {
17763 		char *q;
17764 
17765 		colname = sqlite4_column_name(s4stmt, i);
17766 		if (d->trace) {
17767 		    fprintf(d->trace, "-- column %d name: '%s'\n",
17768 			    i + 1, colname);
17769 		    fflush(d->trace);
17770 		}
17771 		q = (char *) sqlite4_column_table_name(s4stmt, i);
17772 		strcpy(tblname, q ? q : "");
17773 		if (d->trace) {
17774 		    fprintf(d->trace, "-- table %d name: '%s'\n",
17775 			    i + 1, tblname);
17776 		    fflush(d->trace);
17777 		}
17778 		dyncols[i].table = tblname;
17779 		q = (char *) sqlite4_column_database_name(s4stmt, i);
17780 		strcpy(dbname, q ? q : "");
17781 		if (d->trace) {
17782 		    fprintf(d->trace, "-- database %d name: '%s'\n",
17783 			    i + 1, dbname);
17784 		    fflush(d->trace);
17785 		}
17786 		dyncols[i].db = dbname;
17787 		dbname += strlen(dbname) + 1;
17788 		typename = s4stmt_coltype(s4stmt, i, d, &guessed_types);
17789 		strcpy(p, colname);
17790 		dyncols[i].label = p;
17791 		p += strlen(p) + 1;
17792 		q = strchr(colname, '.');
17793 		if (q) {
17794 		    char *q2 = strchr(q + 1, '.');
17795 
17796 		    /* SQLite 3.3.4 produces view.table.column sometimes */
17797 		    if (q2) {
17798 			q = q2;
17799 		    }
17800 		}
17801 		if (q) {
17802 		    dyncols[i].table = p;
17803 		    strncpy(p, colname, q - colname);
17804 		    p[q - colname] = '\0';
17805 		    p += strlen(p) + 1;
17806 		    strcpy(p, q + 1);
17807 		    dyncols[i].column = p;
17808 		    p += strlen(p) + 1;
17809 		} else {
17810 		    strcpy(p, colname);
17811 		    dyncols[i].column = p;
17812 		    p += strlen(p) + 1;
17813 		}
17814 		if (s->longnames) {
17815 		    dyncols[i].column = dyncols[i].label;
17816 		}
17817 #ifdef SQL_LONGVARCHAR
17818 		dyncols[i].type = SQL_LONGVARCHAR;
17819 		dyncols[i].size = 65535;
17820 #else
17821 		dyncols[i].type = SQL_VARCHAR;
17822 		dyncols[i].size = 255;
17823 #endif
17824 		dyncols[i].index = i;
17825 		dyncols[i].scale = 0;
17826 		dyncols[i].prec = 0;
17827 		dyncols[i].nosign = 1;
17828 		s4stmt_addmeta(s4stmt, i, d, &dyncols[i]);
17829 		dyncols[i].typename = xstrdup(typename);
17830 	    }
17831 	    freedyncols(s);
17832 	    s->dyncols = s->cols = dyncols;
17833 	    s->dcols = ncols;
17834 	    fixupdyncols(s, d);
17835 	    s->guessed_types = guessed_types;
17836 	}
17837     }
17838     return ret;
17839 }
17840 
17841 /**
17842  * Internal query preparation used by SQLPrepare() and SQLExecDirect().
17843  * @param stmt statement handle
17844  * @param query query string
17845  * @param queryLen length of query string or SQL_NTS
17846  * @result ODBC error code
17847  */
17848 
17849 static SQLRETURN
drvprepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)17850 drvprepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
17851 {
17852     STMT *s;
17853     DBC *d;
17854     char *errp = NULL;
17855     SQLRETURN sret;
17856 
17857     if (stmt == SQL_NULL_HSTMT) {
17858 	return SQL_INVALID_HANDLE;
17859     }
17860     s = (STMT *) stmt;
17861     if (s->dbc == SQL_NULL_HDBC) {
17862 noconn:
17863 	return noconn(s);
17864     }
17865     d = s->dbc;
17866     if (!d->sqlite) {
17867 	goto noconn;
17868     }
17869     s4stmt_end(s);
17870     s4stmt_drop(s);
17871     sret = starttran(s);
17872     if (sret != SQL_SUCCESS) {
17873 	return sret;
17874     }
17875     freep(&s->query);
17876     s->query = (SQLCHAR *) fixupsql((char *) query, queryLen,
17877 				    &s->nparams, &s->isselect, &errp);
17878     if (!s->query) {
17879 	if (errp) {
17880 	    setstat(s, -1, "%s", (*s->ov3) ? "HY000" : "S1000", errp);
17881 	    return SQL_ERROR;
17882 	}
17883 	return nomem(s);
17884     }
17885     errp = NULL;
17886     freeresult(s, -1);
17887     if (s->isselect == 1) {
17888 	int ret, ncols, nretry = 0;
17889 	int sqlleft;
17890 	sqlite4_stmt *s4stmt = NULL;
17891 
17892 	dbtraceapi(d, "sqlite4_prepare", (char *) s->query);
17893 	do {
17894 	    s4stmt = NULL;
17895 	    ret = sqlite4_prepare(d->sqlite, (char *) s->query, -1,
17896 				  &s4stmt, &sqlleft);
17897 	    if (ret != SQLITE4_OK) {
17898 		if (s4stmt) {
17899 		    sqlite4_finalize(s4stmt);
17900 		    s4stmt = NULL;
17901 		}
17902 	    }
17903 	} while (ret == SQLITE4_SCHEMA && (++nretry) < 2);
17904 	dbtracerc(d, ret, NULL);
17905 	if (ret != SQLITE4_OK) {
17906 	    if (s4stmt) {
17907 		dbtraceapi(d, "sqlite4_finalize", 0);
17908 		sqlite4_finalize(s4stmt);
17909 	    }
17910 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
17911 		    sqlite4_errmsg(d->sqlite), ret);
17912 	    return SQL_ERROR;
17913 	}
17914 	if (sqlite4_bind_parameter_count(s4stmt) != s->nparams) {
17915 	    dbtraceapi(d, "sqlite4_finalize", 0);
17916 	    sqlite4_finalize(s4stmt);
17917 	    setstat(s, SQLITE4_ERROR, "parameter marker count incorrect",
17918 		    (*s->ov3) ? "HY000" : "S1000");
17919 	    return SQL_ERROR;
17920 	}
17921 	ncols = sqlite4_column_count(s4stmt);
17922 	s->guessed_types = 0;
17923 	setupdyncols(s, s4stmt, &ncols);
17924 	s->ncols = ncols;
17925 	s->s4stmt = s4stmt;
17926     }
17927     mkbindcols(s, s->ncols);
17928     s->paramset_count = 0;
17929     return SQL_SUCCESS;
17930 }
17931 
17932 /**
17933  * Internal query execution used by SQLExecute() and SQLExecDirect().
17934  * @param stmt statement handle
17935  * @param initial false when called from SQLPutData()
17936  * @result ODBC error code
17937  */
17938 
17939 static SQLRETURN
drvexecute(SQLHSTMT stmt,int initial)17940 drvexecute(SQLHSTMT stmt, int initial)
17941 {
17942     STMT *s;
17943     DBC *d;
17944     char *errp = NULL;
17945     int rc, i, ncols = 0, nrows = 0;
17946     SQLRETURN ret;
17947 
17948     if (stmt == SQL_NULL_HSTMT) {
17949 	return SQL_INVALID_HANDLE;
17950     }
17951     s = (STMT *) stmt;
17952     if (s->dbc == SQL_NULL_HDBC) {
17953 noconn:
17954 	return noconn(s);
17955     }
17956     d = (DBC *) s->dbc;
17957     if (!d->sqlite) {
17958 	goto noconn;
17959     }
17960     if (!s->query) {
17961 	setstat(s, -1, "no query prepared", (*s->ov3) ? "HY000" : "S1000");
17962 	return SQL_ERROR;
17963     }
17964     if (s->nbindparms < s->nparams) {
17965 unbound:
17966 	setstat(s, -1, "unbound parameters in query",
17967 		(*s->ov3) ? "HY000" : "S1000");
17968 	return SQL_ERROR;
17969     }
17970     for (i = 0; i < s->nparams; i++) {
17971 	BINDPARM *p = &s->bindparms[i];
17972 
17973 	if (!p->bound) {
17974 	    goto unbound;
17975 	}
17976 	if (initial) {
17977 	    SQLLEN *lenp = p->lenp;
17978 
17979 	    if (lenp && *lenp < 0 && *lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
17980 		*lenp != SQL_NTS && *lenp != SQL_NULL_DATA &&
17981 		*lenp != SQL_DATA_AT_EXEC) {
17982 		setstat(s, -1, "invalid length reference", "HY009");
17983 		return SQL_ERROR;
17984 	    }
17985 	    if (lenp && (*lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
17986 			 *lenp == SQL_DATA_AT_EXEC)) {
17987 		p->need = 1;
17988 		p->offs = 0;
17989 		p->len = 0;
17990 	    }
17991 	}
17992     }
17993     ret = starttran(s);
17994     if (ret != SQL_SUCCESS) {
17995 	goto cleanup;
17996     }
17997 again:
17998     s4stmt_end(s);
17999     if (initial) {
18000 	/* fixup data-at-execution parameters and alloc'ed blobs */
18001 	s->pdcount = -1;
18002 	for (i = 0; i < s->nparams; i++) {
18003 	    BINDPARM *p = &s->bindparms[i];
18004 
18005 	    if (p->param == p->parbuf) {
18006 		p->param = NULL;
18007 	    }
18008 	    freep(&p->parbuf);
18009 	    if (p->need <= 0 &&
18010 		p->lenp && (*p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
18011 			    *p->lenp == SQL_DATA_AT_EXEC)) {
18012 		p->need = 1;
18013 		p->offs = 0;
18014 		p->len = 0;
18015 	    }
18016 	}
18017     }
18018     if (s->nparams) {
18019 	for (i = 0; i < s->nparams; i++) {
18020 	    ret = setupparam(s, (char *) s->query, i);
18021 	    if (ret != SQL_SUCCESS) {
18022 		goto cleanup;
18023 	    }
18024 	}
18025     }
18026     freeresult(s, 0);
18027     if (s->isselect == 1 && !d->intrans &&
18028 	s->curtype == SQL_CURSOR_FORWARD_ONLY &&
18029 	d->step_enable && s->nparams == 0 && d->cur_s4stmt == NULL) {
18030 	s->nrows = -1;
18031 	ret = s4stmt_start(s);
18032 	if (ret == SQL_SUCCESS) {
18033 	    goto done2;
18034 	}
18035     }
18036     rc = drvgettable(s, s->s4stmt ? NULL : (char *) s->query, &s->rows,
18037 		     &s->nrows, &ncols, &errp, s->nparams, s->bindparms);
18038     dbtracerc(d, rc, errp);
18039     if (rc != SQLITE4_OK) {
18040 	setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
18041 		errp ? errp : "unknown error", rc);
18042 	if (errp) {
18043 	    sqlite4_free(0, errp);
18044 	    errp = NULL;
18045 	}
18046 	ret = SQL_ERROR;
18047 	goto cleanup;
18048     }
18049     if (errp) {
18050 	sqlite4_free(0, errp);
18051 	errp = NULL;
18052     }
18053     s->rowfree = freerows;
18054     if (s->isselect <= 0 || s->isselect > 1) {
18055 	/*
18056 	 * INSERT/UPDATE/DELETE or DDL results are immediately released.
18057 	 */
18058 	freeresult(s, -1);
18059 	nrows += sqlite4_changes(d->sqlite);
18060 	s->nrows = nrows;
18061 	goto done;
18062     }
18063     if (s->ncols != ncols) {
18064 	/*
18065 	 * Weird result.
18066 	 */
18067 	setstat(s, -1, "broken result set %d/%d",
18068 		(*s->ov3) ? "HY000" : "S1000", s->ncols, ncols);
18069 	ret = SQL_ERROR;
18070 	goto cleanup;
18071     }
18072 done:
18073     mkbindcols(s, s->ncols);
18074 done2:
18075     ret = SQL_SUCCESS;
18076     s->rowp = s->rowprs = -1;
18077     s->paramset_count++;
18078     s->paramset_nrows = s->nrows;
18079     if (s->paramset_count < s->paramset_size) {
18080 	for (i = 0; i < s->nparams; i++) {
18081 	    BINDPARM *p = &s->bindparms[i];
18082 
18083 	    if (p->param == p->parbuf) {
18084 		p->param = NULL;
18085 	    }
18086 	    freep(&p->parbuf);
18087 	    if (p->lenp0 &&
18088 		s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
18089 		p->lenp = (SQLLEN *) ((char *) p->lenp0 +
18090 				      s->paramset_count * s->parm_bind_type);
18091 	    } else if (p->lenp0 && p->inc > 0) {
18092 		p->lenp = p->lenp0 + s->paramset_count;
18093 	    }
18094 	    if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
18095 			     *p->lenp != SQL_DATA_AT_EXEC)) {
18096 		if (p->param0 &&
18097 		    s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
18098 		    p->param = (char *) p->param0 +
18099 			s->paramset_count * s->parm_bind_type;
18100 		} else if (p->param0 && p->inc > 0) {
18101 		    p->param = (char *) p->param0 +
18102 			s->paramset_count * p->inc;
18103 		}
18104 	    } else if (p->lenp && (*p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
18105 				   *p->lenp == SQL_DATA_AT_EXEC)) {
18106 		p->need = 1;
18107 		p->offs = 0;
18108 		p->len = 0;
18109 	    }
18110 	}
18111 	goto again;
18112     }
18113 cleanup:
18114     if (ret != SQL_NEED_DATA) {
18115 	for (i = 0; i < s->nparams; i++) {
18116 	    BINDPARM *p = &s->bindparms[i];
18117 
18118 	    if (p->param == p->parbuf) {
18119 		p->param = NULL;
18120 	    }
18121 	    freep(&p->parbuf);
18122 	    if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
18123 			     *p->lenp != SQL_DATA_AT_EXEC)) {
18124 		p->param = p->param0;
18125 	    }
18126 	    p->lenp = p->lenp0;
18127 	}
18128 	s->nrows = s->paramset_nrows;
18129 	if (s->parm_proc) {
18130 	    *s->parm_proc = s->paramset_count;
18131 	}
18132 	s->paramset_count = 0;
18133 	s->paramset_nrows = 0;
18134     }
18135     /*
18136      * For INSERT/UPDATE/DELETE statements change the return code
18137      * to SQL_NO_DATA if the number of rows affected was 0.
18138      */
18139     if (*s->ov3 && s->isselect == 0 &&
18140 	ret == SQL_SUCCESS && nrows == 0) {
18141 	ret = SQL_NO_DATA;
18142     }
18143     return ret;
18144 }
18145 
18146 #ifndef WINTERFACE
18147 /**
18148  * Prepare HSTMT.
18149  * @param stmt statement handle
18150  * @param query query string
18151  * @param queryLen length of query string or SQL_NTS
18152  * @result ODBC error code
18153  */
18154 
18155 SQLRETURN SQL_API
SQLPrepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)18156 SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
18157 {
18158     SQLRETURN ret;
18159 #if defined(_WIN32) || defined(_WIN64)
18160     char *q;
18161 #endif
18162 
18163     HSTMT_LOCK(stmt);
18164 #if defined(_WIN32) || defined(_WIN64)
18165     if (!((STMT *) stmt)->oemcp[0]) {
18166 	ret = drvprepare(stmt, query, queryLen);
18167 	goto done;
18168     }
18169     q = wmb_to_utf_c((char *) query, queryLen);
18170     if (!q) {
18171 	ret = nomem((STMT *) stmt);
18172 	goto done;
18173     }
18174     query = (SQLCHAR *) q;
18175     queryLen = SQL_NTS;
18176 #endif
18177     ret = drvprepare(stmt, query, queryLen);
18178 #if defined(_WIN32) || defined(_WIN64)
18179     uc_free(q);
18180 done:
18181     ;
18182 #endif
18183     HSTMT_UNLOCK(stmt);
18184     return ret;
18185 }
18186 #endif
18187 
18188 #ifdef WINTERFACE
18189 /**
18190  * Prepare HSTMT (UNICODE version).
18191  * @param stmt statement handle
18192  * @param query query string
18193  * @param queryLen length of query string or SQL_NTS
18194  * @result ODBC error code
18195  */
18196 
18197 SQLRETURN SQL_API
SQLPrepareW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)18198 SQLPrepareW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
18199 {
18200     SQLRETURN ret;
18201     char *q = uc_to_utf_c(query, queryLen);
18202 
18203     HSTMT_LOCK(stmt);
18204     if (!q) {
18205 	ret = nomem((STMT *) stmt);
18206 	goto done;
18207     }
18208     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
18209     uc_free(q);
18210 done:
18211     HSTMT_UNLOCK(stmt);
18212     return ret;
18213 }
18214 #endif
18215 
18216 /**
18217  * Execute query.
18218  * @param stmt statement handle
18219  * @result ODBC error code
18220  */
18221 
18222 SQLRETURN SQL_API
SQLExecute(SQLHSTMT stmt)18223 SQLExecute(SQLHSTMT stmt)
18224 {
18225     SQLRETURN ret;
18226 
18227     HSTMT_LOCK(stmt);
18228     ret = drvexecute(stmt, 1);
18229     HSTMT_UNLOCK(stmt);
18230     return ret;
18231 }
18232 
18233 #ifndef WINTERFACE
18234 /**
18235  * Execute query directly.
18236  * @param stmt statement handle
18237  * @param query query string
18238  * @param queryLen length of query string or SQL_NTS
18239  * @result ODBC error code
18240  */
18241 
18242 SQLRETURN SQL_API
SQLExecDirect(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)18243 SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
18244 {
18245     SQLRETURN ret;
18246 #if defined(_WIN32) || defined(_WIN64)
18247     char *q;
18248 #endif
18249 
18250     HSTMT_LOCK(stmt);
18251 #if defined(_WIN32) || defined(_WIN64)
18252     if (!((STMT *) stmt)->oemcp[0]) {
18253 	ret = drvprepare(stmt, query, queryLen);
18254 	if (ret == SQL_SUCCESS) {
18255 	    ret = drvexecute(stmt, 1);
18256 	}
18257 	goto done;
18258     }
18259     q = wmb_to_utf_c((char *) query, queryLen);
18260     if (!q) {
18261 	ret = nomem((STMT *) stmt);
18262 	goto done;
18263     }
18264     query = (SQLCHAR *) q;
18265     queryLen = SQL_NTS;
18266 #endif
18267     ret = drvprepare(stmt, query, queryLen);
18268     if (ret == SQL_SUCCESS) {
18269 	ret = drvexecute(stmt, 1);
18270     }
18271 #if defined(_WIN32) || defined(_WIN64)
18272     uc_free(q);
18273 done:
18274     ;
18275 #endif
18276     HSTMT_UNLOCK(stmt);
18277     return ret;
18278 }
18279 #endif
18280 
18281 #ifdef WINTERFACE
18282 /**
18283  * Execute query directly (UNICODE version).
18284  * @param stmt statement handle
18285  * @param query query string
18286  * @param queryLen length of query string or SQL_NTS
18287  * @result ODBC error code
18288  */
18289 
18290 SQLRETURN SQL_API
SQLExecDirectW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)18291 SQLExecDirectW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
18292 {
18293     SQLRETURN ret;
18294     char *q = uc_to_utf_c(query, queryLen);
18295 
18296     HSTMT_LOCK(stmt);
18297     if (!q) {
18298 	ret = nomem((STMT *) stmt);
18299 	goto done;
18300     }
18301     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
18302     uc_free(q);
18303     if (ret == SQL_SUCCESS) {
18304 	ret = drvexecute(stmt, 1);
18305     }
18306 done:
18307     HSTMT_UNLOCK(stmt);
18308     return ret;
18309 }
18310 #endif
18311 
18312 
18313 #if defined(_WIN32) || defined(_WIN64)
18314 #ifndef WITHOUT_DRIVERMGR
18315 
18316 /*
18317  * Windows configuration dialog stuff.
18318  */
18319 
18320 #include <windowsx.h>
18321 #include <winuser.h>
18322 
18323 #define MAXPATHLEN      (259+1)           /* Max path length */
18324 #define MAXKEYLEN       (15+1)            /* Max keyword length */
18325 #define MAXDESC         (255+1)           /* Max description length */
18326 #define MAXDSNAME       (255+1)           /* Max data source name length */
18327 #define MAXTONAME       (32+1)            /* Max timeout length */
18328 #define MAXDBNAME       MAXPATHLEN
18329 
18330 /* Attribute key indexes into an array of Attr structs, see below */
18331 
18332 #define KEY_DSN 		0
18333 #define KEY_DESC		1
18334 #define KEY_DBNAME		2
18335 #define KEY_BUSY		3
18336 #define KEY_DRIVER		4
18337 #define KEY_STEPAPI		5
18338 #define KEY_SYNCP		6
18339 #define KEY_NOTXN		7
18340 #define KEY_SHORTNAM		8
18341 #define KEY_LONGNAM		9
18342 #define KEY_NOCREAT	       10
18343 #define KEY_NOWCHAR	       11
18344 #define KEY_LOADEXT	       12
18345 #define KEY_JMODE              13
18346 #define KEY_FKSUPPORT          14
18347 #define KEY_OEMCP              15
18348 #define KEY_BIGINT             16
18349 #define KEY_PASSWD             17
18350 #define NUMOFKEYS	       18
18351 
18352 typedef struct {
18353     BOOL supplied;
18354     char attr[MAXPATHLEN*4];
18355 } ATTR;
18356 
18357 typedef struct {
18358     SQLHWND parent;
18359     LPCSTR  driver;
18360     ATTR    attr[NUMOFKEYS];
18361     char    DSN[MAXDSNAME];
18362     BOOL    newDSN;
18363     BOOL    defDSN;
18364 } SETUPDLG;
18365 
18366 static struct {
18367     char *key;
18368     int ikey;
18369 } attrLookup[] = {
18370     { "DSN", KEY_DSN },
18371     { "DESC", KEY_DESC },
18372     { "Description", KEY_DESC},
18373     { "Database", KEY_DBNAME },
18374     { "Timeout", KEY_BUSY },
18375     { "Driver", KEY_DRIVER },
18376     { "StepAPI", KEY_STEPAPI },
18377     { "SyncPragma", KEY_SYNCP },
18378     { "NoTXN", KEY_NOTXN },
18379     { "ShortNames", KEY_SHORTNAM },
18380     { "LongNames", KEY_LONGNAM },
18381     { "NoCreat", KEY_NOCREAT },
18382     { "NoWCHAR", KEY_NOWCHAR },
18383     { "LoadExt", KEY_LOADEXT },
18384     { "JournalMode", KEY_JMODE },
18385     { "FKSupport", KEY_FKSUPPORT },
18386     { "OEMCP", KEY_OEMCP },
18387     { "BigInt", KEY_BIGINT },
18388     { "PWD", KEY_PASSWD },
18389     { NULL, 0 }
18390 };
18391 
18392 /**
18393  * Setup dialog data from datasource attributes.
18394  * @param attribs attribute string
18395  * @param setupdlg pointer to dialog data
18396  */
18397 
18398 static void
ParseAttributes(LPCSTR attribs,SETUPDLG * setupdlg)18399 ParseAttributes(LPCSTR attribs, SETUPDLG *setupdlg)
18400 {
18401     char *str = (char *) attribs, *start, key[MAXKEYLEN];
18402     int elem, nkey;
18403 
18404     while (*str) {
18405 	start = str;
18406 	if ((str = strchr(str, '=')) == NULL) {
18407 	    return;
18408 	}
18409 	elem = -1;
18410 	nkey = str - start;
18411 	if (nkey < sizeof (key)) {
18412 	    int i;
18413 
18414 	    memcpy(key, start, nkey);
18415 	    key[nkey] = '\0';
18416 	    for (i = 0; attrLookup[i].key; i++) {
18417 		if (strcasecmp(attrLookup[i].key, key) == 0) {
18418 		    elem = attrLookup[i].ikey;
18419 		    break;
18420 		}
18421 	    }
18422 	}
18423 	start = ++str;
18424 	while (*str && *str != ';') {
18425 	    ++str;
18426 	}
18427 	if (elem >= 0) {
18428 	    int end = min(str - start, sizeof (setupdlg->attr[elem].attr) - 1);
18429 
18430 	    setupdlg->attr[elem].supplied = TRUE;
18431 	    memcpy(setupdlg->attr[elem].attr, start, end);
18432 	    setupdlg->attr[elem].attr[end] = '\0';
18433 	}
18434 	++str;
18435     }
18436 }
18437 
18438 /**
18439  * Set datasource attributes in registry.
18440  * @param parent handle of parent window
18441  * @param setupdlg pointer to dialog data
18442  * @result true or false
18443  */
18444 
18445 static BOOL
SetDSNAttributes(HWND parent,SETUPDLG * setupdlg)18446 SetDSNAttributes(HWND parent, SETUPDLG *setupdlg)
18447 {
18448     char *dsn = setupdlg->attr[KEY_DSN].attr;
18449 
18450     if (setupdlg->newDSN && strlen(dsn) == 0) {
18451 	return FALSE;
18452     }
18453     if (!SQLWriteDSNToIni(dsn, setupdlg->driver)) {
18454 	if (parent) {
18455 	    char buf[MAXPATHLEN], msg[MAXPATHLEN];
18456 
18457 	    LoadString(hModule, IDS_BADDSN, buf, sizeof (buf));
18458 	    wsprintf(msg, buf, dsn);
18459 	    LoadString(hModule, IDS_MSGTITLE, buf, sizeof (buf));
18460 	    MessageBox(parent, msg, buf,
18461 		       MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
18462 		       MB_SETFOREGROUND);
18463 	}
18464 	return FALSE;
18465     }
18466     if (parent || setupdlg->attr[KEY_DESC].supplied) {
18467 	SQLWritePrivateProfileString(dsn, "Description",
18468 				     setupdlg->attr[KEY_DESC].attr,
18469 				     ODBC_INI);
18470     }
18471     if (parent || setupdlg->attr[KEY_DBNAME].supplied) {
18472 	SQLWritePrivateProfileString(dsn, "Database",
18473 				     setupdlg->attr[KEY_DBNAME].attr,
18474 				     ODBC_INI);
18475     }
18476     if (parent || setupdlg->attr[KEY_BUSY].supplied) {
18477 	SQLWritePrivateProfileString(dsn, "Timeout",
18478 				     setupdlg->attr[KEY_BUSY].attr,
18479 				     ODBC_INI);
18480     }
18481     if (parent || setupdlg->attr[KEY_STEPAPI].supplied) {
18482 	SQLWritePrivateProfileString(dsn, "StepAPI",
18483 				     setupdlg->attr[KEY_STEPAPI].attr,
18484 				     ODBC_INI);
18485     }
18486     if (parent || setupdlg->attr[KEY_SYNCP].supplied) {
18487 	SQLWritePrivateProfileString(dsn, "SyncPragma",
18488 				     setupdlg->attr[KEY_SYNCP].attr,
18489 				     ODBC_INI);
18490     }
18491     if (parent || setupdlg->attr[KEY_NOTXN].supplied) {
18492 	SQLWritePrivateProfileString(dsn, "NoTXN",
18493 				     setupdlg->attr[KEY_NOTXN].attr,
18494 				     ODBC_INI);
18495     }
18496     if (parent || setupdlg->attr[KEY_SHORTNAM].supplied) {
18497 	SQLWritePrivateProfileString(dsn, "ShortNames",
18498 				     setupdlg->attr[KEY_SHORTNAM].attr,
18499 				     ODBC_INI);
18500     }
18501     if (parent || setupdlg->attr[KEY_LONGNAM].supplied) {
18502 	SQLWritePrivateProfileString(dsn, "LongNames",
18503 				     setupdlg->attr[KEY_LONGNAM].attr,
18504 				     ODBC_INI);
18505     }
18506     if (parent || setupdlg->attr[KEY_NOCREAT].supplied) {
18507 	SQLWritePrivateProfileString(dsn, "NoCreat",
18508 				     setupdlg->attr[KEY_NOCREAT].attr,
18509 				     ODBC_INI);
18510     }
18511     if (parent || setupdlg->attr[KEY_NOWCHAR].supplied) {
18512 	SQLWritePrivateProfileString(dsn, "NoWCHAR",
18513 				     setupdlg->attr[KEY_NOWCHAR].attr,
18514 				     ODBC_INI);
18515     }
18516     if (parent || setupdlg->attr[KEY_FKSUPPORT].supplied) {
18517 	SQLWritePrivateProfileString(dsn, "FKSupport",
18518 				     setupdlg->attr[KEY_FKSUPPORT].attr,
18519 				     ODBC_INI);
18520     }
18521     if (parent || setupdlg->attr[KEY_OEMCP].supplied) {
18522 	SQLWritePrivateProfileString(dsn, "OEMCP",
18523 				     setupdlg->attr[KEY_OEMCP].attr,
18524 				     ODBC_INI);
18525     }
18526     if (parent || setupdlg->attr[KEY_LOADEXT].supplied) {
18527 	SQLWritePrivateProfileString(dsn, "LoadExt",
18528 				     setupdlg->attr[KEY_LOADEXT].attr,
18529 				     ODBC_INI);
18530     }
18531     if (parent || setupdlg->attr[KEY_BIGINT].supplied) {
18532 	SQLWritePrivateProfileString(dsn, "BigInt",
18533 				     setupdlg->attr[KEY_BIGINT].attr,
18534 				     ODBC_INI);
18535     }
18536     if (parent || setupdlg->attr[KEY_PASSWD].supplied) {
18537 	SQLWritePrivateProfileString(dsn, "PWD",
18538 				     setupdlg->attr[KEY_PASSWD].attr,
18539 				     ODBC_INI);
18540     }
18541     if (setupdlg->attr[KEY_DSN].supplied &&
18542 	strcasecmp(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr)) {
18543 	SQLRemoveDSNFromIni(setupdlg->DSN);
18544     }
18545     return TRUE;
18546 }
18547 
18548 /**
18549  * Get datasource attributes from registry.
18550  * @param setupdlg pointer to dialog data
18551  */
18552 
18553 static void
GetAttributes(SETUPDLG * setupdlg)18554 GetAttributes(SETUPDLG *setupdlg)
18555 {
18556     char *dsn = setupdlg->attr[KEY_DSN].attr;
18557 
18558     if (!setupdlg->attr[KEY_DESC].supplied) {
18559 	SQLGetPrivateProfileString(dsn, "Description", "",
18560 				   setupdlg->attr[KEY_DESC].attr,
18561 				   sizeof (setupdlg->attr[KEY_DESC].attr),
18562 				   ODBC_INI);
18563     }
18564     if (!setupdlg->attr[KEY_DBNAME].supplied) {
18565 	SQLGetPrivateProfileString(dsn, "Database", "",
18566 				   setupdlg->attr[KEY_DBNAME].attr,
18567 				   sizeof (setupdlg->attr[KEY_DBNAME].attr),
18568 				   ODBC_INI);
18569     }
18570     if (!setupdlg->attr[KEY_BUSY].supplied) {
18571 	SQLGetPrivateProfileString(dsn, "Timeout", "100000",
18572 				   setupdlg->attr[KEY_BUSY].attr,
18573 				   sizeof (setupdlg->attr[KEY_BUSY].attr),
18574 				   ODBC_INI);
18575     }
18576     if (!setupdlg->attr[KEY_STEPAPI].supplied) {
18577 	SQLGetPrivateProfileString(dsn, "StepAPI", "0",
18578 				   setupdlg->attr[KEY_STEPAPI].attr,
18579 				   sizeof (setupdlg->attr[KEY_STEPAPI].attr),
18580 				   ODBC_INI);
18581     }
18582     if (!setupdlg->attr[KEY_SYNCP].supplied) {
18583 	SQLGetPrivateProfileString(dsn, "SyncPragma", "NORMAL",
18584 				   setupdlg->attr[KEY_SYNCP].attr,
18585 				   sizeof (setupdlg->attr[KEY_SYNCP].attr),
18586 				   ODBC_INI);
18587     }
18588     if (!setupdlg->attr[KEY_NOTXN].supplied) {
18589 	SQLGetPrivateProfileString(dsn, "NoTXN", "",
18590 				   setupdlg->attr[KEY_NOTXN].attr,
18591 				   sizeof (setupdlg->attr[KEY_NOTXN].attr),
18592 				   ODBC_INI);
18593     }
18594     if (!setupdlg->attr[KEY_SHORTNAM].supplied) {
18595 	SQLGetPrivateProfileString(dsn, "ShortNames", "",
18596 				   setupdlg->attr[KEY_SHORTNAM].attr,
18597 				   sizeof (setupdlg->attr[KEY_SHORTNAM].attr),
18598 				   ODBC_INI);
18599     }
18600     if (!setupdlg->attr[KEY_LONGNAM].supplied) {
18601 	SQLGetPrivateProfileString(dsn, "LongNames", "",
18602 				   setupdlg->attr[KEY_LONGNAM].attr,
18603 				   sizeof (setupdlg->attr[KEY_LONGNAM].attr),
18604 				   ODBC_INI);
18605     }
18606     if (!setupdlg->attr[KEY_NOCREAT].supplied) {
18607 	SQLGetPrivateProfileString(dsn, "NoCreat", "",
18608 				   setupdlg->attr[KEY_NOCREAT].attr,
18609 				   sizeof (setupdlg->attr[KEY_NOCREAT].attr),
18610 				   ODBC_INI);
18611     }
18612     if (!setupdlg->attr[KEY_NOWCHAR].supplied) {
18613 	SQLGetPrivateProfileString(dsn, "NoWCHAR", "",
18614 				   setupdlg->attr[KEY_NOWCHAR].attr,
18615 				   sizeof (setupdlg->attr[KEY_NOWCHAR].attr),
18616 				   ODBC_INI);
18617     }
18618     if (!setupdlg->attr[KEY_FKSUPPORT].supplied) {
18619 	SQLGetPrivateProfileString(dsn, "FKSupport", "",
18620 				   setupdlg->attr[KEY_FKSUPPORT].attr,
18621 				   sizeof (setupdlg->attr[KEY_FKSUPPORT].attr),
18622 				   ODBC_INI);
18623     }
18624     if (!setupdlg->attr[KEY_OEMCP].supplied) {
18625 	SQLGetPrivateProfileString(dsn, "OEMCP", "",
18626 				   setupdlg->attr[KEY_OEMCP].attr,
18627 				   sizeof (setupdlg->attr[KEY_OEMCP].attr),
18628 				   ODBC_INI);
18629     }
18630     if (!setupdlg->attr[KEY_LOADEXT].supplied) {
18631 	SQLGetPrivateProfileString(dsn, "LoadExt", "",
18632 				   setupdlg->attr[KEY_LOADEXT].attr,
18633 				   sizeof (setupdlg->attr[KEY_LOADEXT].attr),
18634 				   ODBC_INI);
18635     }
18636     if (!setupdlg->attr[KEY_JMODE].supplied) {
18637 	SQLGetPrivateProfileString(dsn, "JournalMode", "",
18638 				   setupdlg->attr[KEY_JMODE].attr,
18639 				   sizeof (setupdlg->attr[KEY_JMODE].attr),
18640 				   ODBC_INI);
18641     }
18642     if (!setupdlg->attr[KEY_BIGINT].supplied) {
18643 	SQLGetPrivateProfileString(dsn, "BigInt", "",
18644 				   setupdlg->attr[KEY_BIGINT].attr,
18645 				   sizeof (setupdlg->attr[KEY_BIGINT].attr),
18646 				   ODBC_INI);
18647     }
18648     if (!setupdlg->attr[KEY_PASSWD].supplied) {
18649 	SQLGetPrivateProfileString(dsn, "PWD", "",
18650 				   setupdlg->attr[KEY_PASSWD].attr,
18651 				   sizeof (setupdlg->attr[KEY_PASSWD].attr),
18652 				   ODBC_INI);
18653     }
18654 }
18655 
18656 /**
18657  * Open file dialog for selection of SQLite database file.
18658  * @param hdlg handle of originating dialog window
18659  */
18660 
18661 static void
GetDBFile(HWND hdlg)18662 GetDBFile(HWND hdlg)
18663 {
18664 #ifdef _WIN64
18665     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
18666 #else
18667     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
18668 #endif
18669     OPENFILENAME ofn;
18670 
18671     memset(&ofn, 0, sizeof (ofn));
18672     ofn.lStructSize = sizeof (ofn);
18673     ofn.hwndOwner = hdlg;
18674 #ifdef _WIN64
18675     ofn.hInstance = (HINSTANCE) GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
18676 #else
18677     ofn.hInstance = (HINSTANCE) GetWindowLong(hdlg, GWL_HINSTANCE);
18678 #endif
18679     ofn.lpstrFile = (LPTSTR) setupdlg->attr[KEY_DBNAME].attr;
18680     ofn.nMaxFile = MAXPATHLEN;
18681     ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
18682 		OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_FILEMUSTEXIST;
18683     if (GetOpenFileName(&ofn)) {
18684 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
18685 	setupdlg->attr[KEY_DBNAME].supplied = TRUE;
18686     }
18687 }
18688 
18689 /**
18690  * Dialog procedure for ConfigDSN().
18691  * @param hdlg handle of dialog window
18692  * @param wmsg type of message
18693  * @param wparam wparam of message
18694  * @param lparam lparam of message
18695  * @result true or false
18696  */
18697 
18698 static BOOL CALLBACK
ConfigDlgProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)18699 ConfigDlgProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
18700 {
18701     SETUPDLG *setupdlg = NULL;
18702     WORD index;
18703 
18704     switch (wmsg) {
18705     case WM_INITDIALOG:
18706 #ifdef _WIN64
18707 	SetWindowLong(hdlg, DWLP_USER, lparam);
18708 #else
18709 	SetWindowLong(hdlg, DWL_USER, lparam);
18710 #endif
18711 	setupdlg = (SETUPDLG *) lparam;
18712 	GetAttributes(setupdlg);
18713 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
18714 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
18715 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
18716 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
18717 	SetDlgItemText(hdlg, IDC_LOADEXT, setupdlg->attr[KEY_LOADEXT].attr);
18718 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
18719 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
18720 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
18721 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
18722 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
18723 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
18724 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
18725 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
18726 	SendDlgItemMessage(hdlg, IDC_LOADEXT, EM_LIMITTEXT,
18727 			   (WPARAM) (MAXPATHLEN*4 - 1), (LPARAM) 0);
18728 	CheckDlgButton(hdlg, IDC_STEPAPI,
18729 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
18730 		       BST_CHECKED : BST_UNCHECKED);
18731 	CheckDlgButton(hdlg, IDC_NOTXN,
18732 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
18733 		       BST_CHECKED : BST_UNCHECKED);
18734 	CheckDlgButton(hdlg, IDC_SHORTNAM,
18735 		       getbool(setupdlg->attr[KEY_SHORTNAM].attr) ?
18736 		       BST_CHECKED : BST_UNCHECKED);
18737 	CheckDlgButton(hdlg, IDC_LONGNAM,
18738 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
18739 		       BST_CHECKED : BST_UNCHECKED);
18740 	CheckDlgButton(hdlg, IDC_NOCREAT,
18741 		       getbool(setupdlg->attr[KEY_NOCREAT].attr) ?
18742 		       BST_CHECKED : BST_UNCHECKED);
18743 	CheckDlgButton(hdlg, IDC_NOWCHAR,
18744 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
18745 		       BST_CHECKED : BST_UNCHECKED);
18746 	CheckDlgButton(hdlg, IDC_FKSUPPORT,
18747 		       getbool(setupdlg->attr[KEY_FKSUPPORT].attr) ?
18748 		       BST_CHECKED : BST_UNCHECKED);
18749 	CheckDlgButton(hdlg, IDC_OEMCP,
18750 		       getbool(setupdlg->attr[KEY_OEMCP].attr) ?
18751 		       BST_CHECKED : BST_UNCHECKED);
18752 	CheckDlgButton(hdlg, IDC_BIGINT,
18753 		       getbool(setupdlg->attr[KEY_BIGINT].attr) ?
18754 		       BST_CHECKED : BST_UNCHECKED);
18755 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18756 			   CB_LIMITTEXT, (WPARAM) 10, (LPARAM) 0);
18757 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18758 			   CB_ADDSTRING, 0, (LPARAM) "NORMAL");
18759 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18760 			   CB_ADDSTRING, 0, (LPARAM) "OFF");
18761 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18762 			   CB_ADDSTRING, 0, (LPARAM) "FULL");
18763 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18764 			   CB_SELECTSTRING, (WPARAM) -1,
18765 			   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
18766 	if (setupdlg->defDSN) {
18767 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
18768 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
18769 	}
18770 	return TRUE;
18771     case WM_COMMAND:
18772 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
18773 	case IDC_DSNAME:
18774 	    if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) {
18775 		char item[MAXDSNAME];
18776 
18777 		EnableWindow(GetDlgItem(hdlg, IDOK),
18778 			     GetDlgItemText(hdlg, IDC_DSNAME,
18779 					    item, sizeof (item)));
18780 		return TRUE;
18781 	    }
18782 	    break;
18783 	case IDC_BROWSE:
18784 	    GetDBFile(hdlg);
18785 	    break;
18786 	case IDOK:
18787 #ifdef _WIN64
18788 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
18789 #else
18790 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
18791 #endif
18792 	    if (!setupdlg->defDSN) {
18793 		GetDlgItemText(hdlg, IDC_DSNAME,
18794 			       setupdlg->attr[KEY_DSN].attr,
18795 			       sizeof (setupdlg->attr[KEY_DSN].attr));
18796 	    }
18797 	    GetDlgItemText(hdlg, IDC_DESC,
18798 			   setupdlg->attr[KEY_DESC].attr,
18799 			   sizeof (setupdlg->attr[KEY_DESC].attr));
18800 	    GetDlgItemText(hdlg, IDC_DBNAME,
18801 			   setupdlg->attr[KEY_DBNAME].attr,
18802 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
18803 	    GetDlgItemText(hdlg, IDC_TONAME,
18804 			   setupdlg->attr[KEY_BUSY].attr,
18805 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
18806 	    GetDlgItemText(hdlg, IDC_LOADEXT,
18807 			   setupdlg->attr[KEY_LOADEXT].attr,
18808 			   sizeof (setupdlg->attr[KEY_LOADEXT].attr));
18809 	    index = SendDlgItemMessage(hdlg, IDC_SYNCP,
18810 				       CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
18811 	    if (index != (WORD) CB_ERR) {
18812 		SendDlgItemMessage(hdlg, IDC_SYNCP,
18813 				   CB_GETLBTEXT, index,
18814 				   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
18815 	    }
18816 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
18817 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
18818 		   "1" : "0");
18819 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
18820 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
18821 		   "1" : "0");
18822 	    strcpy(setupdlg->attr[KEY_SHORTNAM].attr,
18823 		   (IsDlgButtonChecked(hdlg, IDC_SHORTNAM) == BST_CHECKED) ?
18824 		   "1" : "0");
18825 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
18826 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
18827 		   "1" : "0");
18828 	    strcpy(setupdlg->attr[KEY_NOCREAT].attr,
18829 		   (IsDlgButtonChecked(hdlg, IDC_NOCREAT) == BST_CHECKED) ?
18830 		   "1" : "0");
18831 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
18832 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
18833 		   "1" : "0");
18834 	    strcpy(setupdlg->attr[KEY_FKSUPPORT].attr,
18835 		   (IsDlgButtonChecked(hdlg, IDC_FKSUPPORT) == BST_CHECKED) ?
18836 		   "1" : "0");
18837 	    strcpy(setupdlg->attr[KEY_OEMCP].attr,
18838 		   (IsDlgButtonChecked(hdlg, IDC_OEMCP) == BST_CHECKED) ?
18839 		   "1" : "0");
18840 	    strcpy(setupdlg->attr[KEY_BIGINT].attr,
18841 		   (IsDlgButtonChecked(hdlg, IDC_BIGINT) == BST_CHECKED) ?
18842 		   "1" : "0");
18843 	    SetDSNAttributes(hdlg, setupdlg);
18844 	    /* FALL THROUGH */
18845 	case IDCANCEL:
18846 	    EndDialog(hdlg, wparam);
18847 	    return TRUE;
18848 	}
18849 	break;
18850     }
18851     return FALSE;
18852 }
18853 
18854 /**
18855  * ODBC INSTAPI procedure for DSN configuration.
18856  * @param hwnd parent window handle
18857  * @param request type of request
18858  * @param driver driver name
18859  * @param attribs attribute string of DSN
18860  * @result true or false
18861  */
18862 
18863 BOOL INSTAPI
ConfigDSN(HWND hwnd,WORD request,LPCSTR driver,LPCSTR attribs)18864 ConfigDSN(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attribs)
18865 {
18866     BOOL success;
18867     SETUPDLG *setupdlg;
18868 
18869     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
18870     if (setupdlg == NULL) {
18871 	return FALSE;
18872     }
18873     memset(setupdlg, 0, sizeof (SETUPDLG));
18874     if (attribs) {
18875 	ParseAttributes(attribs, setupdlg);
18876     }
18877     if (setupdlg->attr[KEY_DSN].supplied) {
18878 	strcpy(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr);
18879     } else {
18880 	setupdlg->DSN[0] = '\0';
18881     }
18882     if (request == ODBC_REMOVE_DSN) {
18883 	if (!setupdlg->attr[KEY_DSN].supplied) {
18884 	    success = FALSE;
18885 	} else {
18886 	    success = SQLRemoveDSNFromIni(setupdlg->attr[KEY_DSN].attr);
18887 	}
18888     } else {
18889 	setupdlg->parent = hwnd;
18890 	setupdlg->driver = driver;
18891 	setupdlg->newDSN = request == ODBC_ADD_DSN;
18892 	setupdlg->defDSN = strcasecmp(setupdlg->attr[KEY_DSN].attr,
18893 				      "Default") == 0;
18894 	if (hwnd) {
18895 	    success = DialogBoxParam(hModule, MAKEINTRESOURCE(CONFIGDSN),
18896 				     hwnd, (DLGPROC) ConfigDlgProc,
18897 				     (LPARAM) setupdlg) == IDOK;
18898 	} else if (setupdlg->attr[KEY_DSN].supplied) {
18899 	    success = SetDSNAttributes(hwnd, setupdlg);
18900 	} else {
18901 	    success = FALSE;
18902 	}
18903     }
18904     xfree(setupdlg);
18905     return success;
18906 }
18907 
18908 /**
18909  * Dialog procedure for SQLDriverConnect().
18910  * @param hdlg handle of dialog window
18911  * @param wmsg type of message
18912  * @param wparam wparam of message
18913  * @param lparam lparam of message
18914  * @result true or false
18915  */
18916 
18917 static BOOL CALLBACK
DriverConnectProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)18918 DriverConnectProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
18919 {
18920     SETUPDLG *setupdlg;
18921     WORD index;
18922 
18923     switch (wmsg) {
18924     case WM_INITDIALOG:
18925 #ifdef _WIN64
18926 	SetWindowLong(hdlg, DWLP_USER, lparam);
18927 #else
18928 	SetWindowLong(hdlg, DWL_USER, lparam);
18929 #endif
18930 	setupdlg = (SETUPDLG *) lparam;
18931 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
18932 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
18933 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
18934 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
18935 	SetDlgItemText(hdlg, IDC_LOADEXT, setupdlg->attr[KEY_LOADEXT].attr);
18936 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
18937 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
18938 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
18939 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
18940 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
18941 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
18942 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
18943 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
18944 	SendDlgItemMessage(hdlg, IDC_LOADEXT, EM_LIMITTEXT,
18945 			   (WPARAM) (MAXPATHLEN*4 - 1), (LPARAM) 0);
18946 	CheckDlgButton(hdlg, IDC_STEPAPI,
18947 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
18948 		       BST_CHECKED : BST_UNCHECKED);
18949 	CheckDlgButton(hdlg, IDC_NOTXN,
18950 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
18951 		       BST_CHECKED : BST_UNCHECKED);
18952 	CheckDlgButton(hdlg, IDC_SHORTNAM,
18953 		       getbool(setupdlg->attr[KEY_SHORTNAM].attr) ?
18954 		       BST_CHECKED : BST_UNCHECKED);
18955 	CheckDlgButton(hdlg, IDC_LONGNAM,
18956 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
18957 		       BST_CHECKED : BST_UNCHECKED);
18958 	CheckDlgButton(hdlg, IDC_NOCREAT,
18959 		       getbool(setupdlg->attr[KEY_NOCREAT].attr) ?
18960 		       BST_CHECKED : BST_UNCHECKED);
18961 	CheckDlgButton(hdlg, IDC_NOWCHAR,
18962 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
18963 		       BST_CHECKED : BST_UNCHECKED);
18964 	CheckDlgButton(hdlg, IDC_FKSUPPORT,
18965 		       getbool(setupdlg->attr[KEY_FKSUPPORT].attr) ?
18966 		       BST_CHECKED : BST_UNCHECKED);
18967 	CheckDlgButton(hdlg, IDC_OEMCP,
18968 		       getbool(setupdlg->attr[KEY_OEMCP].attr) ?
18969 		       BST_CHECKED : BST_UNCHECKED);
18970 	CheckDlgButton(hdlg, IDC_BIGINT,
18971 		       getbool(setupdlg->attr[KEY_BIGINT].attr) ?
18972 		       BST_CHECKED : BST_UNCHECKED);
18973 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18974 			   CB_LIMITTEXT, (WPARAM) 10, (LPARAM) 0);
18975 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18976 			   CB_ADDSTRING, 0, (LPARAM) "NORMAL");
18977 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18978 			   CB_ADDSTRING, 0, (LPARAM) "OFF");
18979 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18980 			   CB_ADDSTRING, 0, (LPARAM) "FULL");
18981 	SendDlgItemMessage(hdlg, IDC_SYNCP,
18982 			   CB_SELECTSTRING, (WORD) -1,
18983 			   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
18984 	if (setupdlg->defDSN) {
18985 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
18986 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
18987 	}
18988 	return TRUE;
18989     case WM_COMMAND:
18990 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
18991 	case IDC_BROWSE:
18992 	    GetDBFile(hdlg);
18993 	    break;
18994 	case IDOK:
18995 #ifdef _WIN64
18996 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
18997 #else
18998 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
18999 #endif
19000 	    GetDlgItemText(hdlg, IDC_DSNAME,
19001 			   setupdlg->attr[KEY_DSN].attr,
19002 			   sizeof (setupdlg->attr[KEY_DSN].attr));
19003 	    GetDlgItemText(hdlg, IDC_DBNAME,
19004 			   setupdlg->attr[KEY_DBNAME].attr,
19005 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
19006 	    GetDlgItemText(hdlg, IDC_TONAME,
19007 			   setupdlg->attr[KEY_BUSY].attr,
19008 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
19009 	    GetDlgItemText(hdlg, IDC_LOADEXT,
19010 			   setupdlg->attr[KEY_LOADEXT].attr,
19011 			   sizeof (setupdlg->attr[KEY_LOADEXT].attr));
19012 	    index = SendDlgItemMessage(hdlg, IDC_SYNCP,
19013 				       CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
19014 	    if (index != (WORD) CB_ERR) {
19015 		SendDlgItemMessage(hdlg, IDC_SYNCP,
19016 				   CB_GETLBTEXT, index,
19017 				   (LPARAM) setupdlg->attr[KEY_SYNCP].attr);
19018 	    }
19019 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
19020 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
19021 		   "1" : "0");
19022 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
19023 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
19024 		   "1" : "0");
19025 	    strcpy(setupdlg->attr[KEY_SHORTNAM].attr,
19026 		   (IsDlgButtonChecked(hdlg, IDC_SHORTNAM) == BST_CHECKED) ?
19027 		   "1" : "0");
19028 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
19029 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
19030 		   "1" : "0");
19031 	    strcpy(setupdlg->attr[KEY_NOCREAT].attr,
19032 		   (IsDlgButtonChecked(hdlg, IDC_NOCREAT) == BST_CHECKED) ?
19033 		   "1" : "0");
19034 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
19035 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
19036 		   "1" : "0");
19037 	    strcpy(setupdlg->attr[KEY_FKSUPPORT].attr,
19038 		   (IsDlgButtonChecked(hdlg, IDC_FKSUPPORT) == BST_CHECKED) ?
19039 		   "1" : "0");
19040 	    strcpy(setupdlg->attr[KEY_OEMCP].attr,
19041 		   (IsDlgButtonChecked(hdlg, IDC_OEMCP) == BST_CHECKED) ?
19042 		   "1" : "0");
19043 	    strcpy(setupdlg->attr[KEY_BIGINT].attr,
19044 		   (IsDlgButtonChecked(hdlg, IDC_BIGINT) == BST_CHECKED) ?
19045 		   "1" : "0");
19046 	    /* FALL THROUGH */
19047 	case IDCANCEL:
19048 	    EndDialog(hdlg, GET_WM_COMMAND_ID(wparam, lparam) == IDOK);
19049 	    return TRUE;
19050 	}
19051     }
19052     return FALSE;
19053 }
19054 
19055 /**
19056  * Internal connect using a driver connection string.
19057  * @param dbc database connection handle
19058  * @param hwnd parent window handle
19059  * @param connIn driver connect input string
19060  * @param connInLen length of driver connect input string or SQL_NTS
19061  * @param connOut driver connect output string
19062  * @param connOutMax length of driver connect output string
19063  * @param connOutLen output length of driver connect output string
19064  * @param drvcompl completion type
19065  * @result ODBC error code
19066  */
19067 
19068 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)19069 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
19070 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
19071 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
19072 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
19073 {
19074     BOOL maybeprompt, prompt = FALSE, defaultdsn = FALSE;
19075     DBC *d;
19076     SETUPDLG *setupdlg;
19077     SQLRETURN ret;
19078     char *dsn = NULL, *driver = NULL, *dbname = NULL;
19079 
19080     if (dbc == SQL_NULL_HDBC) {
19081 	return SQL_INVALID_HANDLE;
19082     }
19083     d = (DBC *) dbc;
19084     if (d->sqlite) {
19085 	setstatd(d, -1, "connection already established", "08002");
19086 	return SQL_ERROR;
19087     }
19088     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
19089     if (setupdlg == NULL) {
19090 	return SQL_ERROR;
19091     }
19092     memset(setupdlg, 0, sizeof (SETUPDLG));
19093     maybeprompt = drvcompl == SQL_DRIVER_COMPLETE ||
19094 	drvcompl == SQL_DRIVER_COMPLETE_REQUIRED;
19095     if (connIn == NULL || !connInLen ||
19096 	(connInLen == SQL_NTS && !connIn[0])) {
19097 	prompt = TRUE;
19098     } else {
19099 	ParseAttributes((LPCSTR) connIn, setupdlg);
19100 	if (!setupdlg->attr[KEY_DSN].attr[0] &&
19101 	    drvcompl == SQL_DRIVER_COMPLETE_REQUIRED) {
19102 	    strcpy(setupdlg->attr[KEY_DSN].attr, "DEFAULT");
19103 	    defaultdsn = TRUE;
19104 	}
19105 	GetAttributes(setupdlg);
19106 	if (drvcompl == SQL_DRIVER_PROMPT ||
19107 	    (maybeprompt &&
19108 	     !setupdlg->attr[KEY_DBNAME].attr[0])) {
19109 	    prompt = TRUE;
19110 	}
19111     }
19112 retry:
19113     if (prompt) {
19114 	short dlgret;
19115 
19116 	setupdlg->defDSN = setupdlg->attr[KEY_DRIVER].attr[0] != '\0';
19117 	dlgret = DialogBoxParam(hModule, MAKEINTRESOURCE(DRIVERCONNECT),
19118 				hwnd, (DLGPROC) DriverConnectProc,
19119 				(LPARAM) setupdlg);
19120 
19121 	if (!dlgret || dlgret == -1) {
19122 	    xfree(setupdlg);
19123 	    return SQL_NO_DATA;
19124 	}
19125     }
19126     dsn = setupdlg->attr[KEY_DSN].attr;
19127     driver = setupdlg->attr[KEY_DRIVER].attr;
19128     dbname = setupdlg->attr[KEY_DBNAME].attr;
19129     if (connOut || connOutLen) {
19130 	char buf[SQL_MAX_MESSAGE_LENGTH * 8];
19131 	int len, count;
19132 	char dsn_0 = (dsn && !defaultdsn) ? dsn[0] : '\0';
19133 	char drv_0 = driver ? driver[0] : '\0';
19134 
19135 	buf[0] = '\0';
19136 	count = snprintf(buf, sizeof (buf),
19137 			 "%s%s%s%s%s%sDatabase=%s;StepAPI=%s;"
19138 			 "SyncPragma=%s;NoTXN=%s;Timeout=%s;"
19139 			 "ShortNames=%s;LongNames=%s;"
19140 			 "NoCreat=%s;NoWCHAR=%s;"
19141 			 "FKSupport=%s;JournalMode=%s;OEMCP=%s;LoadExt=%s;"
19142 			 "BigInt=%s;PWD=%s",
19143 			 dsn_0 ? "DSN=" : "",
19144 			 dsn_0 ? dsn : "",
19145 			 dsn_0 ? ";" : "",
19146 			 drv_0 ? "Driver=" : "",
19147 			 drv_0 ? driver : "",
19148 			 drv_0 ? ";" : "",
19149 			 dbname ? dbname : "",
19150 			 setupdlg->attr[KEY_STEPAPI].attr,
19151 			 setupdlg->attr[KEY_SYNCP].attr,
19152 			 setupdlg->attr[KEY_NOTXN].attr,
19153 			 setupdlg->attr[KEY_BUSY].attr,
19154 			 setupdlg->attr[KEY_SHORTNAM].attr,
19155 			 setupdlg->attr[KEY_LONGNAM].attr,
19156 			 setupdlg->attr[KEY_NOCREAT].attr,
19157 			 setupdlg->attr[KEY_NOWCHAR].attr,
19158 			 setupdlg->attr[KEY_FKSUPPORT].attr,
19159 			 setupdlg->attr[KEY_JMODE].attr,
19160 			 setupdlg->attr[KEY_OEMCP].attr,
19161 			 setupdlg->attr[KEY_LOADEXT].attr,
19162 			 setupdlg->attr[KEY_BIGINT].attr,
19163 			 setupdlg->attr[KEY_PASSWD].attr);
19164 	if (count < 0) {
19165 	    buf[sizeof (buf) - 1] = '\0';
19166 	}
19167 	len = min(connOutMax - 1, strlen(buf));
19168 	if (connOut) {
19169 	    strncpy((char *) connOut, buf, len);
19170 	    connOut[len] = '\0';
19171 	}
19172 	if (connOutLen) {
19173 	    *connOutLen = len;
19174 	}
19175     }
19176     if (dsn[0]) {
19177 	char tracef[SQL_MAX_MESSAGE_LENGTH];
19178 
19179 	tracef[0] = '\0';
19180 	SQLGetPrivateProfileString(setupdlg->attr[KEY_DSN].attr,
19181 				   "tracefile", "", tracef,
19182 				   sizeof (tracef), ODBC_INI);
19183 	if (tracef[0] != '\0') {
19184 	    d->trace = fopen(tracef, "a");
19185 	}
19186     }
19187     d->nowchar = getbool(setupdlg->attr[KEY_NOWCHAR].attr);
19188     d->shortnames = getbool(setupdlg->attr[KEY_SHORTNAM].attr);
19189     d->longnames = getbool(setupdlg->attr[KEY_LONGNAM].attr);
19190     d->nocreat = getbool(setupdlg->attr[KEY_NOCREAT].attr);
19191     d->fksupport = getbool(setupdlg->attr[KEY_FKSUPPORT].attr);
19192     d->oemcp = getbool(setupdlg->attr[KEY_OEMCP].attr);
19193     d->dobigint = getbool(setupdlg->attr[KEY_BIGINT].attr);
19194     d->pwdLen = strlen(setupdlg->attr[KEY_PASSWD].attr);
19195     d->pwd = (d->pwdLen > 0) ? setupdlg->attr[KEY_PASSWD].attr : NULL;
19196     ret = dbopen(d, dbname ? dbname : "", 0,
19197 		 dsn ? dsn : "",
19198 		 setupdlg->attr[KEY_STEPAPI].attr,
19199 		 setupdlg->attr[KEY_SYNCP].attr,
19200 		 setupdlg->attr[KEY_NOTXN].attr,
19201 		 setupdlg->attr[KEY_JMODE].attr,
19202 		 setupdlg->attr[KEY_BUSY].attr);
19203     if (ret != SQL_SUCCESS) {
19204 	if (maybeprompt && !prompt) {
19205 	    prompt = TRUE;
19206 	    goto retry;
19207 	}
19208     }
19209     memset(setupdlg->attr[KEY_PASSWD].attr, 0,
19210 	   sizeof (setupdlg->attr[KEY_PASSWD].attr));
19211     if (ret == SQL_SUCCESS) {
19212 	dbloadext(d, setupdlg->attr[KEY_LOADEXT].attr);
19213     }
19214     xfree(setupdlg);
19215     return ret;
19216 }
19217 
19218 #endif /* WITHOUT_DRIVERMGR */
19219 #endif /* _WIN32 || _WIN64 */
19220 
19221 #ifndef WINTERFACE
19222 /**
19223  * Connect using a driver connection string.
19224  * @param dbc database connection handle
19225  * @param hwnd parent window handle
19226  * @param connIn driver connect input string
19227  * @param connInLen length of driver connect input string or SQL_NTS
19228  * @param connOut driver connect output string
19229  * @param connOutMax length of driver connect output string
19230  * @param connOutLen output length of driver connect output string
19231  * @param drvcompl completion type
19232  * @result ODBC error code
19233  */
19234 
19235 SQLRETURN SQL_API
SQLDriverConnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)19236 SQLDriverConnect(SQLHDBC dbc, SQLHWND hwnd,
19237 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
19238 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
19239 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
19240 {
19241     SQLRETURN ret;
19242 
19243     HDBC_LOCK(dbc);
19244     ret = drvdriverconnect(dbc, hwnd, connIn, connInLen,
19245 			   connOut, connOutMax, connOutLen, drvcompl);
19246     HDBC_UNLOCK(dbc);
19247     return ret;
19248 }
19249 #endif
19250 
19251 #ifdef WINTERFACE
19252 /**
19253  * Connect using a driver connection string (UNICODE version).
19254  * @param dbc database connection handle
19255  * @param hwnd parent window handle
19256  * @param connIn driver connect input string
19257  * @param connInLen length of driver connect input string or SQL_NTS
19258  * @param connOut driver connect output string
19259  * @param connOutMax length of driver connect output string
19260  * @param connOutLen output length of driver connect output string
19261  * @param drvcompl completion type
19262  * @result ODBC error code
19263  */
19264 
19265 SQLRETURN SQL_API
SQLDriverConnectW(SQLHDBC dbc,SQLHWND hwnd,SQLWCHAR * connIn,SQLSMALLINT connInLen,SQLWCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)19266 SQLDriverConnectW(SQLHDBC dbc, SQLHWND hwnd,
19267 		  SQLWCHAR *connIn, SQLSMALLINT connInLen,
19268 		  SQLWCHAR *connOut, SQLSMALLINT connOutMax,
19269 		  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
19270 {
19271     SQLRETURN ret;
19272     char *ci = NULL;
19273     SQLSMALLINT len = 0;
19274 
19275     HDBC_LOCK(dbc);
19276     if (connIn) {
19277 #if defined(_WIN32) || defined(_WIN64)
19278 	if (connInLen == SQL_NTS) {
19279 	    connInLen = -1;
19280 	}
19281 	ci = uc_to_wmb(connIn, connInLen);
19282 #else
19283 	ci = uc_to_utf(connIn, connInLen);
19284 #endif
19285 	if (!ci) {
19286 	    DBC *d = (DBC *) dbc;
19287 
19288 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
19289 	    HDBC_UNLOCK(dbc);
19290 	    return SQL_ERROR;
19291 	}
19292     }
19293     ret = drvdriverconnect(dbc, hwnd, (SQLCHAR *) ci, SQL_NTS,
19294 			   (SQLCHAR *) connOut, connOutMax, &len, drvcompl);
19295     HDBC_UNLOCK(dbc);
19296     uc_free(ci);
19297     if (ret == SQL_SUCCESS) {
19298 	SQLWCHAR *co = NULL;
19299 
19300 	if (connOut) {
19301 	    if (len > 0) {
19302 #if defined(_WIN32) || defined(_WIN64)
19303 		co = wmb_to_uc((char *) connOut, len);
19304 #else
19305 		co = uc_from_utf((SQLCHAR *) connOut, len);
19306 #endif
19307 		if (co) {
19308 		    uc_strncpy(connOut, co, connOutMax / sizeof (SQLWCHAR));
19309 		    len = min(connOutMax / sizeof (SQLWCHAR), uc_strlen(co));
19310 		    uc_free(co);
19311 		} else {
19312 		    len = 0;
19313 		}
19314 	    }
19315 	    if (len <= 0) {
19316 		len = 0;
19317 		connOut[0] = 0;
19318 	    }
19319 	} else {
19320 	    len = 0;
19321 	}
19322 	if (connOutLen) {
19323 	    *connOutLen = len;
19324 	}
19325     }
19326     return ret;
19327 }
19328 #endif
19329 
19330 #if defined(_WIN32) || defined(_WIN64)
19331 
19332 /**
19333  * DLL initializer for WIN32.
19334  * @param hinst instance handle
19335  * @param reason reason code for entry point
19336  * @param reserved
19337  * @result always true
19338  */
19339 
19340 BOOL APIENTRY
LibMain(HANDLE hinst,DWORD reason,LPVOID reserved)19341 LibMain(HANDLE hinst, DWORD reason, LPVOID reserved)
19342 {
19343     static int initialized = 0;
19344 
19345     switch (reason) {
19346     case DLL_PROCESS_ATTACH:
19347 	if (!initialized++) {
19348 	    hModule = hinst;
19349 #ifdef WINTERFACE
19350 	    /* MS Access hack part 1 (reserved error -7748) */
19351 	    statSpec2P = statSpec2;
19352 	    statSpec3P = statSpec3;
19353 #endif
19354 #ifdef SQLITE_DYNLOAD
19355 	    dls_init();
19356 #endif
19357 	}
19358 	break;
19359     case DLL_THREAD_ATTACH:
19360 	break;
19361     case DLL_PROCESS_DETACH:
19362 	if (--initialized <= 0) {
19363 #ifdef SQLITE_DYNLOAD
19364 	    dls_fini();
19365 #endif
19366 	}
19367 	break;
19368     case DLL_THREAD_DETACH:
19369 	break;
19370     default:
19371 	break;
19372     }
19373     return TRUE;
19374 }
19375 
19376 /**
19377  * DLL entry point for WIN32.
19378  * @param hinst instance handle
19379  * @param reason reason code for entry point
19380  * @param reserved
19381  * @result always true
19382  */
19383 
19384 int __stdcall
DllMain(HANDLE hinst,DWORD reason,LPVOID reserved)19385 DllMain(HANDLE hinst, DWORD reason, LPVOID reserved)
19386 {
19387     return LibMain(hinst, reason, reserved);
19388 }
19389 
19390 #ifndef WITHOUT_INSTALLER
19391 
19392 /**
19393  * Handler for driver installer/uninstaller error messages.
19394  * @param name name of API function for which to show error messages
19395  * @result true when error message retrieved
19396  */
19397 
19398 static BOOL
InUnError(char * name)19399 InUnError(char *name)
19400 {
19401     WORD err = 1;
19402     DWORD code;
19403     char errmsg[301];
19404     WORD errlen, errmax = sizeof (errmsg) - 1;
19405     int sqlret;
19406     BOOL ret = FALSE;
19407 
19408     do {
19409 	errmsg[0] = '\0';
19410 	sqlret = SQLInstallerError(err, &code, errmsg, errmax, &errlen);
19411 	if (SQL_SUCCEEDED(sqlret)) {
19412 	    MessageBox(NULL, errmsg, name,
19413 		       MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
19414 	    ret = TRUE;
19415 	}
19416 	err++;
19417     } while (sqlret != SQL_NO_DATA);
19418     return ret;
19419 }
19420 
19421 /**
19422  * Built in driver installer/uninstaller.
19423  * @param remove true for uninstall
19424  * @param cmdline command line string of rundll32
19425  */
19426 
19427 static BOOL
InUn(int remove,char * cmdline)19428 InUn(int remove, char *cmdline)
19429 {
19430 #ifdef SQLITE_HAS_CODEC
19431     static char *drivername = "SQLite4 ODBC Driver (SEE)";
19432     static char *dsname = "SQLite4 SEE Datasource";
19433 #else
19434     static char *drivername = "SQLite4 ODBC Driver";
19435     static char *dsname = "SQLite4 Datasource";
19436 #endif
19437     char *dllname, *p;
19438     char dllbuf[301], path[301], driver[300], attr[300], inst[400];
19439     WORD pathmax = sizeof (path) - 1, pathlen;
19440     DWORD usecnt, mincnt;
19441     int quiet = 0;
19442 
19443     dllbuf[0] = '\0';
19444     GetModuleFileName(hModule, dllbuf, sizeof (dllbuf));
19445     p = strrchr(dllbuf, '\\');
19446     dllname = p ? (p + 1) : dllbuf;
19447     quiet = cmdline && strstr(cmdline, "quiet");
19448     if (SQLInstallDriverManager(path, pathmax, &pathlen)) {
19449 	sprintf(driver, "%s;Driver=%s;Setup=%s;",
19450 		drivername, dllname, dllname);
19451 	p = driver;
19452 	while (*p) {
19453 	    if (*p == ';') {
19454 		*p = '\0';
19455 	    }
19456 	    ++p;
19457 	}
19458 	usecnt = 0;
19459 	path[0] = '\0';
19460 	SQLInstallDriverEx(driver, NULL, path, pathmax, NULL,
19461 			   ODBC_INSTALL_INQUIRY, &usecnt);
19462 	pathlen = strlen(path);
19463 	while (pathlen > 0 && path[pathlen - 1] == '\\') {
19464 	    --pathlen;
19465 	    path[pathlen] = '\0';
19466 	}
19467 	sprintf(driver, "%s;Driver=%s\\%s;Setup=%s\\%s;",
19468 		drivername, path, dllname, path, dllname);
19469 	p = driver;
19470 	while (*p) {
19471 	    if (*p == ';') {
19472 		*p = '\0';
19473 	    }
19474 	    ++p;
19475 	}
19476 	sprintf(inst, "%s\\%s", path, dllname);
19477 	if (!remove && usecnt > 0) {
19478 	    /* first install try: copy over driver dll, keeping DSNs */
19479 	    if (GetFileAttributesA(dllbuf) != INVALID_FILE_ATTRIBUTES &&
19480 		CopyFile(dllbuf, inst, 0)) {
19481 		if (!quiet) {
19482 		    char buf[512];
19483 
19484 		    sprintf(buf, "%s replaced.", drivername);
19485 		    MessageBox(NULL, buf, "Info",
19486 			       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
19487 			       MB_SETFOREGROUND);
19488 		}
19489 		return TRUE;
19490 	    }
19491 	}
19492 	mincnt = remove ? 1 : 0;
19493 	while (usecnt != mincnt) {
19494 	    if (!SQLRemoveDriver(driver, TRUE, &usecnt)) {
19495 		break;
19496 	    }
19497 	}
19498 	if (remove) {
19499 	    if (usecnt && !SQLRemoveDriver(driver, TRUE, &usecnt)) {
19500 		InUnError("SQLRemoveDriver");
19501 		return FALSE;
19502 	    }
19503 	    if (!usecnt) {
19504 		char buf[512];
19505 
19506 		DeleteFile(inst);
19507 		if (!quiet) {
19508 		    sprintf(buf, "%s uninstalled.", drivername);
19509 		    MessageBox(NULL, buf, "Info",
19510 			       MB_ICONINFORMATION |MB_OK | MB_TASKMODAL |
19511 			       MB_SETFOREGROUND);
19512 		}
19513 	    }
19514 	    sprintf(attr, "DSN=%s;Database=;", dsname);
19515 	    p = attr;
19516 	    while (*p) {
19517 		if (*p == ';') {
19518 		    *p = '\0';
19519 		}
19520 		++p;
19521 	    }
19522 	    SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
19523 	    return TRUE;
19524 	}
19525 	if (GetFileAttributesA(dllbuf) == INVALID_FILE_ATTRIBUTES) {
19526 	    return FALSE;
19527 	}
19528 	if (strcasecmp(dllbuf, inst) != 0 && !CopyFile(dllbuf, inst, 0)) {
19529 	    char buf[512];
19530 
19531 	    sprintf(buf, "Copy %s to %s failed.", dllbuf, inst);
19532 	    MessageBox(NULL, buf, "CopyFile",
19533 		       MB_ICONSTOP |MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
19534 	    return FALSE;
19535 	}
19536 	if (!SQLInstallDriverEx(driver, path, path, pathmax, &pathlen,
19537 				ODBC_INSTALL_COMPLETE, &usecnt)) {
19538 	    InUnError("SQLInstallDriverEx");
19539 	    return FALSE;
19540 	}
19541 	sprintf(attr, "DSN=%s;Database=;", dsname);
19542 	p = attr;
19543 	while (*p) {
19544 	    if (*p == ';') {
19545 		*p = '\0';
19546 	    }
19547 	    ++p;
19548 	}
19549 	SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
19550 	if (!SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, drivername, attr)) {
19551 	    InUnError("SQLConfigDataSource");
19552 	    return FALSE;
19553 	}
19554 	if (!quiet) {
19555 	    char buf[512];
19556 
19557 	    sprintf(buf, "%s installed.", drivername);
19558 	    MessageBox(NULL, buf, "Info",
19559 		       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
19560 		       MB_SETFOREGROUND);
19561 	}
19562     } else {
19563 	InUnError("SQLInstallDriverManager");
19564 	return FALSE;
19565     }
19566     return TRUE;
19567 }
19568 
19569 /**
19570  * RunDLL32 entry point for driver installation.
19571  * @param hwnd window handle of caller
19572  * @param hinst of this DLL
19573  * @param lpszCmdLine rundll32 command line tail
19574  * @param nCmdShow ignored
19575  */
19576 
19577 void CALLBACK
install(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)19578 install(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
19579 {
19580     InUn(0, lpszCmdLine);
19581 }
19582 
19583 /**
19584  * RunDLL32 entry point for driver uninstallation.
19585  * @param hwnd window handle of caller
19586  * @param hinst of this DLL
19587  * @param lpszCmdLine rundll32 command line tail
19588  * @param nCmdShow ignored
19589  */
19590 
19591 void CALLBACK
uninstall(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)19592 uninstall(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
19593 {
19594     InUn(1, lpszCmdLine);
19595 }
19596 
19597 #endif /* WITHOUT_INSTALLER */
19598 
19599 #ifndef WITHOUT_SHELL
19600 
19601 /**
19602  * Setup argv vector from string
19603  * @param argcp pointer to argc
19604  * @param argvp pointer to argv
19605  * @param cmdline command line string
19606  * @param argv0 0th element for argv or NULL, must be static
19607  */
19608 
19609 static void
setargv(int * argcp,char *** argvp,char * cmdline,char * argv0)19610 setargv(int *argcp, char ***argvp, char *cmdline, char *argv0)
19611 {
19612     char *p, *arg, *argspace, **argv;
19613     int argc, size, inquote, copy, slashes;
19614 
19615     size = 2 + (argv0 ? 1 : 0);
19616     for (p = cmdline; *p != '\0'; p++) {
19617 	if (ISSPACE(*p)) {
19618 	    size++;
19619 	    while (ISSPACE(*p)) {
19620 		p++;
19621 	    }
19622 	    if (*p == '\0') {
19623 		break;
19624 	    }
19625 	}
19626     }
19627     argspace = malloc(size * sizeof (char *) + strlen(cmdline) + 1);
19628     argv = (char **) argspace;
19629     argspace += size * sizeof (char *);
19630     size--;
19631     argc = 0;
19632     if (argv0) {
19633 	argv[argc++] = argv0;
19634     }
19635     p = cmdline;
19636     for (; argc < size; argc++) {
19637 	argv[argc] = arg = argspace;
19638 	while (ISSPACE(*p)) {
19639 	    p++;
19640 	}
19641 	if (*p == '\0') {
19642 	    break;
19643 	}
19644 	inquote = 0;
19645 	slashes = 0;
19646 	while (1) {
19647 	    copy = 1;
19648 	    while (*p == '\\') {
19649 		slashes++;
19650 		p++;
19651 	    }
19652 	    if (*p == '"') {
19653 		if ((slashes & 1) == 0) {
19654 		    copy = 0;
19655 		    if (inquote && p[1] == '"') {
19656 			p++;
19657 			copy = 1;
19658 		    } else {
19659 			inquote = !inquote;
19660 		    }
19661 		}
19662 		slashes >>= 1;
19663 	    }
19664 	    while (slashes) {
19665 		*arg = '\\';
19666 		arg++;
19667 		slashes--;
19668 	    }
19669 	    if (*p == '\0' || (!inquote && ISSPACE(*p))) {
19670 		break;
19671 	    }
19672 	    if (copy != 0) {
19673 		*arg = *p;
19674 		arg++;
19675 	    }
19676 	    p++;
19677 	}
19678 	*arg = '\0';
19679 	argspace = arg + 1;
19680     }
19681     argv[argc] = 0;
19682     *argcp = argc;
19683     *argvp = argv;
19684 }
19685 
19686 /**
19687  * RunDLL32 entry point for SQLite shell
19688  * @param hwnd window handle of caller
19689  * @param hinst of this DLL
19690  * @param lpszCmdLine rundll32 command line tail
19691  * @param nCmdShow ignored
19692  */
19693 
19694 void CALLBACK
shell(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)19695 shell(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
19696 {
19697     int argc, needcon = 0;
19698     char **argv;
19699     extern int sqlite4_main(int, char **);
19700     static const char *name = "SQLite4 Shell";
19701     DWORD ftype0, ftype1, ftype2;
19702 
19703     ftype0 = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
19704     ftype1 = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
19705     ftype2 = GetFileType(GetStdHandle(STD_ERROR_HANDLE));
19706     if (ftype0 != FILE_TYPE_DISK && ftype0 != FILE_TYPE_CHAR &&
19707 	ftype0 != FILE_TYPE_PIPE) {
19708 	fclose(stdin);
19709 	++needcon;
19710 	ftype0 = FILE_TYPE_UNKNOWN;
19711     }
19712     if (ftype1 != FILE_TYPE_DISK && ftype1 != FILE_TYPE_CHAR &&
19713 	ftype1 != FILE_TYPE_PIPE) {
19714 	fclose(stdout);
19715 	++needcon;
19716 	ftype1 = FILE_TYPE_UNKNOWN;
19717     }
19718     if (ftype2 != FILE_TYPE_DISK && ftype2 != FILE_TYPE_CHAR &&
19719 	ftype2 != FILE_TYPE_PIPE) {
19720 	fclose(stderr);
19721 	++needcon;
19722 	ftype2 = FILE_TYPE_UNKNOWN;
19723     }
19724     if (needcon > 0) {
19725 	AllocConsole();
19726 	SetConsoleTitle(name);
19727     }
19728     if (ftype0 == FILE_TYPE_UNKNOWN) {
19729 	freopen("CONIN$", "r", stdin);
19730     }
19731     if (ftype1 == FILE_TYPE_UNKNOWN) {
19732 	freopen("CONOUT$", "w", stdout);
19733     }
19734     if (ftype2 == FILE_TYPE_UNKNOWN) {
19735 	freopen("CONOUT$", "w", stderr);
19736     }
19737     setargv(&argc, &argv, lpszCmdLine, (char *) name);
19738     sqlite4_main(argc, argv);
19739 }
19740 
19741 #endif /* WITHOUT_SHELL */
19742 
19743 #endif /* _WIN32 || _WIN64 */
19744 
19745 #if defined(HAVE_ODBCINSTEXT_H) && (HAVE_ODBCINSTEXT_H)
19746 
19747 /*
19748  * unixODBC property page for this driver,
19749  * may or may not work depending on unixODBC version.
19750  */
19751 
19752 #include <odbcinstext.h>
19753 
19754 int
ODBCINSTGetProperties(HODBCINSTPROPERTY prop)19755 ODBCINSTGetProperties(HODBCINSTPROPERTY prop)
19756 {
19757     static const char *instYN[] = { "No", "Yes", NULL };
19758     static const char *syncPragma[] = { "NORMAL", "OFF", "FULL", NULL };
19759     static const char *jmPragma[] = {
19760 	"DELETE", "PERSIST", "OFF", "TRUNCATE", "MEMORY", "WAL", NULL
19761     };
19762 
19763     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19764     prop = prop->pNext;
19765     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19766     prop->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
19767     strncpy(prop->szName, "Database", INI_MAX_PROPERTY_NAME);
19768     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
19769     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19770     prop = prop->pNext;
19771     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19772     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
19773     strncpy(prop->szName, "Timeout", INI_MAX_PROPERTY_NAME);
19774     strncpy(prop->szValue, "100000", INI_MAX_PROPERTY_VALUE);
19775     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19776     prop = prop->pNext;
19777     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19778     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19779     prop->aPromptData = malloc(sizeof (instYN));
19780     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19781     strncpy(prop->szName, "StepAPI", INI_MAX_PROPERTY_NAME);
19782     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19783     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19784     prop = prop->pNext;
19785     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19786     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19787     prop->aPromptData = malloc(sizeof (instYN));
19788     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19789     strncpy(prop->szName, "ShortNames", INI_MAX_PROPERTY_NAME);
19790     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19791     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19792     prop = prop->pNext;
19793     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19794     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19795     prop->aPromptData = malloc(sizeof (instYN));
19796     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19797     strncpy(prop->szName, "LongNames", INI_MAX_PROPERTY_NAME);
19798     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19799     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19800     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19801     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19802     prop->aPromptData = malloc(sizeof (instYN));
19803     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19804     strncpy(prop->szName, "NoCreat", INI_MAX_PROPERTY_NAME);
19805     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19806 #ifdef WINTERFACE
19807     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19808     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19809     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19810     prop->aPromptData = malloc(sizeof (instYN));
19811     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19812     strncpy(prop->szName, "NoWCHAR", INI_MAX_PROPERTY_NAME);
19813     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19814 #endif
19815     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19816     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19817     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19818     prop->aPromptData = malloc(sizeof (instYN));
19819     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19820     strncpy(prop->szName, "FKSupport", INI_MAX_PROPERTY_NAME);
19821     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19822     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19823     prop = prop->pNext;
19824     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19825     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19826     prop->aPromptData = malloc(sizeof (syncPragma));
19827     memcpy(prop->aPromptData, syncPragma, sizeof (syncPragma));
19828     strncpy(prop->szName, "SyncPragma", INI_MAX_PROPERTY_NAME);
19829     strncpy(prop->szValue, "NORMAL", INI_MAX_PROPERTY_VALUE);
19830     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19831     prop = prop->pNext;
19832     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19833     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19834     prop->aPromptData = malloc(sizeof (jmPragma));
19835     memcpy(prop->aPromptData, jmPragma, sizeof (jmPragma));
19836     strncpy(prop->szName, "JournalMode", INI_MAX_PROPERTY_NAME);
19837     strncpy(prop->szValue, "DELETE", INI_MAX_PROPERTY_VALUE);
19838     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19839     prop = prop->pNext;
19840     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19841     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
19842     strncpy(prop->szName, "LoadExt", INI_MAX_PROPERTY_NAME);
19843     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
19844     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
19845     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
19846     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
19847     prop->aPromptData = malloc(sizeof (instYN));
19848     memcpy(prop->aPromptData, instYN, sizeof (instYN));
19849     strncpy(prop->szName, "BigInt", INI_MAX_PROPERTY_NAME);
19850     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
19851     return 1;
19852 }
19853 
19854 #endif /* HAVE_ODBCINSTEXT_H */
19855 
19856 #ifdef SQLITE_DYNLOAD
19857 
19858 /*
19859  * SQLite4 shared library/DLL stubs.
19860  */
19861 
19862 static void
dls_void(void)19863 dls_void(void)
19864 {
19865 }
19866 
19867 static int
dls_error(void)19868 dls_error(void)
19869 {
19870     return SQLITE4_ERROR;
19871 }
19872 
19873 static int
dls_0(void)19874 dls_0(void)
19875 {
19876     return 0;
19877 }
19878 
19879 #if 0
19880 static sqlite4_int64
19881 dls_0LL(void)
19882 {
19883     return 0;
19884 }
19885 #endif
19886 
19887 static double
dls_00(void)19888 dls_00(void)
19889 {
19890     return 0;
19891 }
19892 
19893 static void *
dls_null(void)19894 dls_null(void)
19895 {
19896     return NULL;
19897 }
19898 
19899 static const char *
dls_empty(void)19900 dls_empty(void)
19901 {
19902     return "";
19903 }
19904 
19905 static int
dls_snull(void)19906 dls_snull(void)
19907 {
19908     return SQLITE4_NULL;
19909 }
19910 
19911 #define DLS_ENT(name, func)						\
19912     { "sqlite4_" #name, offsetof(struct dl_sqlite4_funcs, name),	\
19913       (void *) func }
19914 
19915 #define DLS_ENT3(name, off, func)					\
19916     { "sqlite4_" #name, offsetof(struct dl_sqlite4_funcs, off),		\
19917       (void *) func }
19918 
19919 #define DLS_END { NULL, 0, NULL }
19920 
19921 static struct {
19922     const char *name;
19923     int offset;
19924     void *func;
19925 } dls_nametab[] = {
19926     DLS_ENT(bind_blob, dls_error),
19927     DLS_ENT(bind_double, dls_error),
19928     DLS_ENT(bind_int, dls_error),
19929     DLS_ENT(bind_int64, dls_error),
19930     DLS_ENT(bind_null, dls_error),
19931     DLS_ENT(bind_parameter_count, dls_0),
19932     DLS_ENT(bind_text, dls_error),
19933     DLS_ENT(changes, dls_0),
19934     DLS_ENT(close, dls_error),
19935     DLS_ENT(column_blob, dls_null),
19936     DLS_ENT(column_bytes, dls_0),
19937     DLS_ENT(column_count, dls_0),
19938     DLS_ENT(column_database_name, dls_empty),
19939     DLS_ENT(column_decltype, dls_empty),
19940     DLS_ENT(column_double, dls_00),
19941     DLS_ENT(column_name, dls_empty),
19942     DLS_ENT(column_origin_name, dls_null),
19943     DLS_ENT(column_table_name, dls_null),
19944     DLS_ENT(column_text, dls_null),
19945     DLS_ENT(column_type, dls_snull),
19946     DLS_ENT(create_function, dls_error),
19947     DLS_ENT(errcode, dls_error),
19948     DLS_ENT(errmsg, dls_empty),
19949     DLS_ENT(exec, dls_error),
19950     DLS_ENT(finalize, dls_error),
19951     DLS_ENT(free, free),
19952     DLS_ENT(interrupt, dls_void),
19953 #if 0
19954     DLS_ENT(last_insert_rowid, dls_0LL),
19955 #endif
19956     DLS_ENT(libversion, dls_empty),
19957 #if 0
19958     DLS_ENT(load_extension, dls_error),
19959 #endif
19960     DLS_ENT(malloc, malloc),
19961     DLS_ENT(mprintf, dls_null),
19962     DLS_ENT(open, dls_error),
19963     DLS_ENT(prepare, dls_error),
19964     DLS_ENT(profile, dls_null),
19965     DLS_ENT(realloc, realloc),
19966     DLS_ENT(reset, dls_error),
19967     DLS_ENT(result_blob, dls_void),
19968     DLS_ENT(result_error, dls_void),
19969     DLS_ENT(result_int, dls_void),
19970     DLS_ENT(result_null, dls_void),
19971     DLS_ENT(step, dls_error),
19972 #if defined(_WIN32) || defined(_WIN64)
19973     DLS_ENT3(strnicmp, xstrnicmp, _strnicmp),
19974 #else
19975     DLS_ENT3(strnicmp, xstrnicmp, strncasecmp),
19976 #endif
19977 #if 0
19978     DLS_ENT(table_column_metadata, dls_error),
19979 #endif
19980     DLS_ENT(trace, dls_null),
19981     DLS_ENT(user_data, dls_null),
19982     DLS_ENT(value_blob, dls_null),
19983     DLS_ENT(value_bytes, dls_0),
19984     DLS_ENT(value_text, dls_empty),
19985     DLS_ENT(value_type, dls_snull),
19986     DLS_END
19987 };
19988 
19989 #if defined(_WIN32) || defined(_WIN64)
19990 
19991 static HMODULE sqlite4_dll = 0;
19992 
19993 static void
dls_init(void)19994 dls_init(void)
19995 {
19996     int i;
19997     static const char *dll_names[] = {
19998 	"System.Data.SQLite.dll",
19999 	"sqlite4.dll",
20000 	NULL,
20001     };
20002 
20003     i = 0;
20004     while (dll_names[i]) {
20005 	sqlite4_dll = LoadLibrary(dll_names[i]);
20006 	if (sqlite4_dll) {
20007 	    break;
20008 	}
20009 	++i;
20010     }
20011     i = 0;
20012     while (dls_nametab[i].name) {
20013 	void *func = 0, **loc;
20014 
20015 	if (sqlite4_dll) {
20016 	    func = (void *) GetProcAddress(sqlite4_dll, dls_nametab[i].name);
20017 	}
20018 	if (!func) {
20019 	    func = dls_nametab[i].func;
20020 	}
20021 	loc = (void **) ((char *) &dls_funcs + dls_nametab[i].offset);
20022 	*loc = func;
20023 	++i;
20024     }
20025     if (!sqlite4_dll) {
20026 	char buf[MAXPATHLEN], msg[MAXPATHLEN];
20027 
20028 	LoadString(hModule, IDS_DRVTITLE, buf, sizeof (buf));
20029 	LoadString(hModule, IDS_DLLERR, msg, sizeof (msg));
20030 	MessageBox(NULL, msg, buf,
20031 		   MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
20032 		   MB_SETFOREGROUND);
20033     }
20034 }
20035 
20036 static void
dls_fini(void)20037 dls_fini(void)
20038 {
20039     if (sqlite4_dll) {
20040 	FreeLibrary(sqlite4_dll);
20041 	sqlite4_dll = 0;
20042     }
20043 }
20044 
20045 #else
20046 
20047 #include <dlfcn.h>
20048 
20049 static void *libsqlite4_so = 0;
20050 
20051 void
dls_init(void)20052 dls_init(void)
20053 {
20054     int i;
20055 
20056     libsqlite4_so = dlopen("libsqlite4.so.0", RTLD_NOW | RTLD_GLOBAL);
20057     i = 0;
20058     while (dls_nametab[i].name) {
20059 	void *func = 0, **loc;
20060 
20061 	if (libsqlite4_so) {
20062 	    func = dlsym(libsqlite4_so, dls_nametab[i].name);
20063 	}
20064 	if (!func) {
20065 	    func = dls_nametab[i].func;
20066 	}
20067 	loc = (void **) ((char *) &dls_funcs + dls_nametab[i].offset);
20068 	*loc = func;
20069 	++i;
20070     }
20071     if (!libsqlite4_so) {
20072 	const char errmsg[] = "sqlite4 shared library not found.\n";
20073 
20074 	write(2, errmsg, sizeof (errmsg) - 1);
20075     }
20076 }
20077 
20078 void
dls_fini(void)20079 dls_fini(void)
20080 {
20081     if (libsqlite4_so) {
20082 	dlclose(libsqlite4_so);
20083 	libsqlite4_so = 0;
20084     }
20085 }
20086 
20087 #endif
20088 
20089 #endif
20090 
20091 /*
20092  * Local Variables:
20093  * mode: c
20094  * c-basic-offset: 4
20095  * fill-column: 78
20096  * tab-width: 8
20097  * End:
20098  */
20099