1 /**
2  * @file sqliteodbc.c
3  * SQLite ODBC Driver main module.
4  *
5  * $Id: sqliteodbc.c,v 1.225 2020/06/20 11:56:09 chw Exp chw $
6  *
7  * Copyright (c) 2001-2020 Christian Werner <chw@ch-werner.de>
8  * OS/2 Port Copyright (c) 2004 Lorne R. Sunley <lsunley@mb.sympatico.ca>
9  *
10  * See the file "license.terms" for information on usage
11  * and redistribution of this file and for a
12  * DISCLAIMER OF ALL WARRANTIES.
13  */
14 
15 #include "sqliteodbc.h"
16 
17 #ifdef  SQLITE_UTF8
18 #ifndef WITHOUT_WINTERFACE
19 #define WINTERFACE
20 #define WCHARSUPPORT
21 #endif
22 #endif
23 
24 #ifdef SQLITE_UTF8
25 #if !defined(_WIN32) && !defined(_WIN64)
26 #if !defined(WCHARSUPPORT) && defined(HAVE_SQLWCHAR) && (HAVE_SQLWCHAR)
27 #define WCHARSUPPORT
28 #endif
29 #endif
30 #endif
31 
32 #if defined(WINTERFACE)
33 #include <sqlucode.h>
34 #endif
35 
36 #if defined(_WIN32) || defined(_WIN64)
37 #include "resource.h"
38 #define ODBC_INI "ODBC.INI"
39 #ifndef DRIVER_VER_INFO
40 #define DRIVER_VER_INFO VERSION
41 #endif
42 #else
43 #ifdef __OS2__
44 #define ODBC_INI "ODBC.INI"
45 #else
46 #define ODBC_INI ".odbc.ini"
47 #endif
48 #endif
49 
50 #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 3)))
51 #define	CANT_PASS_VALIST_AS_CHARPTR 1
52 #endif
53 
54 #ifdef _WIN64
55 #undef  CANT_PASS_VALIST_AS_CHARPTR
56 #define CANT_PASS_VALIST_AS_CHARPTR 1
57 #endif
58 
59 #ifdef CANT_PASS_VALIST_AS_CHARPTR
60 #define MAX_PARAMS_FOR_VPRINTF 32
61 #endif
62 
63 #ifndef DRIVER_VER_INFO
64 #define DRIVER_VER_INFO "0.0"
65 #endif
66 
67 #ifndef COLATTRIBUTE_LAST_ARG_TYPE
68 #ifdef _WIN64
69 #define COLATTRIBUTE_LAST_ARG_TYPE SQLLEN *
70 #else
71 #define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
72 #endif
73 #endif
74 
75 #ifndef SETSTMTOPTION_LAST_ARG_TYPE
76 #define SETSTMTOPTION_LAST_ARG_TYPE SQLROWCOUNT
77 #endif
78 
79 #undef min
80 #define min(a, b) ((a) < (b) ? (a) : (b))
81 #undef max
82 #define max(a, b) ((a) < (b) ? (b) : (a))
83 
84 #ifndef PTRDIFF_T
85 #define PTRDIFF_T int
86 #endif
87 
88 #define array_size(x) (sizeof (x) / sizeof (x[0]))
89 
90 #define stringify1(s) #s
91 #define stringify(s) stringify1(s)
92 
93 #define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
94 
95 /* Column types for static string column descriptions (SQLTables etc.) */
96 
97 #if defined(WINTERFACE) && !defined(_WIN32) && !defined(_WIN64)
98 #define SCOL_VARCHAR SQL_WVARCHAR
99 #define SCOL_CHAR SQL_WCHAR
100 #else
101 #define SCOL_VARCHAR SQL_VARCHAR
102 #define SCOL_CHAR SQL_CHAR
103 #endif
104 
105 #define ENV_MAGIC  0x53544145
106 #define DBC_MAGIC  0x53544144
107 #define DEAD_MAGIC 0xdeadbeef
108 
109 #ifdef MEMORY_DEBUG
110 
111 static void *
xmalloc_(int n,char * file,int line)112 xmalloc_(int n, char *file, int line)
113 {
114     int nn = n + 4 * sizeof (long);
115     long *p;
116 
117     p = malloc(nn);
118     if (!p) {
119 #if (MEMORY_DEBUG > 1)
120 	fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
121 #endif
122 	return NULL;
123     }
124     p[0] = 0xdead1234;
125     nn = nn / sizeof (long) - 1;
126     p[1] = n;
127     p[nn] = 0xdead5678;
128 #if (MEMORY_DEBUG > 1)
129     fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
130 #endif
131     return (void *) &p[2];
132 }
133 
134 static void *
xrealloc_(void * old,int n,char * file,int line)135 xrealloc_(void *old, int n, char *file, int line)
136 {
137     int nn = n + 4 * sizeof (long), nnn;
138     long *p, *pp;
139 
140     if (n == 0 || !old) {
141 	return xmalloc_(n, file, line);
142     }
143     p = &((long *) old)[-2];
144     if (p[0] != 0xdead1234) {
145 	fprintf(stderr, "*** low end corruption @ %p\n", old);
146 	abort();
147     }
148     nnn = p[1] + 4 * sizeof (long);
149     nnn = nnn / sizeof (long) - 1;
150     if (p[nnn] != 0xdead5678) {
151 	fprintf(stderr, "*** high end corruption @ %p\n", old);
152 	abort();
153     }
154     pp = realloc(p, nn);
155     if (!pp) {
156 #if (MEMORY_DEBUG > 1)
157 	fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
158 #endif
159 	return NULL;
160     }
161 #if (MEMORY_DEBUG > 1)
162     fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
163 #endif
164     p = pp;
165     p[1] = n;
166     nn = nn / sizeof (long) - 1;
167     p[nn] = 0xdead5678;
168     return (void *) &p[2];
169 }
170 
171 static void
xfree_(void * x,char * file,int line)172 xfree_(void *x, char *file, int line)
173 {
174     long *p;
175     int n;
176 
177     if (!x) {
178 	return;
179     }
180     p = &((long *) x)[-2];
181     if (p[0] != 0xdead1234) {
182 	fprintf(stderr, "*** low end corruption @ %p\n", x);
183 	abort();
184     }
185     n = p[1] + 4 * sizeof (long);
186     n = n / sizeof (long) - 1;
187     if (p[n] != 0xdead5678) {
188 	fprintf(stderr, "*** high end corruption @ %p\n", x);
189 	abort();
190     }
191 #if (MEMORY_DEBUG > 1)
192     fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
193 #endif
194     free(p);
195 }
196 
197 static void
xfree__(void * x)198 xfree__(void *x)
199 {
200     xfree_(x, "unknown location", 0);
201 }
202 
203 static char *
xstrdup_(const char * str,char * file,int line)204 xstrdup_(const char *str, char *file, int line)
205 {
206     char *p;
207 
208     if (!str) {
209 #if (MEMORY_DEBUG > 1)
210 	fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
211 #endif
212 	return NULL;
213     }
214     p = xmalloc_(strlen(str) + 1, file, line);
215     if (p) {
216 	strcpy(p, str);
217     }
218 #if (MEMORY_DEBUG > 1)
219     fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
220 #endif
221     return p;
222 }
223 
224 #define xmalloc(x)    xmalloc_(x, __FILE__, __LINE__)
225 #define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
226 #define xfree(x)      xfree_(x, __FILE__, __LINE__)
227 #define xstrdup(x)    xstrdup_(x, __FILE__, __LINE__)
228 
229 #else
230 
231 #define xmalloc(x)    malloc(x)
232 #define xrealloc(x,y) realloc(x, y)
233 #define xfree(x)      free(x)
234 #define xstrdup(x)    strdup_(x)
235 
236 #endif
237 
238 #if defined(_WIN32) || defined(_WIN64)
239 
240 #define vsnprintf   _vsnprintf
241 #define snprintf    _snprintf
242 #define strcasecmp  _stricmp
243 #define strncasecmp _strnicmp
244 
245 static HINSTANCE NEAR hModule;	/* Saved module handle for resources */
246 
247 #endif
248 
249 #if defined(_WIN32) || defined(_WIN64)
250 
251 /*
252  * SQLHENV, SQLHDBC, and SQLHSTMT synchronization
253  * is done using a critical section in ENV structure.
254  */
255 
256 #define HDBC_LOCK(hdbc)				\
257 {						\
258     DBC *d;					\
259 						\
260     if ((hdbc) == SQL_NULL_HDBC) {		\
261 	return SQL_INVALID_HANDLE;		\
262     }						\
263     d = (DBC *) (hdbc);				\
264     if (d->magic != DBC_MAGIC) {		\
265 	return SQL_INVALID_HANDLE;		\
266     }						\
267     EnterCriticalSection(&d->cs);		\
268     d->owner = GetCurrentThreadId();		\
269 }
270 
271 #define HDBC_UNLOCK(hdbc)			\
272     if ((hdbc) != SQL_NULL_HDBC) {		\
273 	DBC *d;					\
274 						\
275 	d = (DBC *) (hdbc);			\
276 	if (d->magic == DBC_MAGIC) {		\
277 	    d->owner = 0;			\
278 	    LeaveCriticalSection(&d->cs);	\
279 	}					\
280     }
281 
282 #define HSTMT_LOCK(hstmt)			\
283 {						\
284     DBC *d;					\
285 						\
286     if ((hstmt) == SQL_NULL_HSTMT) {		\
287 	return SQL_INVALID_HANDLE;		\
288     }						\
289     d = (DBC *) ((STMT *) (hstmt))->dbc;	\
290     if (d->magic != DBC_MAGIC) {		\
291 	return SQL_INVALID_HANDLE;		\
292     }						\
293     EnterCriticalSection(&d->cs);		\
294     d->owner = GetCurrentThreadId();		\
295 }
296 
297 #define HSTMT_UNLOCK(hstmt)			\
298     if ((hstmt) != SQL_NULL_HSTMT) {		\
299 	DBC *d;					\
300 						\
301 	d = (DBC *) ((STMT *) (hstmt))->dbc;	\
302 	if (d->magic == DBC_MAGIC) {		\
303 	    d->owner = 0;			\
304 	    LeaveCriticalSection(&d->cs);	\
305 	}					\
306     }
307 
308 #else
309 
310 /*
311  * On UN*X assume that we are single-threaded or
312  * the driver manager provides serialization for us.
313  *
314  * In iODBC (3.52.x) serialization can be turned
315  * on using the DSN property "ThreadManager=yes".
316  *
317  * In unixODBC that property is named
318  * "Threading=0-3" and takes one of these values:
319  *
320  *   0 - no protection
321  *   1 - statement level protection
322  *   2 - connection level protection
323  *   3 - environment level protection
324  *
325  * unixODBC 2.2.11 uses environment level protection
326  * by default when it has been built with pthread
327  * support.
328  */
329 
330 #define HDBC_LOCK(hdbc)
331 #define HDBC_UNLOCK(hdbc)
332 #define HSTMT_LOCK(hdbc)
333 #define HSTMT_UNLOCK(hdbc)
334 
335 #endif
336 
337 /*
338  * tolower() replacement w/o locale
339  */
340 
341 static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
342 static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
343 
344 static int
TOLOWER(int c)345 TOLOWER(int c)
346 {
347     if (c) {
348 	char *p = strchr(upper_chars, c);
349 
350 	if (p) {
351 	    c = lower_chars[p - upper_chars];
352 	}
353     }
354     return c;
355 }
356 
357 /*
358  * isdigit() replacement w/o ctype.h
359  */
360 
361 static const char digit_chars[] = "0123456789";
362 
363 #define ISDIGIT(c) \
364     ((c) && strchr(digit_chars, (c)) != NULL)
365 
366 /*
367  * isspace() replacement w/o ctype.h
368  */
369 
370 static const char space_chars[] = " \f\n\r\t\v";
371 
372 #define ISSPACE(c) \
373     ((c) && strchr(space_chars, (c)) != NULL)
374 
375 /*
376  * Characters in named parameters
377  */
378 
379 static const char id_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
380 			       "abcdefghijklmnopqrstuvwxyz"
381 			       "_0123456789";
382 
383 #define ISIDCHAR(c) \
384     ((c) && strchr(id_chars, (c)) != NULL)
385 
386 /*
387  * Forward declarations of static functions.
388  */
389 
390 static void freedyncols(STMT *s);
391 static void freeresult(STMT *s, int clrcols);
392 static void unbindcols(STMT *s);
393 
394 static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
395 static SQLRETURN freestmt(HSTMT stmt);
396 static SQLRETURN mkbindcols(STMT *s, int ncols);
397 static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
398 static SQLRETURN starttran(STMT *s);
399 static SQLRETURN substparam(STMT *s, int pnum, char **outp);
400 
401 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
402 /* MS Access hack part 1 (reserved error -7748) */
403 static COL *statSpec2P, *statSpec3P;
404 #endif
405 
406 #if (MEMORY_DEBUG < 1)
407 /**
408  * Duplicate string using xmalloc().
409  * @param str string to be duplicated
410  * @result pointer to new string or NULL
411  */
412 
413 static char *
strdup_(const char * str)414 strdup_(const char *str)
415 {
416     char *p = NULL;
417 
418     if (str) {
419 	p = xmalloc(strlen(str) + 1);
420 	if (p) {
421 	    strcpy(p, str);
422 	}
423     }
424     return p;
425 }
426 #endif
427 
428 #ifdef WCHARSUPPORT
429 /**
430  * Return length of UNICODE string.
431  * @param str UNICODE string
432  * @result length of string in characters
433  */
434 
435 static int
uc_strlen(SQLWCHAR * str)436 uc_strlen(SQLWCHAR *str)
437 {
438     int len = 0;
439 
440     if (str) {
441 	while (*str) {
442 	    ++len;
443 	    ++str;
444 	}
445     }
446     return len;
447 }
448 
449 /**
450  * Copy UNICODE string like strncpy().
451  * @param dest destination area
452  * @param src source area
453  * @param len length of source area in characters
454  * @return pointer to destination area
455  */
456 
457 static SQLWCHAR *
uc_strncpy(SQLWCHAR * dest,SQLWCHAR * src,int len)458 uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
459 {
460     int i = 0;
461 
462     while (i < len) {
463 	if (!src[i]) {
464 	    break;
465 	}
466 	dest[i] = src[i];
467 	++i;
468     }
469     if (i < len) {
470 	dest[i] = 0;
471     }
472     return dest;
473 }
474 
475 /**
476  * Make UNICODE string from UTF8 string into buffer.
477  * @param str UTF8 string to be converted
478  * @param len length in characters of str or -1
479  * @param uc destination area to receive UNICODE string
480  * @param ucLen byte length of destination area
481  */
482 
483 static void
uc_from_utf_buf(unsigned char * str,int len,SQLWCHAR * uc,int ucLen)484 uc_from_utf_buf(unsigned char *str, int len, SQLWCHAR *uc, int ucLen)
485 {
486     ucLen = ucLen / sizeof (SQLWCHAR);
487     if (!uc || ucLen < 0) {
488 	return;
489     }
490     if (len < 0) {
491 	len = ucLen * 5;
492     }
493     uc[0] = 0;
494     if (str) {
495 	int i = 0;
496 
497 	while (i < len && *str && i < ucLen) {
498 	    unsigned char c = str[0];
499 
500 	    if (c < 0x80) {
501 		uc[i++] = c;
502 		++str;
503 	    } else if (c <= 0xc1 || c >= 0xf5) {
504 		/* illegal, ignored */
505 		++str;
506 	    } else if (c < 0xe0) {
507 		if ((str[1] & 0xc0) == 0x80) {
508 		    unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
509 
510 		    uc[i++] = t;
511 		    str += 2;
512 		} else {
513 		    uc[i++] = c;
514 		    ++str;
515 		}
516 	    } else if (c < 0xf0) {
517 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
518 		    unsigned long t = ((c & 0x0f) << 12) |
519 			((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
520 
521 		    uc[i++] = t;
522 		    str += 3;
523 		} else {
524 		    uc[i++] = c;
525 		    ++str;
526 		}
527 	    } else if (c < 0xf8) {
528 		if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
529 		    (str[3] & 0xc0) == 0x80) {
530 		    unsigned long t = ((c & 0x03) << 18) |
531 			((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
532 			(str[3] & 0x3f);
533 
534 		    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
535 			t >= 0x10000) {
536 			t -= 0x10000;
537 			uc[i++] = 0xd800 | ((t >> 10) & 0x3ff);
538 			if (i >= ucLen) {
539 			    break;
540 			}
541 			t = 0xdc00 | (t & 0x3ff);
542 		    }
543 		    uc[i++] = t;
544 		    str += 4;
545 		} else {
546 		    uc[i++] = c;
547 		    ++str;
548 		}
549 	    } else {
550 		/* ignore */
551 		++str;
552 	    }
553 	}
554 	if (i < ucLen) {
555 	    uc[i] = 0;
556 	}
557     }
558 }
559 
560 /**
561  * Make UNICODE string from UTF8 string.
562  * @param str UTF8 string to be converted
563  * @param len length of UTF8 string
564  * @return alloc'ed UNICODE string to be free'd by uc_free()
565  */
566 
567 static SQLWCHAR *
uc_from_utf(unsigned char * str,int len)568 uc_from_utf(unsigned char *str, int len)
569 {
570     SQLWCHAR *uc = NULL;
571     int ucLen;
572 
573     if (str) {
574 	if (len == SQL_NTS) {
575 	    len = strlen((char *) str);
576 	}
577 	ucLen = sizeof (SQLWCHAR) * (len + 1);
578 	uc = xmalloc(ucLen);
579 	if (uc) {
580 	    uc_from_utf_buf(str, len, uc, ucLen);
581 	}
582     }
583     return uc;
584 }
585 
586 /**
587  * Make UTF8 string from UNICODE string.
588  * @param str UNICODE string to be converted
589  * @param len length of UNICODE string in bytes
590  * @return alloc'ed UTF8 string to be free'd by uc_free()
591  */
592 
593 static char *
uc_to_utf(SQLWCHAR * str,int len)594 uc_to_utf(SQLWCHAR *str, int len)
595 {
596     int i;
597     char *cp, *ret = NULL;
598 
599     if (!str) {
600 	return ret;
601     }
602     if (len == SQL_NTS) {
603 	len = uc_strlen(str);
604     } else {
605 	len = len / sizeof (SQLWCHAR);
606     }
607     cp = xmalloc(len * 6 + 1);
608     if (!cp) {
609 	return ret;
610     }
611     ret = cp;
612     for (i = 0; i < len; i++) {
613 	unsigned long c = str[i];
614 
615 	if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
616 	    c &= 0xffff;
617 	}
618 	if (c < 0x80) {
619 	    *cp++ = c;
620 	} else if (c < 0x800) {
621 	    *cp++ = 0xc0 | ((c >> 6) & 0x1f);
622 	    *cp++ = 0x80 | (c & 0x3f);
623 	} else if (c < 0x10000) {
624 	    if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
625 		c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
626 		unsigned long c2 = str[i + 1] & 0xffff;
627 
628 		if (c2 >= 0xdc00 && c2 <= 0xdfff) {
629 		    c = (((c & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10000;
630 		    *cp++ = 0xf0 | ((c >> 18) & 0x07);
631 		    *cp++ = 0x80 | ((c >> 12) & 0x3f);
632 		    *cp++ = 0x80 | ((c >> 6) & 0x3f);
633 		    *cp++ = 0x80 | (c & 0x3f);
634 		    ++i;
635 		    continue;
636 		}
637 	    }
638 	    *cp++ = 0xe0 | ((c >> 12) & 0x0f);
639 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
640 	    *cp++ = 0x80 | (c & 0x3f);
641 	} else if (c <= 0x10ffff) {
642 	    *cp++ = 0xf0 | ((c >> 18) & 0x07);
643 	    *cp++ = 0x80 | ((c >> 12) & 0x3f);
644 	    *cp++ = 0x80 | ((c >> 6) & 0x3f);
645 	    *cp++ = 0x80 | (c & 0x3f);
646 	}
647     }
648     *cp = '\0';
649     return ret;
650 }
651 
652 #endif
653 
654 #ifdef WINTERFACE
655 
656 /**
657  * Make UTF8 string from UNICODE string.
658  * @param str UNICODE string to be converted
659  * @param len length of UNICODE string in characters
660  * @return alloc'ed UTF8 string to be free'd by uc_free()
661  */
662 
663 static char *
uc_to_utf_c(SQLWCHAR * str,int len)664 uc_to_utf_c(SQLWCHAR *str, int len)
665 {
666     if (len != SQL_NTS) {
667 	len = len * sizeof (SQLWCHAR);
668     }
669     return uc_to_utf(str, len);
670 }
671 
672 #endif
673 
674 #if defined(WINTERFACE) || defined(WCHARSUPPORT)
675 
676 /**
677  * Free converted UTF8 or UNICODE string.
678  */
679 
680 static void
uc_free(void * str)681 uc_free(void *str)
682 {
683     if (str) {
684 	xfree(str);
685     }
686 }
687 
688 #endif
689 
690 #ifdef USE_DLOPEN_FOR_GPPS
691 
692 #include <dlfcn.h>
693 
694 #define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
695 
696 /*
697  * EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
698  * dlopen(), in theory this makes the driver independent from the
699  * driver manager, i.e. the same driver binary can run with iODBC
700  * and unixODBC.
701  */
702 
703 static void
drvgetgpps(DBC * d)704 drvgetgpps(DBC *d)
705 {
706     void *lib;
707     int (*gpps)();
708 
709     lib = dlopen("libodbcinst.so.2", RTLD_LAZY);
710     if (!lib) {
711 	lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
712     }
713     if (!lib) {
714 	lib = dlopen("libodbcinst.so", RTLD_LAZY);
715     }
716     if (!lib) {
717 	lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
718     }
719     if (!lib) {
720 	lib = dlopen("libiodbcinst.so", RTLD_LAZY);
721     }
722     if (lib) {
723 	gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
724 	if (!gpps) {
725 	    dlclose(lib);
726 	    return;
727 	}
728 	d->instlib = lib;
729 	d->gpps = gpps;
730     }
731 }
732 
733 static void
drvrelgpps(DBC * d)734 drvrelgpps(DBC *d)
735 {
736     if (d->instlib) {
737 	dlclose(d->instlib);
738 	d->instlib = 0;
739     }
740 }
741 
742 static int
drvgpps(DBC * d,char * sect,char * ent,char * def,char * buf,int bufsiz,char * fname)743 drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
744 	int bufsiz, char *fname)
745 {
746     if (d->gpps) {
747 	return d->gpps(sect, ent, def, buf, bufsiz, fname);
748     }
749     strncpy(buf, def, bufsiz);
750     buf[bufsiz - 1] = '\0';
751     return 1;
752 }
753 #else
754 #include <odbcinst.h>
755 #define drvgetgpps(d)
756 #define drvrelgpps(d)
757 #endif
758 
759 /**
760  * Set error message and SQL state on DBC
761  * @param d database connection pointer
762  * @param naterr native error code
763  * @param msg error message
764  * @param st SQL state
765  */
766 
767 #if defined(__GNUC__) && (__GNUC__ >= 2)
768 static void setstatd(DBC *, int, char *, char *, ...)
769     __attribute__((format (printf, 3, 5)));
770 #endif
771 
772 static void
setstatd(DBC * d,int naterr,char * msg,char * st,...)773 setstatd(DBC *d, int naterr, char *msg, char *st, ...)
774 {
775     va_list ap;
776 
777     if (!d) {
778 	return;
779     }
780     d->naterr = naterr;
781     d->logmsg[0] = '\0';
782     if (msg) {
783 	int count;
784 
785 	va_start(ap, st);
786 	count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
787 	va_end(ap);
788 	if (count < 0) {
789 	    d->logmsg[sizeof (d->logmsg) - 1] = '\0';
790 	}
791     }
792     if (!st) {
793 	st = "?????";
794     }
795     strncpy(d->sqlstate, st, 5);
796     d->sqlstate[5] = '\0';
797 }
798 
799 /**
800  * Set error message and SQL state on statement
801  * @param s statement pointer
802  * @param naterr native error code
803  * @param msg error message
804  * @param st SQL state
805  */
806 
807 #if defined(__GNUC__) && (__GNUC__ >= 2)
808 static void setstat(STMT *, int, char *, char *, ...)
809     __attribute__((format (printf, 3, 5)));
810 #endif
811 
812 static void
setstat(STMT * s,int naterr,char * msg,char * st,...)813 setstat(STMT *s, int naterr, char *msg, char *st, ...)
814 {
815     va_list ap;
816 
817     if (!s) {
818 	return;
819     }
820     s->naterr = naterr;
821     s->logmsg[0] = '\0';
822     if (msg) {
823 	int count;
824 
825 	va_start(ap, st);
826 	count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
827 	va_end(ap);
828 	if (count < 0) {
829 	    s->logmsg[sizeof (s->logmsg) - 1] = '\0';
830 	}
831     }
832     if (!st) {
833 	st = "?????";
834     }
835     strncpy(s->sqlstate, st, 5);
836     s->sqlstate[5] = '\0';
837 }
838 
839 /**
840  * Report IM001 (not implemented) SQL error code for HDBC.
841  * @param dbc database connection handle
842  * @result ODBC error code
843  */
844 
845 static SQLRETURN
drvunimpldbc(HDBC dbc)846 drvunimpldbc(HDBC dbc)
847 {
848     DBC *d;
849 
850     if (dbc == SQL_NULL_HDBC) {
851 	return SQL_INVALID_HANDLE;
852     }
853     d = (DBC *) dbc;
854     setstatd(d, -1, "not supported", "IM001");
855     return SQL_ERROR;
856 }
857 
858 /**
859  * Report IM001 (not implemented) SQL error code for HSTMT.
860  * @param stmt statement handle
861  * @result ODBC error code
862  */
863 
864 static SQLRETURN
drvunimplstmt(HSTMT stmt)865 drvunimplstmt(HSTMT stmt)
866 {
867     STMT *s;
868 
869     if (stmt == SQL_NULL_HSTMT) {
870 	return SQL_INVALID_HANDLE;
871     }
872     s = (STMT *) stmt;
873     setstat(s, -1, "not supported", "IM001");
874     return SQL_ERROR;
875 }
876 
877 /**
878  * Free memory given pointer to memory pointer.
879  * @param x pointer to pointer to memory to be free'd
880  */
881 
882 static void
freep(void * x)883 freep(void *x)
884 {
885     if (x && ((char **) x)[0]) {
886 	xfree(((char **) x)[0]);
887 	((char **) x)[0] = NULL;
888     }
889 }
890 
891 /**
892  * Report S1000 (out of memory) SQL error given STMT.
893  * @param s statement pointer
894  * @result ODBC error code
895  */
896 
897 static SQLRETURN
nomem(STMT * s)898 nomem(STMT *s)
899 {
900     setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
901     return SQL_ERROR;
902 }
903 
904 /**
905  * Report S1000 (not connected) SQL error given STMT.
906  * @param s statement pointer
907  * @result ODBC error code
908  */
909 
910 static SQLRETURN
noconn(STMT * s)911 noconn(STMT *s)
912 {
913     setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
914     return SQL_ERROR;
915 }
916 
917 /**
918  * Internal locale neutral strtod function.
919  * @param data pointer to string
920  * @param endp pointer for ending character
921  * @result double value
922  */
923 
924 #if defined(HAVE_SQLITEATOF) && (HAVE_SQLITEATOF)
925 
926 extern double sqliteAtoF(char *data, char **endp);
927 
928 #define ln_strtod(A,B) sqliteAtoF(A,B)
929 
930 #else
931 
932 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
933 
934 static double
ln_strtod(const char * data,char ** endp)935 ln_strtod(const char *data, char **endp)
936 {
937     struct lconv *lc = 0;
938     char buf[128], *p, *end;
939     double value;
940 
941     lc = localeconv();
942     if (lc && lc->decimal_point && lc->decimal_point[0] &&
943 	lc->decimal_point[0] != '.') {
944 	strncpy(buf, data, sizeof (buf) - 1);
945 	buf[sizeof (buf) - 1] = '\0';
946 	p = strchr(buf, '.');
947 	if (p) {
948 	    *p = lc->decimal_point[0];
949 	}
950 	p = buf;
951     } else {
952 	p = (char *) data;
953     }
954     value = strtod(p, &end);
955     end = (char *) data + (end - p);
956     if (endp) {
957 	*endp = end;
958     }
959     return value;
960 }
961 
962 #else
963 
964 #define ln_strtod(A,B) strtod(A,B)
965 
966 #endif
967 
968 #endif
969 
970 #if !defined(HAVE_SQLITEMPRINTF) || !(HAVE_SQLITEMPRINTF)
971 /**
972  * Internal locale neutral sprintf("%g") function.
973  * @param buf pointer to string
974  * @param value double value
975  */
976 
977 static void
ln_sprintfg(char * buf,double value)978 ln_sprintfg(char *buf, double value)
979 {
980 #if defined(HAVE_LOCALECONV) || defined(_WIN32) || defined(_WIN64)
981     struct lconv *lc = 0;
982     char *p;
983 
984     sprintf(buf, "%.16g", value);
985     lc = localeconv();
986     if (lc && lc->decimal_point && lc->decimal_point[0] &&
987 	lc->decimal_point[0] != '.') {
988 	p = strchr(buf, lc->decimal_point[0]);
989 	if (p) {
990 	    *p = '.';
991 	}
992     }
993 #else
994     sprintf(buf, "%.16g", value);
995 #endif
996 }
997 #endif
998 
999 /**
1000  * Strip quotes from quoted string in-place.
1001  * @param str string
1002  */
1003 
1004 static char *
unquote(char * str)1005 unquote(char *str)
1006 {
1007     if (str) {
1008 	int len = strlen(str);
1009 
1010 	if (len > 1) {
1011 	    int end = len - 1;
1012 
1013 	    if ((str[0] == '\'' && str[end] == '\'') ||
1014 		(str[0] == '"' && str[end] == '"') ||
1015 		(str[0] == '[' && str[end] == ']')) {
1016 		memmove(str, str + 1, end - 1);
1017 		str[end - 1] = '\0';
1018 	    }
1019 	}
1020     }
1021     return str;
1022 }
1023 
1024 /**
1025  * Unescape search pattern for e.g. table name in
1026  * catalog functions. Replacements in string are done in-place.
1027  * @param str string
1028  * @result number of pattern characters in string or 0
1029  */
1030 
1031 static int
unescpat(char * str)1032 unescpat(char *str)
1033 {
1034     char *p, *q;
1035     int count = 0;
1036 
1037     p = str;
1038     while ((q = strchr(p, '_')) != NULL) {
1039 	if (q == str || q[-1] != '\\') {
1040 	    count++;
1041 	}
1042 	p = q + 1;
1043     }
1044     p = str;
1045     while ((q = strchr(p, '%')) != NULL) {
1046 	if (q == str || q[-1] != '\\') {
1047 	    count++;
1048 	}
1049 	p = q + 1;
1050     }
1051     p = str;
1052     while ((q = strchr(p, '\\')) != NULL) {
1053 	if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
1054 	    memmove(q, q + 1, strlen(q));
1055 	}
1056 	p = q + 1;
1057     }
1058     return count;
1059 }
1060 
1061 /**
1062  * SQL LIKE string match with optional backslash escape handling.
1063  * @param str string
1064  * @param pat pattern
1065  * @param esc when true, treat literally "\\" as "\", "\%" as "%", "\_" as "_"
1066  * @result true when pattern matched
1067  */
1068 
1069 static int
namematch(char * str,char * pat,int esc)1070 namematch(char *str, char *pat, int esc)
1071 {
1072     int cp, ch;
1073 
1074     while (1) {
1075 	cp = TOLOWER(*pat);
1076 	if (cp == '\0') {
1077 	    if (*str != '\0') {
1078 		goto nomatch;
1079 	    }
1080 	    break;
1081 	}
1082 	if (*str == '\0' && cp != '%') {
1083 	    goto nomatch;
1084 	}
1085 	if (cp == '%') {
1086 	    while (*pat == '%') {
1087 		++pat;
1088 	    }
1089 	    cp = TOLOWER(*pat);
1090 	    if (cp == '\0') {
1091 		break;
1092 	    }
1093 	    while (1) {
1094 		if (cp != '_' && cp != '\\') {
1095 		    while (*str) {
1096 			ch = TOLOWER(*str);
1097 			if (ch == cp) {
1098 			    break;
1099 			}
1100 			++str;
1101 		    }
1102 		}
1103 		if (namematch(str, pat, esc)) {
1104 		    goto match;
1105 		}
1106 		if (*str == '\0') {
1107 		    goto nomatch;
1108 		}
1109 		ch = TOLOWER(*str);
1110 		++str;
1111 	    }
1112 	}
1113 	if (cp == '_') {
1114 	    pat++;
1115 	    str++;
1116 	    continue;
1117 	}
1118 	if (esc && cp == '\\' &&
1119 	    (pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
1120 	    ++pat;
1121 	    cp = TOLOWER(*pat);
1122 	}
1123 	ch = TOLOWER(*str++);
1124 	++pat;
1125 	if (ch != cp) {
1126 	    goto nomatch;
1127 	}
1128     }
1129 match:
1130     return 1;
1131 nomatch:
1132     return 0;
1133 }
1134 
1135 /**
1136  * Busy callback for SQLite.
1137  * @param udata user data, pointer to DBC
1138  * @param table table name or NULL
1139  * @param count count of subsequenct calls
1140  * @result true of false
1141  */
1142 
1143 static int
busy_handler(void * udata,const char * table,int count)1144 busy_handler(void *udata, const char *table, int count)
1145 {
1146     DBC *d = (DBC *) udata;
1147     long t1;
1148     int ret = 0;
1149 #if !defined(_WIN32) && !defined(_WIN64)
1150     struct timeval tv;
1151 #ifdef HAVE_NANOSLEEP
1152     struct timespec ts;
1153 #endif
1154 #endif
1155 
1156     if (d->busyint) {
1157 	d->busyint = 0;
1158 	return ret;
1159     }
1160     if (d->timeout <= 0) {
1161 	return ret;
1162     }
1163     if (count <= 1) {
1164 #if defined(_WIN32) || defined(_WIN64)
1165 	d->t0 = GetTickCount();
1166 #else
1167 	gettimeofday(&tv, NULL);
1168 	d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1169 #endif
1170     }
1171 #if defined(_WIN32) || defined(_WIN64)
1172     t1 = GetTickCount();
1173 #else
1174     gettimeofday(&tv, NULL);
1175     t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1176 #endif
1177     if (t1 - d->t0 > d->timeout) {
1178 	goto done;
1179     }
1180 #if defined(_WIN32) || defined(_WIN64)
1181     Sleep(10);
1182 #else
1183 #ifdef HAVE_NANOSLEEP
1184     ts.tv_sec = 0;
1185     ts.tv_nsec = 10000000;
1186     do {
1187 	ret = nanosleep(&ts, &ts);
1188 	if (ret < 0 && errno != EINTR) {
1189 	    ret = 0;
1190 	}
1191     } while (ret);
1192 #else
1193 #ifdef HAVE_USLEEP
1194     usleep(10000);
1195 #else
1196     tv.tv_sec = 0;
1197     tv.tv_usec = 10000;
1198     select(0, NULL, NULL, NULL, &tv);
1199 #endif
1200 #endif
1201 #endif
1202     ret = 1;
1203 done:
1204     return ret;
1205 }
1206 
1207 #ifdef HAVE_ENCDEC
1208 static void hextobin_func(sqlite_func *context, int argc, const char **argv);
1209 static void bintohex_func(sqlite_func *context, int argc, const char **argv);
1210 #endif
1211 
1212 static void time_func(sqlite_func *context, int argc, const char **argv);
1213 
1214 /**
1215  * Set SQLite options (PRAGMAs) given SQLite handle.
1216  * @param x SQLite database handle
1217  * @param d DBC pointer
1218  * @result SQLite error code
1219  *
1220  * "full_column_names" is always turned on to get the table
1221  * names in column labels. "count_changes" is always turned
1222  * on to get the number of affected rows for INSERTs et.al.
1223  * "empty_result_callbacks" is always turned on to get
1224  * column labels even when no rows are returned.
1225  * Starting from SQLite 2.6.0 data types are reported for
1226  * callback functions when the "show_datatypes" pragma is
1227  * asserted.
1228  */
1229 
1230 static int
setsqliteopts(sqlite * x,DBC * d)1231 setsqliteopts(sqlite *x, DBC *d)
1232 {
1233     int count = 0, step = 0, rc;
1234 
1235     while (step < 4) {
1236 	if (step < 1) {
1237 	    rc = sqlite_exec(x, "PRAGMA full_column_names = on;",
1238 			     NULL, NULL, NULL);
1239 	} else if (step < 2) {
1240 	    rc = sqlite_exec(x, "PRAGMA count_changes = on;",
1241 			     NULL, NULL, NULL);
1242 	} else if (step < 3) {
1243 	    rc = sqlite_exec(x, "PRAGMA empty_result_callbacks = on;",
1244 			     NULL, NULL, NULL);
1245 	} else {
1246 	    rc = sqlite_exec(x, "PRAGMA show_datatypes = on;",
1247 			     NULL, NULL, NULL);
1248 	}
1249 	if (rc != SQLITE_OK) {
1250 	    if (rc != SQLITE_BUSY ||
1251 		!busy_handler((void *) d, NULL, ++count)) {
1252 		return rc;
1253 	    }
1254 	    continue;
1255 	}
1256 	count = 0;
1257 	++step;
1258     }
1259     sqlite_busy_handler(x, busy_handler, (void *) d);
1260 #if (HAVE_ENCDEC)
1261     {
1262 	char *fname;
1263 
1264 	fname = "hextobin";
1265 	sqlite_create_function(x, fname, 1, hextobin_func, 0);
1266 	sqlite_function_type(x, fname, SQLITE_TEXT);
1267 	fname = "bintohex";
1268 	sqlite_create_function(x, fname, 1, bintohex_func, 0);
1269 	sqlite_function_type(x, fname, SQLITE_TEXT);
1270     }
1271 #endif
1272     {
1273 	char *fname;
1274 
1275 	fname = "current_time_local";
1276 	sqlite_create_function(x, fname, 0, time_func, (void *) 0);
1277 	sqlite_function_type(x, fname, SQLITE_TEXT);
1278 	fname = "current_time_utc";
1279 	sqlite_create_function(x, fname, 0, time_func, (void *) 1);
1280 	sqlite_function_type(x, fname, SQLITE_TEXT);
1281 	fname = "current_date_local";
1282 	sqlite_create_function(x, fname, 0, time_func, (void *) 2);
1283 	sqlite_function_type(x, fname, SQLITE_TEXT);
1284 	fname = "current_date_utc";
1285 	sqlite_create_function(x, fname, 0, time_func, (void *) 3);
1286 	sqlite_function_type(x, fname, SQLITE_TEXT);
1287 	fname = "current_datetime_local";
1288 	sqlite_create_function(x, fname, 0, time_func, (void *) 4);
1289 	sqlite_function_type(x, fname, SQLITE_TEXT);
1290 	fname = "current_datetime_utc";
1291 	sqlite_create_function(x, fname, 0, time_func, (void *) 5);
1292 	sqlite_function_type(x, fname, SQLITE_TEXT);
1293 	fname = "current_timestamp_local";
1294 	sqlite_create_function(x, fname, 0, time_func, (void *) 4);
1295 	sqlite_function_type(x, fname, SQLITE_TEXT);
1296 	fname = "current_timestamp_utc";
1297 	sqlite_create_function(x, fname, 0, time_func, (void *) 5);
1298 	sqlite_function_type(x, fname, SQLITE_TEXT);
1299     }
1300     return SQLITE_OK;
1301 }
1302 
1303 /**
1304  * Free counted array of char pointers.
1305  * @param rowp pointer to char pointer array
1306  *
1307  * The -1-th element of the array holds the array size.
1308  * All non-NULL pointers of the array and then the array
1309  * itself are free'd.
1310  */
1311 
1312 static void
freerows(char ** rowp)1313 freerows(char **rowp)
1314 {
1315     int size, i;
1316 
1317     if (!rowp) {
1318 	return;
1319     }
1320     --rowp;
1321     size = (PTRDIFF_T) rowp[0];
1322     for (i = 1; i <= size; i++) {
1323 	freep(&rowp[i]);
1324     }
1325     freep(&rowp);
1326 }
1327 
1328 /**
1329  * Map SQL field type from string to ODBC integer type code.
1330  * @param typename field type string
1331  * @param nosign pointer to indicator for unsigned field or NULL
1332  * @param ov3 boolean, true for SQL_OV_ODBC3
1333  * @param nowchar boolean, for WINTERFACE don't use WCHAR
1334  * @result SQL data type
1335  */
1336 
1337 static int
mapsqltype(const char * typename,int * nosign,int ov3,int nowchar)1338 mapsqltype(const char *typename, int *nosign, int ov3, int nowchar)
1339 {
1340     char *p, *q;
1341     int testsign = 0, result;
1342 
1343 #ifdef WINTERFACE
1344     result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
1345 #else
1346     result = SQL_VARCHAR;
1347 #endif
1348     if (!typename) {
1349 	return result;
1350     }
1351     q = p = xmalloc(strlen(typename) + 1);
1352     if (!p) {
1353 	return result;
1354     }
1355     strcpy(p, typename);
1356     while (*q) {
1357 	*q = TOLOWER(*q);
1358 	++q;
1359     }
1360     if (strncmp(p, "inter", 5) == 0) {
1361     } else if (strncmp(p, "int", 3) == 0 ||
1362 	strncmp(p, "mediumint", 9) == 0) {
1363 	testsign = 1;
1364 	result = SQL_INTEGER;
1365     } else if (strncmp(p, "numeric", 7) == 0) {
1366 	result = SQL_DOUBLE;
1367     } else if (strncmp(p, "tinyint", 7) == 0) {
1368 	testsign = 1;
1369 	result = SQL_TINYINT;
1370     } else if (strncmp(p, "smallint", 8) == 0) {
1371 	testsign = 1;
1372 	result = SQL_SMALLINT;
1373     } else if (strncmp(p, "float", 5) == 0) {
1374 	result = SQL_DOUBLE;
1375     } else if (strncmp(p, "double", 6) == 0 ||
1376 	strncmp(p, "real", 4) == 0) {
1377 	result = SQL_DOUBLE;
1378     } else if (strncmp(p, "timestamp", 9) == 0) {
1379 #ifdef SQL_TYPE_TIMESTAMP
1380 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
1381 #else
1382 	result = SQL_TIMESTAMP;
1383 #endif
1384     } else if (strncmp(p, "datetime", 8) == 0) {
1385 #ifdef SQL_TYPE_TIMESTAMP
1386 	result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
1387 #else
1388 	result = SQL_TIMESTAMP;
1389 #endif
1390     } else if (strncmp(p, "time", 4) == 0) {
1391 #ifdef SQL_TYPE_TIME
1392 	result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
1393 #else
1394 	result = SQL_TIME;
1395 #endif
1396     } else if (strncmp(p, "date", 4) == 0) {
1397 #ifdef SQL_TYPE_DATE
1398 	result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
1399 #else
1400 	result = SQL_DATE;
1401 #endif
1402 #ifdef SQL_LONGVARCHAR
1403     } else if (strncmp(p, "text", 4) == 0 ||
1404 	       strncmp(p, "memo", 4) == 0 ||
1405 	       strncmp(p, "longvarchar", 11) == 0) {
1406 #ifdef WINTERFACE
1407 	result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
1408 #else
1409 	result = SQL_LONGVARCHAR;
1410 #endif
1411 #ifdef WINTERFACE
1412     } else if (strncmp(p, "wtext", 5) == 0 ||
1413 	       strncmp(p, "wvarchar", 8) == 0 ||
1414 	       strncmp(p, "longwvarchar", 12) == 0) {
1415 	result = SQL_WLONGVARCHAR;
1416 #endif
1417 #endif
1418 #if (HAVE_ENCDEC)
1419     } else if (strncmp(p, "binary", 6) == 0 ||
1420 	       strncmp(p, "varbinary", 9) == 0 ||
1421 	       strncmp(p, "bytea", 5) == 0 ||
1422 	       strncmp(p, "blob", 4) == 0 ||
1423 	       strncmp(p, "tinyblob", 8) == 0 ||
1424 	       strncmp(p, "mediumblob", 10) == 0) {
1425 	result = SQL_VARBINARY;
1426     } else if (strncmp(p, "longbinary", 10) == 0 ||
1427 	       strncmp(p, "longvarbinary", 13) == 0 ||
1428 	       strncmp(p, "longblob", 8) == 0) {
1429 	result = SQL_LONGVARBINARY;
1430 #endif
1431 #ifdef SQL_BIT
1432     } else if (strncmp(p, "bool", 4) == 0 ||
1433 	       strncmp(p, "bit", 3) == 0) {
1434 	testsign = 0;
1435 	result = SQL_BIT;
1436 #endif
1437     }
1438     if (nosign) {
1439 	if (testsign) {
1440 	    *nosign = strstr(p, "unsigned") != NULL;
1441 	} else {
1442 	    *nosign = 1;
1443 	}
1444     }
1445     xfree(p);
1446     return result;
1447 }
1448 
1449 /**
1450  * Get maximum display size and number of digits after decimal point
1451  * from field type specification.
1452  * @param typename field type specification
1453  * @param sqltype target SQL data type
1454  * @param mp pointer to maximum display size or NULL
1455  * @param dp pointer to number of digits after decimal point or NULL
1456  */
1457 
1458 static void
getmd(const char * typename,int sqltype,int * mp,int * dp)1459 getmd(const char *typename, int sqltype, int *mp, int *dp)
1460 {
1461     int m = 0, d = 0;
1462 
1463     switch (sqltype) {
1464     case SQL_INTEGER:      m = 10; d = 9; break;
1465     case SQL_TINYINT:      m = 4; d = 3; break;
1466     case SQL_SMALLINT:     m = 6; d = 5; break;
1467     case SQL_FLOAT:        m = 25; d = 24; break;
1468     case SQL_DOUBLE:       m = 54; d = 53; break;
1469     case SQL_VARCHAR:      m = 255; d = 0; break;
1470 #ifdef WINTERFACE
1471 #ifdef SQL_WVARCHAR
1472     case SQL_WVARCHAR:     m = 255; d = 0; break;
1473 #endif
1474 #endif
1475 #ifdef SQL_TYPE_DATE
1476     case SQL_TYPE_DATE:
1477 #endif
1478     case SQL_DATE:         m = 10; d = 0; break;
1479 #ifdef SQL_TYPE_TIME
1480     case SQL_TYPE_TIME:
1481 #endif
1482     case SQL_TIME:         m = 8; d = 0; break;
1483 #ifdef SQL_TYPE_TIMESTAMP
1484     case SQL_TYPE_TIMESTAMP:
1485 #endif
1486     case SQL_TIMESTAMP:    m = 32; d = 3; break;
1487 #ifdef SQL_LONGVARCHAR
1488     case SQL_LONGVARCHAR : m = 65536; d = 0; break;
1489 #endif
1490 #ifdef WINTERFACE
1491 #ifdef SQL_WLONGVARCHAR
1492     case SQL_WLONGVARCHAR: m = 65536; d = 0; break;
1493 #endif
1494 #endif
1495 #if (HAVE_ENCDEC)
1496     case SQL_BINARY:
1497     case SQL_VARBINARY: m = 255; d = 0; break;
1498     case SQL_LONGVARBINARY: m = 65536; d = 0; break;
1499 #endif
1500 #ifdef SQL_BIT
1501     case SQL_BIT:	    m = 1; d = 1; break;
1502 #endif
1503     }
1504     if (m && typename) {
1505 	int mm, dd;
1506 	char clbr[4];
1507 
1508 	if (sscanf(typename, "%*[^(](%d,%d %1[)]", &mm, &dd, clbr) == 3) {
1509 	    m = mm;
1510 	    d = dd;
1511 	} else if (sscanf(typename, "%*[^(](%d %1[)]", &mm, clbr) == 2) {
1512 	    if (sqltype == SQL_TIMESTAMP) {
1513 		d = mm;
1514 	    }
1515 #ifdef SQL_TYPE_TIMESTAMP
1516 	    if (sqltype == SQL_TYPE_TIMESTAMP) {
1517 		d = mm;
1518 	    }
1519 #endif
1520 	    else {
1521 		m = d = mm;
1522 	    }
1523 	}
1524     }
1525     if (mp) {
1526 	*mp = m;
1527     }
1528     if (dp) {
1529 	*dp = d;
1530     }
1531 }
1532 
1533 /**
1534  * Map SQL_C_DEFAULT to proper C type.
1535  * @param type input C type
1536  * @param stype input SQL type
1537  * @param nosign 0=signed, 0>unsigned, 0<undefined
1538  * @param nowchar when compiled with WINTERFACE don't use WCHAR
1539  * @result C type
1540  */
1541 
1542 static int
mapdeftype(int type,int stype,int nosign,int nowchar)1543 mapdeftype(int type, int stype, int nosign, int nowchar)
1544 {
1545     if (type == SQL_C_DEFAULT) {
1546 	switch (stype) {
1547 	case SQL_INTEGER:
1548 	    type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
1549 	    break;
1550 	case SQL_TINYINT:
1551 	    type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
1552 	    break;
1553 	case SQL_SMALLINT:
1554 	    type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
1555 	    break;
1556 	case SQL_FLOAT:
1557 	    type = SQL_C_FLOAT;
1558 	    break;
1559 	case SQL_DOUBLE:
1560 	    type = SQL_C_DOUBLE;
1561 	    break;
1562 	case SQL_TIMESTAMP:
1563 	    type = SQL_C_TIMESTAMP;
1564 	    break;
1565 	case SQL_TIME:
1566 	    type = SQL_C_TIME;
1567 	    break;
1568 	case SQL_DATE:
1569 	    type = SQL_C_DATE;
1570 	    break;
1571 #ifdef SQL_C_TYPE_TIMESTAMP
1572 	case SQL_TYPE_TIMESTAMP:
1573 	    type = SQL_C_TYPE_TIMESTAMP;
1574 	    break;
1575 #endif
1576 #ifdef SQL_C_TYPE_TIME
1577 	case SQL_TYPE_TIME:
1578 	    type = SQL_C_TYPE_TIME;
1579 	    break;
1580 #endif
1581 #ifdef SQL_C_TYPE_DATE
1582 	case SQL_TYPE_DATE:
1583 	    type = SQL_C_TYPE_DATE;
1584 	    break;
1585 #endif
1586 #ifdef WINTERFACE
1587 	case SQL_WVARCHAR:
1588 	case SQL_WCHAR:
1589 #ifdef SQL_WLONGVARCHAR
1590 	case SQL_WLONGVARCHAR:
1591 #endif
1592 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
1593 	    break;
1594 #endif
1595 #if (HAVE_ENCDEC)
1596 	case SQL_BINARY:
1597 	case SQL_VARBINARY:
1598 	case SQL_LONGVARBINARY:
1599 	    type = SQL_C_BINARY;
1600 	    break;
1601 #endif
1602 #ifdef SQL_BIT
1603 	case SQL_BIT:
1604 	    type = SQL_C_BIT;
1605 	    break;
1606 #endif
1607 	default:
1608 #ifdef WINTERFACE
1609 	    type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
1610 #else
1611 	    type = SQL_C_CHAR;
1612 #endif
1613 	    break;
1614 	}
1615     }
1616     return type;
1617 }
1618 
1619  /**
1620   * Check if query is a DDL statement.
1621   * @param sql query string
1622   * @result true or false
1623   */
1624 
1625 static int
checkddl(char * sql)1626 checkddl(char *sql)
1627 {
1628     int isddl = 0;
1629 
1630     while (*sql && ISSPACE(*sql)) {
1631 	++sql;
1632     }
1633     if (*sql && *sql != ';') {
1634 	int i, size;
1635 	static const struct {
1636 	    int len;
1637 	    const char *str;
1638 	} ddlstr[] = {
1639 	    { 6, "attach" },
1640 	    { 5, "begin" },
1641 	    { 6, "commit" },
1642 	    { 6, "create" },
1643 	    { 6, "detach" },
1644 	    { 4, "drop" },
1645 	    { 3, "end" },
1646 	    { 8, "rollback" },
1647 	    { 6, "vacuum" }
1648 	};
1649 
1650 	size = strlen(sql);
1651 	for (i = 0; i < array_size(ddlstr); i++) {
1652 	    if (size >= ddlstr[i].len &&
1653 		strncasecmp(sql, ddlstr[i].str, ddlstr[i].len) == 0) {
1654 		isddl = 1;
1655 		break;
1656 	    }
1657 	}
1658     }
1659     return isddl;
1660 }
1661 
1662 /**
1663  * Fixup query string with optional parameter markers.
1664  * @param sql original query string
1665  * @param sqlLen length of query string or SQL_NTS
1666  * @param nparam output number of parameters
1667  * @param isselect output indicator for SELECT (1) or DDL statement (2)
1668  * @param errmsg output error message
1669  * @param version SQLite version information
1670  * @param namepp pointer to parameter names array
1671  * @result newly allocated string containing query string for SQLite or NULL
1672  */
1673 
1674 static char *
fixupsql(char * sql,int sqlLen,int * nparam,int * isselect,char ** errmsg,int version,char *** namepp)1675 fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg,
1676 	 int version, char ***namepp)
1677 {
1678     char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
1679     int np = 0, isddl = -1, size;
1680     char **npp = NULL, *ncp = NULL;
1681 
1682     *errmsg = NULL;
1683     if (sqlLen != SQL_NTS) {
1684 	qz = q = xmalloc(sqlLen + 1);
1685 	if (!qz) {
1686 	    return NULL;
1687 	}
1688 	memcpy(q, sql, sqlLen);
1689 	q[sqlLen] = '\0';
1690 	size = sqlLen * 4;
1691     } else {
1692 	size = strlen(sql) * 4;
1693     }
1694     size += sizeof (char *) - 1;
1695     size &= ~(sizeof (char *) - 1);
1696     p = xmalloc(2 * size + size * sizeof (char *) / 2);
1697     if (!p) {
1698 errout:
1699 	freep(&qz);
1700 	return NULL;
1701     }
1702     memset(p, 0, 2 * size + size * sizeof (char *) / 2);
1703     out = p;
1704     npp = (char **) (out + size);
1705     ncp = (char *) npp + size * sizeof (char *) / 2;
1706     while (*q) {
1707 	switch (*q) {
1708 	case '\'':
1709 	case '\"':
1710 	    if (q == inq) {
1711 		inq = NULL;
1712 	    } else if (!inq) {
1713 		inq = q + 1;
1714 
1715 		while (*inq) {
1716 		    if (*inq == *q) {
1717 			if (inq[1] == *q) {
1718 			    inq++;
1719 			} else {
1720 			    break;
1721 			}
1722 		    }
1723 		    inq++;
1724 		}
1725 	    }
1726 	    *p++ = *q;
1727 	    break;
1728 	case '?':
1729 	    if (inq) {
1730 		*p++ = *q;
1731 	    } else {
1732 		*p++ = '%';
1733 		*p++ = 'Q';
1734 		npp[np] = ncp;
1735 		*ncp = '\0';
1736 		++ncp;
1737 		np++;
1738 	    }
1739 	    break;
1740 	case ':':		/* ORACLE-style named parameter */
1741 	case '@':		/* ADO.NET-style named parameter */
1742 	    if (inq) {
1743 		*p++ = *q;
1744 	    } else {
1745 		int n = -1;
1746 
1747 		do {
1748 		   ++q;
1749 		   ++n;
1750 		} while (*q && ISIDCHAR(*q));
1751 		if (n > 0) {
1752 		    *p++ = '%';
1753 		    *p++ = 'Q';
1754 		    npp[np] = ncp;
1755 		    memcpy(ncp, q - n, n);
1756 		    ncp[n] = '\0';
1757 		    ncp += n + 1;
1758 		    np++;
1759 		}
1760 		--q;
1761 	    }
1762 	    break;
1763 	case ';':
1764 	    if (!inq) {
1765 		if (isddl < 0) {
1766 		    isddl = checkddl(out);
1767 		}
1768 		if (isddl == 0) {
1769 		    char *qq = q;
1770 
1771 		    do {
1772 			++qq;
1773 		    } while (*qq && ISSPACE(*qq));
1774 		    if (*qq && *qq != ';') {
1775 			freep(&out);
1776 			*errmsg = "only one SQL statement allowed";
1777 			goto errout;
1778 		    }
1779 		}
1780 	    }
1781 	    *p++ = *q;
1782 	    break;
1783 	case '%':
1784 	    *p++ = '%';
1785 	    *p++ = '%';
1786 	    break;
1787 	case '{':
1788 	    /*
1789 	     * Deal with escape sequences:
1790 	     * {d 'YYYY-MM-DD'}, {t ...}, {ts ...}
1791 	     * {oj ...}, {fn ...} etc.
1792 	     */
1793 	    if (!inq) {
1794 		int ojfn = 0;
1795 		char *inq2 = NULL, *end = q + 1, *start;
1796 
1797 		while (*end && ISSPACE(*end)) {
1798 		    ++end;
1799 		}
1800 		if (*end != 'd' && *end != 'D' &&
1801 		    *end != 't' && *end != 'T') {
1802 		    ojfn = 1;
1803 		}
1804 		start = end;
1805 		while (*end) {
1806 		    if (inq2 && *end == *inq2) {
1807 			inq2 = NULL;
1808 		    } else if (inq2 == NULL && *end == '}') {
1809 			break;
1810 		    } else if (inq2 == NULL && (*end == '\'' || *end == '"')) {
1811 			inq2 = end;
1812 		    }
1813 		    ++end;
1814 		}
1815 		if (*end == '}') {
1816 		    char *end2 = end - 1;
1817 
1818 		    if (ojfn) {
1819 			while (start < end) {
1820 			    if (ISSPACE(*start)) {
1821 				break;
1822 			    }
1823 			    ++start;
1824 			}
1825 			while (start < end) {
1826 			    *p++ = *start;
1827 			    ++start;
1828 			}
1829 			q = end;
1830 			break;
1831 		    } else {
1832 			while (start < end2 && *start != '\'') {
1833 			    ++start;
1834 			}
1835 			while (end2 > start && *end2 != '\'') {
1836 			    --end2;
1837 			}
1838 			if (*start == '\'' && *end2 == '\'') {
1839 			    while (start <= end2) {
1840 				*p++ = *start;
1841 				++start;
1842 			    }
1843 			    q = end;
1844 			    break;
1845 			}
1846 		    }
1847 		}
1848 	    }
1849 	    /* FALL THROUGH */
1850 	default:
1851 	    *p++ = *q;
1852 	}
1853 	++q;
1854     }
1855     freep(&qz);
1856     *p = '\0';
1857     if (nparam) {
1858 	*nparam = np;
1859     }
1860     if (isselect) {
1861 	if (isddl < 0) {
1862 	    isddl = checkddl(out);
1863 	}
1864 	if (isddl > 0) {
1865 	    *isselect = 2;
1866 	} else {
1867 	    int incom = 0;
1868 
1869 	    p = out;
1870 	    while (*p) {
1871 		switch (*p) {
1872 		case '-':
1873 		    if (!incom && p[1] == '-') {
1874 			incom = -1;
1875 		    }
1876 		    break;
1877 		case '\n':
1878 		    if (incom < 0) {
1879 			incom = 0;
1880 		    }
1881 		    break;
1882 		case '/':
1883 		    if (incom > 0 && p[-1] == '*') {
1884 			incom = 0;
1885 			p++;
1886 			continue;
1887 		    } else if (!incom && p[1] == '*') {
1888 			incom = 1;
1889 		    }
1890 		    break;
1891 		}
1892 		if (!incom && !ISSPACE(*p)) {
1893 		    break;
1894 		}
1895 		++p;
1896 	    }
1897 	    size = strlen(p);
1898 	    if (size >= 6 &&
1899 		(strncasecmp(p, "select", 6) == 0 ||
1900 		 strncasecmp(p, "pragma", 6) == 0)) {
1901 		*isselect = 1;
1902 	    } else if (size >= 7 &&
1903 		       strncasecmp(p, "explain", 7) == 0) {
1904 		*isselect = 1;
1905 	    } else {
1906 		*isselect = 0;
1907 	    }
1908 	}
1909     }
1910     if (namepp) {
1911 	*namepp = npp;
1912     }
1913     return out;
1914 }
1915 
1916 /**
1917  * Find column given name in string array.
1918  * @param cols string array
1919  * @param ncols number of strings
1920  * @param name column name
1921  * @result >= 0 on success, -1 on error
1922  */
1923 
1924 static int
findcol(char ** cols,int ncols,char * name)1925 findcol(char **cols, int ncols, char *name)
1926 {
1927     int i;
1928 
1929     if (cols) {
1930 	for (i = 0; i < ncols; i++) {
1931 	    if (strcmp(cols[i], name) == 0) {
1932 		return i;
1933 	    }
1934 	}
1935     }
1936     return -1;
1937 }
1938 
1939 /**
1940  * Fixup column information for a running statement.
1941  * @param s statement to get fresh column information
1942  * @param sqlite SQLite database handle
1943  * @param types column types or NULL
1944  *
1945  * The column labels get the table names stripped
1946  * when there's more than one column and all table
1947  * names are identical.
1948  *
1949  * The "dyncols" field of STMT is filled with column
1950  * information obtained by SQLite "PRAGMA table_info"
1951  * for each column whose table name is known. If the
1952  * types are already present as with SQLite 2.5.7
1953  * this information is used instead.
1954  */
1955 
1956 static void
fixupdyncols(STMT * s,sqlite * sqlite,const char ** types)1957 fixupdyncols(STMT *s, sqlite *sqlite, const char **types)
1958 {
1959     int i, k, pk, nn, t, r, nrows, ncols;
1960     char **rowp, *flagp, flags[128];
1961 
1962     if (!s->dyncols) {
1963 	return;
1964     }
1965     /* fixup labels */
1966     if (!s->longnames) {
1967 	if (s->dcols > 1) {
1968 	    char *table = s->dyncols[0].table;
1969 
1970 	    for (i = 1; table[0] && i < s->dcols; i++) {
1971 		if (strcmp(s->dyncols[i].table, table)) {
1972 		    break;
1973 		}
1974 	    }
1975 	    if (i >= s->dcols) {
1976 		for (i = 0; i < s->dcols; i++) {
1977 		    s->dyncols[i].label = s->dyncols[i].column;
1978 		}
1979 	    }
1980 	} else if (s->dcols == 1) {
1981 	    s->dyncols[0].label = s->dyncols[0].column;
1982 	}
1983     }
1984     if (types) {
1985 	for (i = 0; i < s->dcols; i++) {
1986 	    freep(&s->dyncols[i].typename);
1987 	    s->dyncols[i].typename = xstrdup(types[i] ? types[i] : "text");
1988 	    s->dyncols[i].type =
1989 		mapsqltype(types[i], &s->dyncols[i].nosign, *s->ov3,
1990 			   s->nowchar[0] || s->nowchar[1]);
1991 	    getmd(types[i], s->dyncols[i].type, &s->dyncols[i].size,
1992 		  &s->dyncols[i].prec);
1993 #ifdef SQL_LONGVARCHAR
1994 	    if (s->dyncols[i].type == SQL_VARCHAR &&
1995 		s->dyncols[i].size > 255) {
1996 		s->dyncols[i].type = SQL_LONGVARCHAR;
1997 	    }
1998 #endif
1999 #ifdef WINTERFACE
2000 #ifdef SQL_WLONGVARCHAR
2001 	    if (s->dyncols[i].type == SQL_WVARCHAR &&
2002 		s->dyncols[i].size > 255) {
2003 		s->dyncols[i].type = SQL_WLONGVARCHAR;
2004 	    }
2005 #endif
2006 #endif
2007 #if (HAVE_ENCDEC)
2008 	    if (s->dyncols[i].type == SQL_VARBINARY &&
2009 		s->dyncols[i].size > 255) {
2010 		s->dyncols[i].type = SQL_LONGVARBINARY;
2011 	    }
2012 #endif
2013 	}
2014     }
2015     if (s->dcols > array_size(flags)) {
2016 	flagp = xmalloc(sizeof (flags[0]) * s->dcols);
2017 	if (flagp == NULL) {
2018 	    return;
2019 	}
2020     } else {
2021 	flagp = flags;
2022     }
2023     memset(flagp, 0, sizeof (flags[0]) * s->dcols);
2024     for (i = 0; i < s->dcols; i++) {
2025 	s->dyncols[i].autoinc = SQL_FALSE;
2026 	s->dyncols[i].notnull = SQL_NULLABLE;
2027     }
2028     for (i = 0; i < s->dcols; i++) {
2029 	int ret, lastpk = -1, autoinccount = 0;
2030 
2031 	if (!s->dyncols[i].table[0]) {
2032 	    continue;
2033 	}
2034 	if (flagp[i]) {
2035 	    continue;
2036 	}
2037 	ret = sqlite_get_table_printf(sqlite,
2038 				      "PRAGMA table_info('%q')", &rowp,
2039 				      &nrows, &ncols, NULL,
2040 				      s->dyncols[i].table);
2041 	if (ret != SQLITE_OK) {
2042 	    continue;
2043 	}
2044 	k = findcol(rowp, ncols, "name");
2045 	t = findcol(rowp, ncols, "type");
2046 	pk = findcol(rowp, ncols, "pk");
2047 	nn = findcol(rowp, ncols, "notnull");
2048 	if (k < 0 || t < 0) {
2049 	    goto freet;
2050 	}
2051 	for (r = 1; r <= nrows; r++) {
2052 	    int m;
2053 
2054 	    for (m = i; m < s->dcols; m++) {
2055 		if (!flagp[m] &&
2056 		    strcmp(s->dyncols[m].column, rowp[r * ncols + k]) == 0 &&
2057 		    strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
2058 		    char *typename = rowp[r * ncols + t];
2059 
2060 		    flagp[m] = 1;
2061 		    freep(&s->dyncols[m].typename);
2062 		    s->dyncols[m].typename = xstrdup(typename);
2063 		    s->dyncols[m].type =
2064 			mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
2065 				   s->nowchar[0] || s->nowchar[1]);
2066 		    getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
2067 			  &s->dyncols[m].prec);
2068 #ifdef SQL_LONGVARCHAR
2069 		    if (s->dyncols[m].type == SQL_VARCHAR &&
2070 			s->dyncols[m].size > 255) {
2071 			s->dyncols[m].type = SQL_LONGVARCHAR;
2072 		    }
2073 #endif
2074 #ifdef WINTERFACE
2075 #ifdef SQL_WLONGVARCHAR
2076 		    if (s->dyncols[i].type == SQL_WVARCHAR &&
2077 			s->dyncols[i].size > 255) {
2078 			s->dyncols[i].type = SQL_WLONGVARCHAR;
2079 		    }
2080 #endif
2081 #endif
2082 #if (HAVE_ENCDEC)
2083 		    if (s->dyncols[i].type == SQL_VARBINARY &&
2084 			s->dyncols[i].size > 255) {
2085 			s->dyncols[i].type = SQL_LONGVARBINARY;
2086 		    }
2087 #endif
2088 		    if (pk >= 0	&& strcmp(rowp[r * ncols + pk], "1") == 0) {
2089 			if (++autoinccount > 1) {
2090 			    if (lastpk >= 0) {
2091 				s->dyncols[lastpk].autoinc = SQL_FALSE;
2092 				lastpk = -1;
2093 			    }
2094 			} else {
2095 			    lastpk = m;
2096 			    if (strlen(typename) == 7 &&
2097 				strncasecmp(typename, "integer", 7) == 0) {
2098 				s->dyncols[m].autoinc = SQL_TRUE;
2099 			    }
2100 			}
2101 		    }
2102 		    if (nn >= 0 && rowp[r * ncols + nn][0] != '0') {
2103 			s->dyncols[m].notnull = SQL_NO_NULLS;
2104 		    }
2105 		}
2106 	    }
2107 	}
2108 freet:
2109 	sqlite_free_table(rowp);
2110     }
2111     if (flagp != flags) {
2112 	freep(&flagp);
2113     }
2114 }
2115 
2116 /**
2117  * Return number of month days.
2118  * @param year
2119  * @param month 1..12
2120  * @result number of month days or 0
2121  */
2122 
2123 static int
getmdays(int year,int month)2124 getmdays(int year, int month)
2125 {
2126     static const int mdays[] = {
2127 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2128     };
2129     int mday;
2130 
2131     if (month < 1) {
2132 	return 0;
2133     }
2134     mday = mdays[(month - 1) % 12];
2135     if (mday == 28 && year % 4 == 0 &&
2136 	(!(year % 100 == 0) || year % 400 == 0)) {
2137 	mday++;
2138     }
2139     return mday;
2140 }
2141 
2142 /**
2143  * Convert string to ODBC DATE_STRUCT.
2144  * @param str string to be converted
2145  * @param ds output DATE_STRUCT
2146  * @result 0 on success, -1 on error
2147  *
2148  * Strings of the format 'YYYYMMDD' or 'YYYY-MM-DD' or
2149  * 'YYYY/MM/DD' or 'MM/DD/YYYY' are converted to a
2150  * DATE_STRUCT.
2151  */
2152 
2153 static int
str2date(char * str,DATE_STRUCT * ds)2154 str2date(char *str, DATE_STRUCT *ds)
2155 {
2156     int i, err = 0;
2157     char *p, *q, sepc = '\0';
2158 
2159     ds->year = ds->month = ds->day = 0;
2160     p = str;
2161     while (*p && !ISDIGIT(*p)) {
2162 	++p;
2163     }
2164     q = p;
2165     i = 0;
2166     while (*q && !ISDIGIT(*q)) {
2167 	++i;
2168 	++q;
2169     }
2170     if (i >= 8) {
2171 	char buf[8];
2172 
2173 	strncpy(buf, p + 0, 4); buf[4] = '\0';
2174 	ds->year = strtol(buf, NULL, 10);
2175 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2176 	ds->month = strtol(buf, NULL, 10);
2177 	strncpy(buf, p + 6, 2); buf[2] = '\0';
2178 	ds->day = strtol(buf, NULL, 10);
2179 	goto done;
2180     }
2181     i = 0;
2182     while (i < 3) {
2183 	int n;
2184 
2185 	q = NULL;
2186 	n = strtol(p, &q, 10);
2187 	if (!q || q == p) {
2188 	    if (*q == '\0') {
2189 		if (i == 0) {
2190 		    err = 1;
2191 		}
2192 		goto done;
2193 	    }
2194 	}
2195 	if (!sepc) {
2196 	    sepc = *q;
2197 	}
2198 	if (*q == '-' || *q == '/' || *q == '\0' || i == 2) {
2199 	    switch (i) {
2200 	    case 0: ds->year = n; break;
2201 	    case 1: ds->month = n; break;
2202 	    case 2: ds->day = n; break;
2203 	    }
2204 	    ++i;
2205 	    if (*q) {
2206 		++q;
2207 	    }
2208 	} else {
2209 	    i = 0;
2210 	    while (*q && !ISDIGIT(*q)) {
2211 		++q;
2212 	    }
2213 	}
2214 	p = q;
2215     }
2216 done:
2217     /* final check for overflow */
2218     if (err ||
2219 	ds->month < 1 || ds->month > 12 ||
2220 	ds->day < 1 || ds->day > getmdays(ds->year, ds->month)) {
2221 	if (sepc == '/') {
2222 	    /* Try MM/DD/YYYY format */
2223 	    int t[3];
2224 
2225 	    t[0] = ds->year;
2226 	    t[1] = ds->month;
2227 	    t[2] = ds->day;
2228 	    ds->year = t[2];
2229 	    ds->day = t[1];
2230 	    ds->month = t[0];
2231 	    if (ds->month >= 1 && ds->month <= 12 &&
2232 		ds->day >= 1 && ds->day <= getmdays(ds->year, ds->month)) {
2233 		return 0;
2234 	    }
2235 	}
2236 	return -1;
2237     }
2238     return 0;
2239 }
2240 
2241 /**
2242  * Convert string to ODBC TIME_STRUCT.
2243  * @param str string to be converted
2244  * @param ts output TIME_STRUCT
2245  * @result 0 on success, -1 on error
2246  *
2247  * Strings of the format 'HHMMSS' or 'HH:MM:SS'
2248  * are converted to a TIME_STRUCT.
2249  */
2250 
2251 static int
str2time(char * str,TIME_STRUCT * ts)2252 str2time(char *str, TIME_STRUCT *ts)
2253 {
2254     int i, err = 0, ampm = -1;
2255     char *p, *q;
2256 
2257     ts->hour = ts->minute = ts->second = 0;
2258     p = str;
2259     while (*p && !ISDIGIT(*p)) {
2260 	++p;
2261     }
2262     q = p;
2263     i = 0;
2264     while (*q && ISDIGIT(*q)) {
2265 	++i;
2266 	++q;
2267     }
2268     if (i >= 6) {
2269 	char buf[4];
2270 
2271 	strncpy(buf, p + 0, 2); buf[2] = '\0';
2272 	ts->hour = strtol(buf, NULL, 10);
2273 	strncpy(buf, p + 2, 2); buf[2] = '\0';
2274 	ts->minute = strtol(buf, NULL, 10);
2275 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2276 	ts->second = strtol(buf, NULL, 10);
2277 	goto done;
2278     }
2279     i = 0;
2280     while (i < 3) {
2281 	int n;
2282 
2283 	q = NULL;
2284 	n = strtol(p, &q, 10);
2285 	if (!q || q == p) {
2286 	    if (*q == '\0') {
2287 		if (i == 0) {
2288 		    err = 1;
2289 		}
2290 		goto done;
2291 	    }
2292 	}
2293 	if (*q == ':' || *q == '\0' || i == 2) {
2294 	    switch (i) {
2295 	    case 0: ts->hour = n; break;
2296 	    case 1: ts->minute = n; break;
2297 	    case 2: ts->second = n; break;
2298 	    }
2299 	    ++i;
2300 	    if (*q) {
2301 		++q;
2302 	    }
2303 	} else {
2304 	    i = 0;
2305 	    while (*q && !ISDIGIT(*q)) {
2306 		++q;
2307 	    }
2308 	}
2309 	p = q;
2310     }
2311     if (!err) {
2312 	while (*p) {
2313 	    if ((p[0] == 'p' || p[0] == 'P') &&
2314 		(p[1] == 'm' || p[1] == 'M')) {
2315 		ampm = 1;
2316 	    } else if ((p[0] == 'a' || p[0] == 'A') &&
2317 		       (p[1] == 'm' || p[1] == 'M')) {
2318 		ampm = 0;
2319 	    }
2320 	    ++p;
2321 	}
2322 	if (ampm > 0) {
2323 	    if (ts->hour < 12) {
2324 		ts->hour += 12;
2325 	    }
2326 	} else if(ampm == 0) {
2327 	    if (ts->hour == 12) {
2328 		ts->hour = 0;
2329 	    }
2330 	}
2331     }
2332 done:
2333     /* final check for overflow */
2334     if (err || ts->hour > 23 || ts->minute > 59 || ts->second > 59) {
2335 	return -1;
2336     }
2337     return 0;
2338 }
2339 
2340 /**
2341  * Convert string to ODBC TIMESTAMP_STRUCT.
2342  * @param str string to be converted
2343  * @param tss output TIMESTAMP_STRUCT
2344  * @result 0 on success, -1 on error
2345  *
2346  * Strings of the format 'YYYYMMDDhhmmssff' or 'YYYY-MM-DD hh:mm:ss ff'
2347  * or 'YYYY/MM/DD hh:mm:ss ff' or 'hh:mm:ss ff YYYY-MM-DD' are
2348  * converted to a TIMESTAMP_STRUCT. The ISO8601 formats
2349  *    YYYY-MM-DDThh:mm:ss[.f]Z
2350  *    YYYY-MM-DDThh:mm:ss[.f]shh:mm
2351  * are also supported. In case a time zone field is present,
2352  * the resulting TIMESTAMP_STRUCT is expressed in UTC.
2353  */
2354 
2355 static int
str2timestamp(char * str,TIMESTAMP_STRUCT * tss)2356 str2timestamp(char *str, TIMESTAMP_STRUCT *tss)
2357 {
2358     int i, m, n, err = 0, ampm = -1;
2359     char *p, *q, in = '\0', sepc = '\0';
2360 
2361     tss->year = tss->month = tss->day = 0;
2362     tss->hour = tss->minute = tss->second = 0;
2363     tss->fraction = 0;
2364     p = str;
2365     while (*p && !ISDIGIT(*p)) {
2366 	++p;
2367     }
2368     q = p;
2369     i = 0;
2370     while (*q && ISDIGIT(*q)) {
2371 	++i;
2372 	++q;
2373     }
2374     if (i >= 14) {
2375 	char buf[16];
2376 
2377 	strncpy(buf, p + 0, 4); buf[4] = '\0';
2378 	tss->year = strtol(buf, NULL, 10);
2379 	strncpy(buf, p + 4, 2); buf[2] = '\0';
2380 	tss->month = strtol(buf, NULL, 10);
2381 	strncpy(buf, p + 6, 2); buf[2] = '\0';
2382 	tss->day = strtol(buf, NULL, 10);
2383 	strncpy(buf, p + 8, 2); buf[2] = '\0';
2384 	tss->hour = strtol(buf, NULL, 10);
2385 	strncpy(buf, p + 10, 2); buf[2] = '\0';
2386 	tss->minute = strtol(buf, NULL, 10);
2387 	strncpy(buf, p + 12, 2); buf[2] = '\0';
2388 	tss->second = strtol(buf, NULL, 10);
2389 	if (i > 14) {
2390 	    m = i - 14;
2391 	    strncpy(buf, p + 14, m);
2392 	    while (m < 9) {
2393 		buf[m] = '0';
2394 		++m;
2395 	    }
2396 	    buf[m] = '\0';
2397 	    tss->fraction = strtol(buf, NULL, 10);
2398 	}
2399 	m = 7;
2400 	goto done;
2401     }
2402     m = i = 0;
2403     while ((m & 7) != 7) {
2404 	q = NULL;
2405 	n = strtol(p, &q, 10);
2406 	if (!q || q == p) {
2407 	    if (*q == '\0') {
2408 		if (m < 1) {
2409 		    err = 1;
2410 		}
2411 		goto done;
2412 	    }
2413 	}
2414 	if (in == '\0') {
2415 	    switch (*q) {
2416 	    case '-':
2417 	    case '/':
2418 		if ((m & 1) == 0) {
2419 		    in = *q;
2420 		    i = 0;
2421 		}
2422 		break;
2423 	    case ':':
2424 		if ((m & 2) == 0) {
2425 		    in = *q;
2426 		    i = 0;
2427 		}
2428 		break;
2429 	    case ' ':
2430 	    case '.':
2431 		break;
2432 	    default:
2433 		in = '\0';
2434 		i = 0;
2435 		break;
2436 	    }
2437 	}
2438 	switch (in) {
2439 	case '-':
2440 	case '/':
2441 	    if (!sepc) {
2442 		sepc = in;
2443 	    }
2444 	    switch (i) {
2445 	    case 0: tss->year = n; break;
2446 	    case 1: tss->month = n; break;
2447 	    case 2: tss->day = n; break;
2448 	    }
2449 	    if (++i >= 3) {
2450 		i = 0;
2451 		m |= 1;
2452 		if (!(m & 2)) {
2453 		    m |= 8;
2454 		}
2455 		goto skip;
2456 	    } else {
2457 		++q;
2458 	    }
2459 	    break;
2460 	case ':':
2461 	    switch (i) {
2462 	    case 0: tss->hour = n; break;
2463 	    case 1: tss->minute = n; break;
2464 	    case 2: tss->second = n; break;
2465 	    }
2466 	    if (++i >= 3) {
2467 		i = 0;
2468 		m |= 2;
2469 		if (*q == '.') {
2470 		    in = '.';
2471 		    goto skip2;
2472 		}
2473 		if (*q == ' ') {
2474 		    if ((m & 1) == 0) {
2475 			char *e = NULL;
2476 
2477 			(void) strtol(q + 1, &e, 10);
2478 			if (e && *e == '-') {
2479 			    goto skip;
2480 			}
2481 		    }
2482 		    in = '.';
2483 		    goto skip2;
2484 		}
2485 		goto skip;
2486 	    } else {
2487 		++q;
2488 	    }
2489 	    break;
2490 	case '.':
2491 	    if (++i >= 1) {
2492 		int ndig = q - p;
2493 
2494 		if (p[0] == '+' || p[0] == '-') {
2495 		    ndig--;
2496 		}
2497 		while (ndig < 9) {
2498 		    n = n * 10;
2499 		    ++ndig;
2500 		}
2501 		tss->fraction = n;
2502 		m |= 4;
2503 		i = 0;
2504 	    }
2505 	default:
2506 	skip:
2507 	    in = '\0';
2508 	skip2:
2509 	    while (*q && !ISDIGIT(*q)) {
2510 		if ((q[0] == 'a' || q[0] == 'A') &&
2511 		    (q[1] == 'm' || q[1] == 'M')) {
2512 		    ampm = 0;
2513 		    ++q;
2514 		} else if ((q[0] == 'p' || q[0] == 'P') &&
2515 			   (q[1] == 'm' || q[1] == 'M')) {
2516 		    ampm = 1;
2517 		    ++q;
2518 		}
2519 		++q;
2520 	    }
2521 	}
2522 	p = q;
2523     }
2524     if ((m & 7) > 1 && (m & 8)) {
2525 	/* ISO8601 timezone */
2526 	if (p > str && ISDIGIT(*p)) {
2527 	    int nn, sign;
2528 
2529 	    q = p - 1;
2530 	    if (*q != '+' && *q != '-') {
2531 		goto done;
2532 	    }
2533 	    sign = (*q == '+') ? -1 : 1;
2534 	    q = NULL;
2535 	    n = strtol(p, &q, 10);
2536 	    if (!q || *q++ != ':' || !ISDIGIT(*q)) {
2537 		goto done;
2538 	    }
2539 	    p = q;
2540 	    q = NULL;
2541 	    nn = strtol(p, &q, 10);
2542 	    tss->minute += nn * sign;
2543 	    if ((SQLSMALLINT) tss->minute < 0) {
2544 		tss->hour -= 1;
2545 		tss->minute += 60;
2546 	    } else if (tss->minute >= 60) {
2547 		tss->hour += 1;
2548 		tss->minute -= 60;
2549 	    }
2550 	    tss->hour += n * sign;
2551 	    if ((SQLSMALLINT) tss->hour < 0) {
2552 		tss->day -= 1;
2553 		tss->hour += 24;
2554 	    } else if (tss->hour >= 24) {
2555 		tss->day += 1;
2556 		tss->hour -= 24;
2557 	    }
2558 	    if ((short) tss->day < 1 || tss->day >= 28) {
2559 		int mday, pday, pmon;
2560 
2561 		mday = getmdays(tss->year, tss->month);
2562 		pmon = tss->month - 1;
2563 		if (pmon < 1) {
2564 		    pmon = 12;
2565 		}
2566 		pday = getmdays(tss->year, pmon);
2567 		if ((SQLSMALLINT) tss->day < 1) {
2568 		    tss->month -= 1;
2569 		    tss->day = pday;
2570 		} else if (tss->day > mday) {
2571 		    tss->month += 1;
2572 		    tss->day = 1;
2573 		}
2574 		if ((SQLSMALLINT) tss->month < 1) {
2575 		    tss->year -= 1;
2576 		    tss->month = 12;
2577 		} else if (tss->month > 12) {
2578 		    tss->year += 1;
2579 		    tss->month = 1;
2580 		}
2581 	    }
2582 	}
2583     }
2584 done:
2585     if ((m & 1) &&
2586 	(tss->month < 1 || tss->month > 12 ||
2587 	 tss->day < 1 || tss->day > getmdays(tss->year, tss->month))) {
2588 	if (sepc == '/') {
2589 	    /* Try MM/DD/YYYY format */
2590 	    int t[3];
2591 
2592 	    t[0] = tss->year;
2593 	    t[1] = tss->month;
2594 	    t[2] = tss->day;
2595 	    tss->year = t[2];
2596 	    tss->day = t[1];
2597 	    tss->month = t[0];
2598 	}
2599     }
2600     /* Replace missing year/month/day with current date */
2601     if (!err && (m & 1) == 0) {
2602 #ifdef _WIN32
2603 	SYSTEMTIME t;
2604 
2605 	GetLocalTime(&t);
2606 	tss->year = t.wYear;
2607 	tss->month = t.wMonth;
2608 	tss->day = t.wDay;
2609 #else
2610 	struct timeval tv;
2611 	struct tm tm;
2612 
2613 	gettimeofday(&tv, NULL);
2614 	tm = *localtime(&tv.tv_sec);
2615 	tss->year = tm.tm_year + 1900;
2616 	tss->month = tm.tm_mon + 1;
2617 	tss->day = tm.tm_mday;
2618 #endif
2619     }
2620     /* Normalize fraction */
2621     if (tss->fraction < 0) {
2622 	tss->fraction = 0;
2623     }
2624     /* Final check for overflow */
2625     if (err ||
2626 	tss->month < 1 || tss->month > 12 ||
2627 	tss->day < 1 || tss->day > getmdays(tss->year, tss->month) ||
2628 	tss->hour > 23 || tss->minute > 59 || tss->second > 59) {
2629 	return -1;
2630     }
2631     if ((m & 7) > 1) {
2632 	if (ampm > 0) {
2633 	    if (tss->hour < 12) {
2634 		tss->hour += 12;
2635 	    }
2636 	} else if (ampm == 0) {
2637 	    if (tss->hour == 12) {
2638 		tss->hour = 0;
2639 	    }
2640 	}
2641     }
2642     return ((m & 7) < 1) ? -1 : 0;
2643 }
2644 
2645 /**
2646  * Get boolean flag from string.
2647  * @param string string to be inspected
2648  * @result true or false
2649  */
2650 
2651 static int
getbool(char * string)2652 getbool(char *string)
2653 {
2654     if (string) {
2655 	return string[0] && strchr("Yy123456789Tt", string[0]) != NULL;
2656     }
2657     return 0;
2658 }
2659 
2660 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
2661 /**
2662  * SQLite trace callback
2663  * @param arg DBC pointer
2664  */
2665 
2666 static void
dbtrace(void * arg,const char * msg)2667 dbtrace(void *arg, const char *msg)
2668 {
2669     DBC *d = (DBC *) arg;
2670 
2671     if (msg && d->trace) {
2672 	int len = strlen(msg);
2673 
2674 	if (len > 0) {
2675 	    char *end = "\n";
2676 
2677 	    if (msg[len - 1] != ';') {
2678 		end = ";\n";
2679 	    }
2680 	    fprintf(d->trace, "%s%s", msg, end);
2681 	    fflush(d->trace);
2682 	}
2683     }
2684 }
2685 
2686 /**
2687  * Trace function for SQLite return codes
2688  * @param rc SQLite return code
2689  * @param err error string or NULL
2690  */
2691 
2692 static void
dbtracerc(DBC * d,int rc,char * err)2693 dbtracerc(DBC *d, int rc, char *err)
2694 {
2695     if (rc != SQLITE_OK && d->trace) {
2696 	fprintf(d->trace, "-- SQLITE ERROR CODE %d", rc);
2697 	fprintf(d->trace, err ? ": %s\n" : "\n", err);
2698 	fflush(d->trace);
2699     }
2700 }
2701 #else
2702 
2703 #define dbtracerc(a,b,c)
2704 
2705 #endif
2706 
2707 /**
2708  * Open SQLite database file given file name and flags.
2709  * @param d DBC pointer
2710  * @param name file name
2711  * @param dsn data source name
2712  * @param sflag STEPAPI flag
2713  * @param sflag NoTXN flag
2714  * @param busy busy/lock timeout
2715  * @result ODBC error code
2716  */
2717 
2718 static SQLRETURN
dbopen(DBC * d,char * name,char * dsn,char * sflag,char * ntflag,char * busy)2719 dbopen(DBC *d, char *name, char *dsn, char *sflag, char *ntflag, char *busy)
2720 {
2721     char *errp = NULL, *endp = NULL;
2722     int tmp, busyto = 100000;
2723 #if defined(_WIN32) || defined(_WIN64)
2724     char expname[MAX_PATH];
2725 #endif
2726 
2727     if (d->sqlite) {
2728 	sqlite_close(d->sqlite);
2729 	d->sqlite = NULL;
2730     }
2731 #if defined(_WIN32) || defined(_WIN64)
2732     expname[0] = '\0';
2733     tmp = ExpandEnvironmentStrings(name, expname, sizeof (expname));
2734     if (tmp <= sizeof (expname)) {
2735 	name = expname;
2736     }
2737 #endif
2738     d->sqlite = sqlite_open(name, 0, &errp);
2739     if (d->sqlite == NULL) {
2740 connfail:
2741 	setstatd(d, -1, "%s", (*d->ov3) ? "HY000" : "S1000",
2742 		 errp ? errp : "connect failed");
2743 	if (errp) {
2744 	    sqlite_freemem(errp);
2745 	    errp = NULL;
2746 	}
2747 	return SQL_ERROR;
2748     }
2749     if (errp) {
2750 	sqlite_freemem(errp);
2751 	errp = NULL;
2752     }
2753 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
2754     if (d->trace) {
2755 	sqlite_trace(d->sqlite, dbtrace, d);
2756     }
2757 #endif
2758     d->step_enable = getbool(sflag);
2759     d->trans_disable = getbool(ntflag);
2760     d->curtype = d->step_enable ?
2761 	SQL_CURSOR_FORWARD_ONLY : SQL_CURSOR_STATIC;
2762     tmp = strtol(busy, &endp, 0);
2763     if (endp && *endp == '\0' && endp != busy) {
2764 	busyto = tmp;
2765     }
2766     if (busyto < 1 || busyto > 1000000) {
2767 	busyto = 1000000;
2768     }
2769     d->timeout = busyto;
2770     freep(&d->dbname);
2771     d->dbname = xstrdup(name);
2772     freep(&d->dsn);
2773     d->dsn = xstrdup(dsn);
2774     if (setsqliteopts(d->sqlite, d) != SQLITE_OK) {
2775 	sqlite_close(d->sqlite);
2776 	d->sqlite = NULL;
2777 	goto connfail;
2778     }
2779 #if defined(_WIN32) || defined(_WIN64)
2780     {
2781 	char pname[MAX_PATH];
2782 	HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
2783 			       FALSE, GetCurrentProcessId());
2784 
2785 	pname[0] = '\0';
2786 	if (h) {
2787 	    HMODULE m = NULL, l = LoadLibrary("psapi.dll");
2788 	    DWORD need;
2789 	    typedef BOOL (WINAPI *epmfunc)(HANDLE, HMODULE *, DWORD, LPDWORD);
2790 	    typedef BOOL (WINAPI *gmbfunc)(HANDLE, HMODULE, LPSTR, DWORD);
2791 	    epmfunc epm;
2792 	    gmbfunc gmb;
2793 
2794 	    if (l) {
2795 		epm = (epmfunc) GetProcAddress(l, "EnumProcessModules");
2796 		gmb = (gmbfunc) GetProcAddress(l, "GetModuleBaseNameA");
2797 		if (epm && gmb && epm(h, &m, sizeof (m), &need)) {
2798 		    gmb(h, m, pname, sizeof (pname));
2799 		}
2800 		FreeLibrary(l);
2801 	    }
2802 	    CloseHandle(h);
2803 	}
2804 	d->xcelqrx = strncasecmp(pname, "EXCEL", 5) == 0 ||
2805 		     strncasecmp(pname, "MSQRY", 5) == 0;
2806 	if (d->trace && d->xcelqrx) {
2807 	    fprintf(d->trace, "-- enabled EXCEL quirks\n");
2808 	    fflush(d->trace);
2809 	}
2810     }
2811 #endif
2812     return SQL_SUCCESS;
2813 }
2814 
2815 /**
2816  * Do one VM step gathering one result row
2817  * @param s statement pointer
2818  * @result ODBC error code
2819  */
2820 
2821 static int
vm_step(STMT * s)2822 vm_step(STMT *s)
2823 {
2824     DBC *d = (DBC *) s->dbc;
2825     char **rowd = NULL, *errp = NULL;
2826     const char **values, **cols;
2827     int i, ncols, rc;
2828 
2829     if (s != d->vm_stmt || !s->vm) {
2830 	setstat(s, -1, "stale statement", (*s->ov3) ? "HY000" : "S1000");
2831 	return SQL_ERROR;
2832     }
2833     rc = sqlite_step(s->vm, &ncols, &values, &cols);
2834     if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
2835 	++d->vm_rownum;
2836 	if (d->vm_rownum == 0 && cols && ncols > 0) {
2837 	    int size;
2838 	    char *p;
2839 	    COL *dyncols;
2840 
2841 	    for (i = size = 0; i < ncols; i++) {
2842 		size += 3 + 3 * strlen(cols[i]);
2843 	    }
2844 	    dyncols = xmalloc(ncols * sizeof (COL) + size);
2845 	    if (!dyncols) {
2846 		freedyncols(s);
2847 		s->ncols = 0;
2848 		sqlite_finalize(s->vm, NULL);
2849 		s->vm = NULL;
2850 		d->vm_stmt = NULL;
2851 		return nomem(s);
2852 	    }
2853 	    p = (char *) (dyncols + ncols);
2854 	    for (i = 0; i < ncols; i++) {
2855 		char *q;
2856 
2857 		dyncols[i].db = ((DBC *) (s->dbc))->dbname;
2858 		strcpy(p, cols[i]);
2859 		dyncols[i].label = p;
2860 		p += strlen(p) + 1;
2861 		q = strchr(cols[i], '.');
2862 		if (q) {
2863 		    dyncols[i].table = p;
2864 		    strncpy(p, cols[i], q - cols[i]);
2865 		    p[q - cols[i]] = '\0';
2866 		    p += strlen(p) + 1;
2867 		    strcpy(p, q + 1);
2868 		    dyncols[i].column = p;
2869 		    p += strlen(p) + 1;
2870 		} else {
2871 		    dyncols[i].table = "";
2872 		    strcpy(p, cols[i]);
2873 		    dyncols[i].column = p;
2874 		    p += strlen(p) + 1;
2875 		}
2876 		if (s->longnames) {
2877 		    dyncols[i].column = dyncols[i].label;
2878 		}
2879 #ifdef SQL_LONGVARCHAR
2880 		dyncols[i].type = SQL_LONGVARCHAR;
2881 		dyncols[i].size = 65535;
2882 #else
2883 		dyncols[i].type = SQL_VARCHAR;
2884 		dyncols[i].size = 255;
2885 #endif
2886 		dyncols[i].index = i;
2887 		dyncols[i].scale = 0;
2888 		dyncols[i].prec = 0;
2889 		dyncols[i].nosign = 1;
2890 		dyncols[i].autoinc = SQL_FALSE;
2891 		dyncols[i].notnull = SQL_NULLABLE;
2892 		dyncols[i].typename = NULL;
2893 	    }
2894 	    freedyncols(s);
2895 	    s->ncols = s->dcols = ncols;
2896 	    s->dyncols = s->cols = dyncols;
2897 	    fixupdyncols(s, d->sqlite, cols + ncols);
2898 	    mkbindcols(s, s->ncols);
2899 	}
2900 	if (!cols || ncols <= 0) {
2901 	    goto killvm;
2902 	}
2903 	if (!values) {
2904 	    if (rc == SQLITE_DONE) {
2905 		freeresult(s, 0);
2906 		s->nrows = 0;
2907 		sqlite_finalize(s->vm, NULL);
2908 		s->vm = NULL;
2909 		d->vm_stmt = NULL;
2910 		return SQL_SUCCESS;
2911 	    }
2912 	    goto killvm;
2913 	}
2914 	rowd = xmalloc((1 + 2 * ncols) * sizeof (char *));
2915 	if (rowd) {
2916 	    rowd[0] = (char *) ((PTRDIFF_T) (ncols * 2));
2917 	    ++rowd;
2918 	    for (i = 0; i < ncols; i++) {
2919 		rowd[i] = NULL;
2920 		rowd[i + ncols] = xstrdup(values[i]);
2921 	    }
2922 	    for (i = 0; i < ncols; i++) {
2923 		if (values[i] && !rowd[i + ncols]) {
2924 		    freerows(rowd);
2925 		    rowd = 0;
2926 		    break;
2927 		}
2928 	    }
2929 	}
2930 	if (rowd) {
2931 	    freeresult(s, 0);
2932 	    s->nrows = 1;
2933 	    s->rows = rowd;
2934 	    s->rowfree = freerows;
2935 	    if (rc == SQLITE_DONE) {
2936 		sqlite_finalize(s->vm, NULL);
2937 		s->vm = NULL;
2938 		d->vm_stmt = NULL;
2939 	    }
2940 	    return SQL_SUCCESS;
2941 	}
2942     }
2943 killvm:
2944     sqlite_finalize(s->vm, &errp);
2945     s->vm = NULL;
2946     d->vm_stmt = NULL;
2947     setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
2948 	    errp ? errp : "unknown error", rc);
2949     if (errp) {
2950 	sqlite_freemem(errp);
2951 	errp = NULL;
2952     }
2953     return SQL_ERROR;
2954 }
2955 
2956 /**
2957  * Stop running VM
2958  * @param s statement pointer
2959  */
2960 
2961 static void
vm_end(STMT * s)2962 vm_end(STMT *s)
2963 {
2964     DBC *d;
2965 
2966     if (!s || !s->vm) {
2967 	return;
2968     }
2969     d = (DBC *) s->dbc;
2970     if (d) {
2971 	d->busyint = 0;
2972     }
2973     sqlite_finalize(s->vm, NULL);
2974     s->vm = NULL;
2975     d->vm_stmt = NULL;
2976 }
2977 
2978 /**
2979  * Conditionally stop running VM
2980  * @param s statement pointer
2981  */
2982 
2983 static void
vm_end_if(STMT * s)2984 vm_end_if(STMT *s)
2985 {
2986     DBC *d = (DBC *) s->dbc;
2987 
2988     if (d) {
2989 	d->busyint = 0;
2990     }
2991     if (d && d->vm_stmt == s) {
2992 	vm_end(s);
2993     }
2994 }
2995 
2996 /**
2997  * Start VM for execution of SELECT statement.
2998  * @param s statement pointer
2999  * @param params string array of statement parameters
3000  * @result ODBC error code
3001  */
3002 
3003 static SQLRETURN
vm_start(STMT * s,char ** params)3004 vm_start(STMT *s, char **params)
3005 {
3006     DBC *d = (DBC *) s->dbc;
3007     char *errp = NULL, *sql = NULL;
3008     const char *endp;
3009     sqlite_vm *vm;
3010     int rc;
3011 
3012 #ifdef CANT_PASS_VALIST_AS_CHARPTR
3013     if (params) {
3014 	sql = sqlite_mprintf((char *) s->query,
3015 			     params[0], params[1],
3016 			     params[2], params[3],
3017 			     params[4], params[5],
3018 			     params[6], params[7],
3019 			     params[8], params[9],
3020 			     params[10], params[11],
3021 			     params[12], params[13],
3022 			     params[14], params[15],
3023 			     params[16], params[17],
3024 			     params[18], params[19],
3025 			     params[20], params[21],
3026 			     params[22], params[23],
3027 			     params[24], params[25],
3028 			     params[26], params[27],
3029 			     params[28], params[29],
3030 			     params[30], params[31]);
3031     } else {
3032 	sql = sqlite_mprintf((char *) s->query);
3033     }
3034 #else
3035     sql = sqlite_vmprintf((char *) s->query, (char *) params);
3036 #endif
3037     if (!sql) {
3038 	return nomem(s);
3039     }
3040     rc = sqlite_compile(d->sqlite, sql, &endp, &vm, &errp);
3041     dbtracerc(d, rc, errp);
3042     sqlite_freemem(sql);
3043     if (rc != SQLITE_OK) {
3044 	setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
3045 		errp ? errp : "unknown error", rc);
3046 	if (errp) {
3047 	    sqlite_freemem(errp);
3048 	    errp = NULL;
3049 	}
3050 	return SQL_ERROR;
3051     }
3052     s->vm = vm;
3053     d->vm_stmt = s;
3054     d->vm_rownum = -1;
3055     return SQL_SUCCESS;
3056 }
3057 
3058 /**
3059  * Function not implemented.
3060  */
3061 
3062 SQLRETURN SQL_API
SQLBulkOperations(SQLHSTMT stmt,SQLSMALLINT oper)3063 SQLBulkOperations(SQLHSTMT stmt, SQLSMALLINT oper)
3064 {
3065     SQLRETURN ret;
3066 
3067     HSTMT_LOCK(stmt);
3068     ret = drvunimplstmt(stmt);
3069     HSTMT_UNLOCK(stmt);
3070     return ret;
3071 }
3072 
3073 #ifndef WINTERFACE
3074 /**
3075  * Function not implemented.
3076  */
3077 
3078 SQLRETURN SQL_API
SQLDataSources(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)3079 SQLDataSources(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *srvname,
3080 	       SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
3081 	       SQLCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
3082 {
3083     if (env == SQL_NULL_HENV) {
3084 	return SQL_INVALID_HANDLE;
3085     }
3086     return SQL_ERROR;
3087 }
3088 #endif
3089 
3090 #ifdef WINTERFACE
3091 /**
3092  * Function not implemented.
3093  */
3094 
3095 SQLRETURN SQL_API
SQLDataSourcesW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * srvname,SQLSMALLINT buflen1,SQLSMALLINT * lenp1,SQLWCHAR * desc,SQLSMALLINT buflen2,SQLSMALLINT * lenp2)3096 SQLDataSourcesW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *srvname,
3097 		SQLSMALLINT buflen1, SQLSMALLINT *lenp1,
3098 		SQLWCHAR *desc, SQLSMALLINT buflen2, SQLSMALLINT *lenp2)
3099 {
3100     if (env == SQL_NULL_HENV) {
3101 	return SQL_INVALID_HANDLE;
3102     }
3103     return SQL_ERROR;
3104 }
3105 #endif
3106 
3107 #ifndef WINTERFACE
3108 /**
3109  * Function not implemented.
3110  */
3111 
3112 SQLRETURN SQL_API
SQLDrivers(SQLHENV env,SQLUSMALLINT dir,SQLCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)3113 SQLDrivers(SQLHENV env, SQLUSMALLINT dir, SQLCHAR *drvdesc,
3114 	   SQLSMALLINT descmax, SQLSMALLINT *desclenp,
3115 	   SQLCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
3116 {
3117     if (env == SQL_NULL_HENV) {
3118 	return SQL_INVALID_HANDLE;
3119     }
3120     return SQL_ERROR;
3121 }
3122 #endif
3123 
3124 #ifdef WINTERFACE
3125 /**
3126  * Function not implemented.
3127  */
3128 
3129 SQLRETURN SQL_API
SQLDriversW(SQLHENV env,SQLUSMALLINT dir,SQLWCHAR * drvdesc,SQLSMALLINT descmax,SQLSMALLINT * desclenp,SQLWCHAR * drvattr,SQLSMALLINT attrmax,SQLSMALLINT * attrlenp)3130 SQLDriversW(SQLHENV env, SQLUSMALLINT dir, SQLWCHAR *drvdesc,
3131 	    SQLSMALLINT descmax, SQLSMALLINT *desclenp,
3132 	    SQLWCHAR *drvattr, SQLSMALLINT attrmax, SQLSMALLINT *attrlenp)
3133 {
3134     if (env == SQL_NULL_HENV) {
3135 	return SQL_INVALID_HANDLE;
3136     }
3137     return SQL_ERROR;
3138 }
3139 #endif
3140 
3141 #ifndef WINTERFACE
3142 /**
3143  * Function not implemented.
3144  */
3145 
3146 SQLRETURN SQL_API
SQLBrowseConnect(SQLHDBC dbc,SQLCHAR * connin,SQLSMALLINT conninLen,SQLCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)3147 SQLBrowseConnect(SQLHDBC dbc, SQLCHAR *connin, SQLSMALLINT conninLen,
3148 		 SQLCHAR *connout, SQLSMALLINT connoutMax,
3149 		 SQLSMALLINT *connoutLen)
3150 {
3151     SQLRETURN ret;
3152 
3153     HDBC_LOCK(dbc);
3154     ret = drvunimpldbc(dbc);
3155     HDBC_UNLOCK(dbc);
3156     return ret;
3157 }
3158 #endif
3159 
3160 #ifdef WINTERFACE
3161 /**
3162  * Function not implemented.
3163  */
3164 
3165 SQLRETURN SQL_API
SQLBrowseConnectW(SQLHDBC dbc,SQLWCHAR * connin,SQLSMALLINT conninLen,SQLWCHAR * connout,SQLSMALLINT connoutMax,SQLSMALLINT * connoutLen)3166 SQLBrowseConnectW(SQLHDBC dbc, SQLWCHAR *connin, SQLSMALLINT conninLen,
3167 		  SQLWCHAR *connout, SQLSMALLINT connoutMax,
3168 		  SQLSMALLINT *connoutLen)
3169 {
3170     SQLRETURN ret;
3171 
3172     HDBC_LOCK(dbc);
3173     ret = drvunimpldbc(dbc);
3174     HDBC_UNLOCK(dbc);
3175     return ret;
3176 }
3177 #endif
3178 
3179 /**
3180  * SQLite function "current_time_local" etc.
3181  * @param context SQLite function context
3182  * @param argc number arguments
3183  * @param argv argument vector
3184  */
3185 
3186 static void
time_func(sqlite_func * context,int argc,const char ** argv)3187 time_func(sqlite_func *context, int argc, const char **argv)
3188 {
3189     char buf[128];
3190     PTRDIFF_T what = (PTRDIFF_T) sqlite_user_data(context);
3191 #if defined(_WIN32) || defined(_WIN64)
3192     SYSTEMTIME st;
3193 
3194     if (what & 1) {
3195 	GetSystemTime(&st);
3196     } else {
3197 	GetLocalTime(&st);
3198     }
3199     if (what & 4) {
3200 	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
3201 		st.wYear, st.wMonth, st.wDay,
3202 		st.wHour, st.wMinute, st.wSecond);
3203     } else if (what & 2) {
3204 	sprintf(buf, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
3205     } else {
3206 	sprintf(buf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
3207     }
3208 #else
3209     time_t t;
3210     struct tm tm;
3211 
3212     time(&t);
3213     if (what & 1) {
3214 #ifdef HAVE_GMTIME_R
3215 	gmtime_r(&t, &tm);
3216 #else
3217 	tm = *gmtime(&t);
3218 #endif
3219     } else {
3220 #ifdef HAVE_LOCALTIME_R
3221 	localtime_r(&t, &tm);
3222 #else
3223 	tm = *localtime(&t);
3224 #endif
3225     }
3226     if (what & 4) {
3227 	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
3228 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
3229 		tm.tm_hour, tm.tm_min, tm.tm_sec);
3230     } else if (what & 2) {
3231 	sprintf(buf, "%04d-%02d-%02d",
3232 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
3233     } else {
3234 	sprintf(buf, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
3235     }
3236 #endif
3237     sqlite_set_result_string(context, buf, -1);
3238 }
3239 
3240 #if (HAVE_ENCDEC)
3241 static const char hexdigits[] = "0123456789ABCDEFabcdef";
3242 
3243 /**
3244  * SQLite function "hextobin"
3245  * @param context SQLite function context
3246  * @param argc number arguments
3247  * @param argv argument vector
3248  */
3249 
3250 static void
hextobin_func(sqlite_func * context,int argc,const char ** argv)3251 hextobin_func(sqlite_func *context, int argc, const char **argv)
3252 {
3253     int i, len;
3254     char *bin, *p;
3255 
3256     if (argc < 1) {
3257 	return;
3258     }
3259     if (!argv[0]) {
3260 	sqlite_set_result_string(context, NULL, 4);
3261 	return;
3262     }
3263     len = strlen(argv[0]) / 2;
3264     bin = xmalloc(len + 1);
3265     if (!bin) {
3266 oom:
3267 	sqlite_set_result_error(context, "out of memory", -1);
3268 	return;
3269     }
3270     if (len <= 0) {
3271 	sqlite_set_result_string(context, bin, 0);
3272 	freep(&bin);
3273 	return;
3274     }
3275     for (i = 0, p = (char *) argv[0]; i < len; i++) {
3276 	char *x;
3277 	int v;
3278 
3279 	if (!*p || !(x = strchr(hexdigits, *p))) {
3280 	    goto converr;
3281 	}
3282 	v = x - hexdigits;
3283 	bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
3284 	++p;
3285 	if (!*p || !(x = strchr(hexdigits, *p))) {
3286 converr:
3287 	    freep(&bin);
3288 	    sqlite_set_result_error(context, "conversion error", -1);
3289 	    return;
3290 	}
3291 	v = x - hexdigits;
3292 	bin[i] |= (v >= 16) ? (v - 6) : v;
3293 	++p;
3294     }
3295     i = sqlite_encode_binary((unsigned char *) bin, len, 0);
3296     p = xmalloc(i + 1);
3297     if (!p) {
3298 	freep(&bin);
3299 	goto oom;
3300     }
3301     i = sqlite_encode_binary((unsigned char *) bin, len,
3302 			     (unsigned char *) p);
3303     sqlite_set_result_string(context, p, i);
3304     freep(&bin);
3305     freep(&p);
3306 }
3307 
3308 /**
3309  * SQLite function "bintohex"
3310  * @param context SQLite function context
3311  * @param argc number arguments
3312  * @param argv argument vector
3313  */
3314 
3315 static void
bintohex_func(sqlite_func * context,int argc,const char ** argv)3316 bintohex_func(sqlite_func *context, int argc, const char **argv)
3317 {
3318     int i, k, len;
3319     char *bin, *p;
3320 
3321     if (argc < 1) {
3322 	return;
3323     }
3324     if (!argv[0]) {
3325 empty:
3326 	sqlite_set_result_string(context, "", 0);
3327 	return;
3328     }
3329     bin = xmalloc(strlen(argv[0]) + 1);
3330     if (!bin) {
3331 oom:
3332 	sqlite_set_result_error(context, "out of memory", -1);
3333 	return;
3334     }
3335     len = sqlite_decode_binary((unsigned char *) argv[0],
3336 			       (unsigned char *) bin);
3337     if (len < 0) {
3338 	freep(&bin);
3339 	sqlite_set_result_error(context, "error decoding binary data", -1);
3340 	return;
3341     }
3342     if (len == 0) {
3343 	goto empty;
3344     }
3345     p = xmalloc(len * 2 + 1);
3346     if (!p) {
3347 	goto oom;
3348     }
3349     for (i = 0, k = 0; i < len; i++) {
3350 	p[k++] = hexdigits[(bin[i] >> 4) & 0x0f];
3351 	p[k++] = hexdigits[bin[i] & 0x0f];
3352     }
3353     p[k] = '\0';
3354     sqlite_set_result_string(context, p, k);
3355     freep(&bin);
3356     freep(&p);
3357 }
3358 
3359 /**
3360  * Encode hex (char) parameter to SQLite binary string.
3361  * @param s STMT pointer
3362  * @param p BINDPARM pointer
3363  * @result ODBD error code
3364  */
3365 
3366 static SQLRETURN
hextobin(STMT * s,BINDPARM * p)3367 hextobin(STMT *s, BINDPARM *p)
3368 {
3369     int i, len = strlen(p->param) / 2;
3370     char *bin = xmalloc(len + 1), *pp;
3371 
3372     if (!bin) {
3373 	return nomem(s);
3374     }
3375     if (len <= 0) {
3376 	bin[0] = '\0';
3377 	freep(&p->parbuf);
3378 	p->parbuf = p->param = bin;
3379 	p->len = 0;
3380 	return SQL_SUCCESS;
3381     }
3382     for (i = 0, pp = (char *) p->param; i < len; i++) {
3383 	char *x;
3384 	int v;
3385 
3386 	if (!*pp || !(x = strchr(hexdigits, *pp))) {
3387 	    goto converr;
3388 	}
3389 	v = x - hexdigits;
3390 	bin[i] = (v >= 16) ? ((v - 6) << 4) : (v << 4);
3391 	++pp;
3392 	if (!*pp || !(x = strchr(hexdigits, *pp))) {
3393 converr:
3394 	    freep(&bin);
3395 	    setstat(s, -1, "conversion error", (*s->ov3) ? "HY000" : "S1000");
3396 	    return SQL_ERROR;
3397 	}
3398 	v = x - hexdigits;
3399 	bin[i] |= (v >= 16) ? (v - 6) : v;
3400 	++pp;
3401     }
3402     i = sqlite_encode_binary((unsigned char *) bin, len, 0);
3403     pp = xmalloc(i + 1);
3404     if (!pp) {
3405 	freep(&bin);
3406 	return nomem(s);
3407     }
3408     p->len = sqlite_encode_binary((unsigned char *) bin, len,
3409 				  (unsigned char *) pp);
3410     freep(&p->parbuf);
3411     p->parbuf = p->param = pp;
3412     freep(&bin);
3413     return SQL_SUCCESS;
3414 }
3415 #endif
3416 
3417 /**
3418  * Internal put (partial) parameter data into executing statement.
3419  * @param stmt statement handle
3420  * @param data pointer to data
3421  * @param len length of data
3422  * @result ODBC error code
3423  */
3424 
3425 static SQLRETURN
drvputdata(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)3426 drvputdata(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
3427 {
3428     STMT *s;
3429     int i, dlen, done = 0;
3430     BINDPARM *p;
3431 
3432     if (stmt == SQL_NULL_HSTMT) {
3433 	return SQL_INVALID_HANDLE;
3434     }
3435     s = (STMT *) stmt;
3436     if (!s->query || s->nparams <= 0) {
3437 seqerr:
3438 	setstat(s, -1, "sequence error", "HY010");
3439 	return SQL_ERROR;
3440     }
3441     for (i = (s->pdcount < 0) ? 0 : s->pdcount; i < s->nparams; i++) {
3442 	p = &s->bindparms[i];
3443 	if (p->need > 0) {
3444 	    int type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
3445 
3446 	    if (len == SQL_NULL_DATA) {
3447 		freep(&p->parbuf);
3448 		p->param = NULL;
3449 		p->len = SQL_NULL_DATA;
3450 		p->need = -1;
3451 	    } else if (type != SQL_C_CHAR
3452 #ifdef WCHARSUPPORT
3453 		       && type != SQL_C_WCHAR
3454 #endif
3455 #if (HAVE_ENCDEC)
3456 		       && type != SQL_C_BINARY
3457 #endif
3458 		      ) {
3459 		int size = 0;
3460 
3461 		switch (type) {
3462 		case SQL_C_TINYINT:
3463 		case SQL_C_UTINYINT:
3464 		case SQL_C_STINYINT:
3465 #ifdef SQL_BIT
3466 		case SQL_C_BIT:
3467 #endif
3468 		    size = sizeof (SQLCHAR);
3469 		    break;
3470 		case SQL_C_SHORT:
3471 		case SQL_C_USHORT:
3472 		case SQL_C_SSHORT:
3473 		    size = sizeof (SQLSMALLINT);
3474 		    break;
3475 		case SQL_C_LONG:
3476 		case SQL_C_ULONG:
3477 		case SQL_C_SLONG:
3478 		    size = sizeof (SQLINTEGER);
3479 		    break;
3480 		case SQL_C_FLOAT:
3481 		    size = sizeof (float);
3482 		    break;
3483 		case SQL_C_DOUBLE:
3484 		    size = sizeof (double);
3485 		    break;
3486 #ifdef SQL_C_TYPE_DATE
3487 		case SQL_C_TYPE_DATE:
3488 #endif
3489 		case SQL_C_DATE:
3490 		    size = sizeof (DATE_STRUCT);
3491 		    break;
3492 #ifdef SQL_C_TYPE_DATE
3493 		case SQL_C_TYPE_TIME:
3494 #endif
3495 		case SQL_C_TIME:
3496 		    size = sizeof (TIME_STRUCT);
3497 		    break;
3498 #ifdef SQL_C_TYPE_DATE
3499 		case SQL_C_TYPE_TIMESTAMP:
3500 #endif
3501 		case SQL_C_TIMESTAMP:
3502 		    size = sizeof (TIMESTAMP_STRUCT);
3503 		    break;
3504 		}
3505 		freep(&p->parbuf);
3506 		p->parbuf = xmalloc(size);
3507 		if (!p->parbuf) {
3508 		    return nomem(s);
3509 		}
3510 		p->param = p->parbuf;
3511 		memcpy(p->param, data, size);
3512 		p->len = size;
3513 		p->need = -1;
3514 	    } else if (len == SQL_NTS && (
3515 		       type == SQL_C_CHAR
3516 #ifdef WCHARSUPPORT
3517 		       || type == SQL_C_WCHAR
3518 #endif
3519 		       )) {
3520 		char *dp = data;
3521 
3522 #ifdef WCHARSUPPORT
3523 		if (type == SQL_C_WCHAR) {
3524 		    dp = uc_to_utf(data, len);
3525 		    if (!dp) {
3526 			return nomem(s);
3527 		    }
3528 		}
3529 #endif
3530 		dlen = strlen(dp);
3531 		freep(&p->parbuf);
3532 		p->parbuf = xmalloc(dlen + 1);
3533 		if (!p->parbuf) {
3534 #ifdef WCHARSUPPORT
3535 		    if (dp != data) {
3536 			uc_free(dp);
3537 		    }
3538 #endif
3539 		    return nomem(s);
3540 		}
3541 		p->param = p->parbuf;
3542 		strcpy(p->param, dp);
3543 #ifdef WCHARSUPPORT
3544 		if (dp != data) {
3545 		    uc_free(dp);
3546 		}
3547 #endif
3548 		p->len = dlen;
3549 		p->need = -1;
3550 	    } else if (len < 0) {
3551 		setstat(s, -1, "invalid length", "HY090");
3552 		return SQL_ERROR;
3553 	    } else {
3554 		dlen = min(p->len - p->offs, len);
3555 		if (!p->param) {
3556 		    setstat(s, -1, "no memory for parameter", "HY013");
3557 		    return SQL_ERROR;
3558 		}
3559 		memcpy((char *) p->param + p->offs, data, dlen);
3560 		p->offs += dlen;
3561 		if (p->offs >= p->len) {
3562 #ifdef WCHARSUPPORT
3563 		    if (type == SQL_C_WCHAR) {
3564 			char *dp = uc_to_utf(p->param, p->len);
3565 			char *np;
3566 			int nlen;
3567 
3568 			if (!dp) {
3569 			    return nomem(s);
3570 			}
3571 			nlen = strlen(dp);
3572 			np = xmalloc(nlen + 1);
3573 			if (!np) {
3574 			    uc_free(dp);
3575 			    return nomem(s);
3576 			}
3577 			strcpy(np, dp);
3578 			uc_free(dp);
3579 			if (p->param == p->parbuf) {
3580 			    freep(&p->parbuf);
3581 			}
3582 			p->parbuf = p->param = np;
3583 			p->len = nlen;
3584 		    } else {
3585 			*((char *) p->param + p->len) = '\0';
3586 		    }
3587 #else
3588 #if defined(_WIN32) || defined(_WIN64)
3589 		    if (p->type == SQL_C_WCHAR &&
3590 			(p->stype == SQL_VARCHAR ||
3591 			 p->stype == SQL_LONGVARCHAR) &&
3592 			 p->len == p->coldef * sizeof (SQLWCHAR)) {
3593 			/* fix for MS-Access */
3594 			p->len = p->coldef;
3595 		    }
3596 #endif
3597 		    *((char *) p->param + p->len) = '\0';
3598 #endif
3599 #if (HAVE_ENCDEC)
3600 		    if ((p->stype == SQL_BINARY ||
3601 			 p->stype == SQL_VARBINARY ||
3602 			 p->stype == SQL_LONGVARBINARY) &&
3603 #ifdef WCHARSUPPORT
3604 			(type == SQL_C_CHAR || type == SQL_C_WCHAR)
3605 #else
3606 			type == SQL_C_CHAR
3607 #endif
3608 		       ) {
3609 			if (hextobin(s, p) != SQL_SUCCESS) {
3610 			    return SQL_ERROR;
3611 			}
3612 		    } else if (type == SQL_C_BINARY) {
3613 			int bsize;
3614 			unsigned char *bin;
3615 
3616 			bsize = sqlite_encode_binary(p->param, p->len, 0);
3617 			bin = xmalloc(bsize + 1);
3618 			if (!bin) {
3619 			    return nomem(s);
3620 			}
3621 			p->len = sqlite_encode_binary(p->param, p->len, bin);
3622 			if (p->param == p->parbuf) {
3623 			    freep(&p->parbuf);
3624 			}
3625 			p->parbuf = p->param = bin;
3626 		    }
3627 #endif
3628 		    p->need = -1;
3629 		}
3630 	    }
3631 	    done = 1;
3632 	    break;
3633 	}
3634     }
3635     if (!done) {
3636 	goto seqerr;
3637     }
3638     return SQL_SUCCESS;
3639 }
3640 
3641 /**
3642  * Put (partial) parameter data into executing statement.
3643  * @param stmt statement handle
3644  * @param data pointer to data
3645  * @param len length of data
3646  * @result ODBC error code
3647  */
3648 
3649 SQLRETURN SQL_API
SQLPutData(SQLHSTMT stmt,SQLPOINTER data,SQLLEN len)3650 SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN len)
3651 {
3652     SQLRETURN ret;
3653 
3654     HSTMT_LOCK(stmt);
3655     ret = drvputdata(stmt, data, len);
3656     HSTMT_UNLOCK(stmt);
3657     return ret;
3658 }
3659 
3660 /**
3661  * Clear out parameter bindings, if any.
3662  * @param s statement pointer
3663  */
3664 
3665 static SQLRETURN
freeparams(STMT * s)3666 freeparams(STMT *s)
3667 {
3668     if (s->bindparms) {
3669 	int n;
3670 
3671 	for (n = 0; n < s->nbindparms; n++) {
3672 	    freep(&s->bindparms[n].parbuf);
3673 	    memset(&s->bindparms[n], 0, sizeof (BINDPARM));
3674 	}
3675     }
3676     return SQL_SUCCESS;
3677 }
3678 
3679 /**
3680  * Substitute parameter for statement.
3681  * @param s statement pointer
3682  * @param pnum parameter number
3683  * @param outp output pointer or NULL
3684  * @result ODBC error code
3685  *
3686  * If no output buffer is given, the function computes and
3687  * reports the space needed for the parameter. Otherwise
3688  * the parameter is converted to its string representation
3689  * in order to be presented to sqlite_exec_vprintf() et.al.
3690  */
3691 
3692 static SQLRETURN
substparam(STMT * s,int pnum,char ** outp)3693 substparam(STMT *s, int pnum, char **outp)
3694 {
3695     char *outdata = NULL;
3696     int type, len, isnull = 0, needalloc = 0;
3697     BINDPARM *p;
3698     double dval;
3699 #if (HAVE_ENCDEC)
3700     int chkbin = 1;
3701 #endif
3702 
3703     if (!s->bindparms || pnum < 0 || pnum >= s->nbindparms) {
3704 	goto error;
3705     }
3706     p = &s->bindparms[pnum];
3707     type = mapdeftype(p->type, p->stype, -1, s->nowchar[0]);
3708 
3709 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
3710     /* MS Access hack part 4 (map SQL_C_DEFAULT to SQL_C_CHAR) */
3711     if (type == SQL_C_WCHAR && p->type == SQL_C_DEFAULT) {
3712 	type = SQL_C_CHAR;
3713     }
3714 #endif
3715 
3716     if (p->need > 0) {
3717 	return setupparbuf(s, p);
3718     }
3719     p->strbuf[0] = '\0';
3720     if (!p->param || (p->lenp && *p->lenp == SQL_NULL_DATA)) {
3721 	isnull = 1;
3722 	goto bind;
3723     }
3724 #if (HAVE_ENCDEC)
3725     if (type == SQL_C_CHAR &&
3726 	(p->stype == SQL_BINARY ||
3727 	 p->stype == SQL_VARBINARY ||
3728 	 p->stype == SQL_LONGVARBINARY)) {
3729 	type = SQL_C_BINARY;
3730     }
3731 #endif
3732     switch (type) {
3733     case SQL_C_CHAR:
3734 #ifdef WCHARSUPPORT
3735     case SQL_C_WCHAR:
3736 #endif
3737 #if (HAVE_ENCDEC)
3738     case SQL_C_BINARY:
3739 #endif
3740 	break;
3741 #ifdef SQL_BIT
3742     case SQL_C_BIT:
3743 	strcpy(p->strbuf, (*((unsigned char *) p->param)) ? "1" : "0");
3744 	goto bind;
3745 #endif
3746     case SQL_C_UTINYINT:
3747 	sprintf(p->strbuf, "%d", *((unsigned char *) p->param));
3748 	goto bind;
3749     case SQL_C_TINYINT:
3750     case SQL_C_STINYINT:
3751 	sprintf(p->strbuf, "%d", *((char *) p->param));
3752 	goto bind;
3753     case SQL_C_USHORT:
3754 	sprintf(p->strbuf, "%d", *((unsigned short *) p->param));
3755 	goto bind;
3756     case SQL_C_SHORT:
3757     case SQL_C_SSHORT:
3758 	sprintf(p->strbuf, "%d", *((short *) p->param));
3759 	goto bind;
3760     case SQL_C_ULONG:
3761     case SQL_C_LONG:
3762     case SQL_C_SLONG:
3763 	sprintf(p->strbuf, "%ld", *((long *) p->param));
3764 	goto bind;
3765     case SQL_C_FLOAT:
3766 	dval = *((float *) p->param);
3767 	goto dodouble;
3768     case SQL_C_DOUBLE:
3769 	dval = *((double *) p->param);
3770     dodouble:
3771 #if defined(HAVE_SQLITEMPRINTF) && (HAVE_SQLITEMPRINTF)
3772 	{
3773 	    char *buf2 = sqlite_mprintf("%.16g", dval);
3774 
3775 	    if (buf2) {
3776 		strcpy(p->strbuf, buf2);
3777 		sqlite_freemem(buf2);
3778 	    } else {
3779 		isnull = 1;
3780 	    }
3781 	}
3782 #else
3783 	ln_sprintfg(p->strbuf, dval);
3784 #endif
3785 	goto bind;
3786 #ifdef SQL_C_TYPE_DATE
3787     case SQL_C_TYPE_DATE:
3788 #endif
3789     case SQL_C_DATE:
3790 	sprintf(p->strbuf, "%04d-%02d-%02d",
3791 		((DATE_STRUCT *) p->param)->year,
3792 		((DATE_STRUCT *) p->param)->month,
3793 		((DATE_STRUCT *) p->param)->day);
3794 	goto bind;
3795 #ifdef SQL_C_TYPE_TIME
3796     case SQL_C_TYPE_TIME:
3797 #endif
3798     case SQL_C_TIME:
3799 	sprintf(p->strbuf, "%02d:%02d:%02d",
3800 		((TIME_STRUCT *) p->param)->hour,
3801 		((TIME_STRUCT *) p->param)->minute,
3802 		((TIME_STRUCT *) p->param)->second);
3803 	goto bind;
3804 #ifdef SQL_C_TYPE_TIMESTAMP
3805     case SQL_C_TYPE_TIMESTAMP:
3806 #endif
3807     case SQL_C_TIMESTAMP:
3808 	len = (int) ((TIMESTAMP_STRUCT *) p->param)->fraction;
3809 	len /= 1000000;
3810 	len = len % 1000;
3811 	if (len < 0) {
3812 	    len = 0;
3813 	}
3814 	if (p->coldef && p->coldef <= 16) {
3815 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:00.000",
3816 		    ((TIMESTAMP_STRUCT *) p->param)->year,
3817 		    ((TIMESTAMP_STRUCT *) p->param)->month,
3818 		    ((TIMESTAMP_STRUCT *) p->param)->day,
3819 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
3820 		    ((TIMESTAMP_STRUCT *) p->param)->minute);
3821 	} else if (p->coldef && p->coldef <= 19) {
3822 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.000",
3823 		    ((TIMESTAMP_STRUCT *) p->param)->year,
3824 		    ((TIMESTAMP_STRUCT *) p->param)->month,
3825 		    ((TIMESTAMP_STRUCT *) p->param)->day,
3826 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
3827 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
3828 		    ((TIMESTAMP_STRUCT *) p->param)->second);
3829 	} else {
3830 	    sprintf(p->strbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
3831 		    ((TIMESTAMP_STRUCT *) p->param)->year,
3832 		    ((TIMESTAMP_STRUCT *) p->param)->month,
3833 		    ((TIMESTAMP_STRUCT *) p->param)->day,
3834 		    ((TIMESTAMP_STRUCT *) p->param)->hour,
3835 		    ((TIMESTAMP_STRUCT *) p->param)->minute,
3836 		    ((TIMESTAMP_STRUCT *) p->param)->second,
3837 		    len);
3838 	}
3839     bind:
3840 	if (outp) {
3841 	    *outp = isnull ? NULL : p->strbuf;
3842 	}
3843 	return SQL_SUCCESS;
3844     default:
3845     error:
3846 	setstat(s, -1, "unsupported parameter type",
3847 		(*s->ov3) ? "07009" : "S1093");
3848 	return SQL_ERROR;
3849     }
3850     if (!p->parbuf) {
3851 #ifdef WCHARSUPPORT
3852 	if (type == SQL_C_WCHAR) {
3853 	    if (!p->lenp || *p->lenp == SQL_NTS) {
3854 		p->max = uc_strlen(p->param) * sizeof (SQLWCHAR);
3855 	    } else if (*p->lenp >= 0) {
3856 		p->max = *p->lenp;
3857 	    }
3858 	} else
3859 #endif
3860 	if (type == SQL_C_CHAR) {
3861 	    if (!p->lenp || *p->lenp == SQL_NTS) {
3862 		p->len = p->max = strlen(p->param);
3863 	    } else if (*p->lenp >= 0) {
3864 		p->len = p->max = *p->lenp;
3865 		needalloc = 1;
3866 	    }
3867 	}
3868 #if (HAVE_ENCDEC)
3869 	else if (type == SQL_C_BINARY) {
3870 	    p->len = p->max = p->lenp ? *p->lenp : 0;
3871 	}
3872 #endif
3873     }
3874     if (p->need < 0 && p->parbuf == p->param) {
3875 	outdata = p->param;
3876 	goto putp;
3877     }
3878 #ifdef WCHARSUPPORT
3879     if (type == SQL_C_WCHAR) {
3880 	char *dp = uc_to_utf(p->param, p->max);
3881 
3882 	if (!dp) {
3883 	    return nomem(s);
3884 	}
3885 	if (p->param == p->parbuf) {
3886 	    freep(&p->parbuf);
3887 	}
3888 	p->parbuf = p->param = dp;
3889 	p->need = -1;
3890 	p->len = strlen(p->param);
3891 	outdata = p->param;
3892     } else
3893 #endif
3894 #if (HAVE_ENCDEC)
3895     if (type == SQL_C_BINARY) {
3896 	int bsize;
3897 	char *dp;
3898 
3899 	p->len = *p->lenp;
3900 	if (p->len < 0) {
3901 	    setstat(s, -1, "invalid length reference", "HY009");
3902 	    return SQL_ERROR;
3903 	}
3904 	bsize = sqlite_encode_binary(p->param, p->len, 0);
3905 	dp = xmalloc(bsize + 1);
3906 	if (!dp) {
3907 	    return nomem(s);
3908 	}
3909 	p->len = sqlite_encode_binary(p->param, p->len, (unsigned char *) dp);
3910 	if (p->param == p->parbuf) {
3911 	    freep(&p->parbuf);
3912 	}
3913 	p->parbuf = p->param = dp;
3914 	p->need = -1;
3915 	chkbin = 0;
3916 	outdata = p->param;
3917     } else
3918 #endif
3919     if (type == SQL_C_CHAR) {
3920 	outdata = p->param;
3921 	if (needalloc) {
3922 	    char *dp;
3923 
3924 	    freep(&p->parbuf);
3925 	    dp = xmalloc(p->len + 1);
3926 	    if (!dp) {
3927 		return nomem(s);
3928 	    }
3929 	    memcpy(dp, p->param, p->len);
3930 	    dp[p->len] = '\0';
3931 	    p->parbuf = p->param = dp;
3932 	    p->need = -1;
3933 	    outdata = p->param;
3934 	}
3935     } else {
3936 	outdata = p->param;
3937 #if (HAVE_ENCDEC)
3938 	chkbin = 0;
3939 #endif
3940     }
3941 #if (HAVE_ENCDEC)
3942     if (chkbin) {
3943 	if (p->stype == SQL_BINARY ||
3944 	    p->stype == SQL_VARBINARY ||
3945 	    p->stype == SQL_LONGVARBINARY) {
3946 	    if (hextobin(s, p) != SQL_SUCCESS) {
3947 		return SQL_ERROR;
3948 	    }
3949 	    outdata = p->param;
3950 	}
3951     }
3952 #endif
3953 putp:
3954     if (outp) {
3955 	*outp = outdata;
3956     }
3957     return SQL_SUCCESS;
3958 }
3959 
3960 /**
3961  * Internal bind parameter on HSTMT.
3962  * @param stmt statement handle
3963  * @param pnum parameter number, starting at 1
3964  * @param iotype input/output type of parameter
3965  * @param buftype type of host variable
3966  * @param ptype
3967  * @param coldef
3968  * @param scale
3969  * @param data pointer to host variable
3970  * @param buflen length of host variable
3971  * @param len output length pointer
3972  * @result ODBC error code
3973  */
3974 
3975 static SQLRETURN
drvbindparam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLUINTEGER coldef,SQLSMALLINT scale,SQLPOINTER data,SQLINTEGER buflen,SQLLEN * len)3976 drvbindparam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
3977 	     SQLSMALLINT buftype, SQLSMALLINT ptype, SQLUINTEGER coldef,
3978 	     SQLSMALLINT scale,
3979 	     SQLPOINTER data, SQLINTEGER buflen, SQLLEN *len)
3980 {
3981     STMT *s;
3982     BINDPARM *p;
3983 
3984     if (stmt == SQL_NULL_HSTMT) {
3985 	return SQL_INVALID_HANDLE;
3986     }
3987     s = (STMT *) stmt;
3988     if (pnum == 0) {
3989 	setstat(s, -1, "invalid parameter", (*s->ov3) ? "07009" : "S1093");
3990 	return SQL_ERROR;
3991     }
3992     if (!data && !len) {
3993 	setstat(s, -1, "invalid buffer", "HY003");
3994 	return SQL_ERROR;
3995     }
3996     --pnum;
3997     if (s->bindparms) {
3998 	if (pnum >= s->nbindparms) {
3999 	    BINDPARM *newparms;
4000 
4001 	    newparms = xrealloc(s->bindparms,
4002 				(pnum + 1) * sizeof (BINDPARM));
4003 	    if (!newparms) {
4004 outofmem:
4005 		return nomem(s);
4006 	    }
4007 	    s->bindparms = newparms;
4008 	    memset(&s->bindparms[s->nbindparms], 0,
4009 		   (pnum + 1 - s->nbindparms) * sizeof (BINDPARM));
4010 	    s->nbindparms = pnum + 1;
4011 	}
4012     } else {
4013 	int npar = max(10, pnum + 1);
4014 
4015 	s->bindparms = xmalloc(npar * sizeof (BINDPARM));
4016 	if (!s->bindparms) {
4017 	    goto outofmem;
4018 	}
4019 	memset(s->bindparms, 0, npar * sizeof (BINDPARM));
4020 	s->nbindparms = npar;
4021     }
4022     switch (buftype) {
4023     case SQL_C_STINYINT:
4024     case SQL_C_UTINYINT:
4025     case SQL_C_TINYINT:
4026 #ifdef SQL_C_BIT
4027     case SQL_C_BIT:
4028 #endif
4029 	buflen = sizeof (char);
4030 	break;
4031     case SQL_C_SHORT:
4032     case SQL_C_USHORT:
4033     case SQL_C_SSHORT:
4034 	buflen = sizeof (short);
4035 	break;
4036     case SQL_C_SLONG:
4037     case SQL_C_ULONG:
4038     case SQL_C_LONG:
4039 	buflen = sizeof (long);
4040 	break;
4041     case SQL_C_FLOAT:
4042 	buflen = sizeof (float);
4043 	break;
4044     case SQL_C_DOUBLE:
4045 	buflen = sizeof (double);
4046 	break;
4047     case SQL_C_TIMESTAMP:
4048 #ifdef SQL_C_TYPE_TIMESTAMP
4049     case SQL_C_TYPE_TIMESTAMP:
4050 #endif
4051 	buflen = sizeof (TIMESTAMP_STRUCT);
4052 	break;
4053     case SQL_C_TIME:
4054 #ifdef SQL_C_TYPE_TIME
4055     case SQL_C_TYPE_TIME:
4056 #endif
4057 	buflen = sizeof (TIME_STRUCT);
4058 	break;
4059     case SQL_C_DATE:
4060 #ifdef SQL_C_TYPE_DATE
4061     case SQL_C_TYPE_DATE:
4062 #endif
4063 	buflen = sizeof (DATE_STRUCT);
4064 	break;
4065 #ifdef SQL_C_UBIGINT
4066     case SQL_C_UBIGINT:
4067 	buflen = sizeof (SQLBIGINT);
4068 	break;
4069 #endif
4070 #ifdef SQL_C_SBIGINT
4071     case SQL_C_SBIGINT:
4072 	buflen = sizeof (SQLBIGINT);
4073 	break;
4074 #endif
4075 #ifdef SQL_C_BIGINT
4076     case SQL_C_BIGINT:
4077 	buflen = sizeof (SQLBIGINT);
4078 	break;
4079 #endif
4080     }
4081     p = &s->bindparms[pnum];
4082     p->type = buftype;
4083     p->stype = ptype;
4084     p->coldef = coldef;
4085     p->scale = scale;
4086     p->max = buflen;
4087     p->inc = buflen;
4088     p->lenp0 = p->lenp = len;
4089     p->offs = 0;
4090     p->len = 0;
4091     p->param0 = data;
4092     freep(&p->parbuf);
4093     p->param = p->param0;
4094     p->bound = 1;
4095     p->need = 0;
4096     return SQL_SUCCESS;
4097 }
4098 
4099 /**
4100  * Bind parameter on HSTMT.
4101  * @param stmt statement handle
4102  * @param pnum parameter number, starting at 1
4103  * @param iotype input/output type of parameter
4104  * @param buftype type of host variable
4105  * @param ptype
4106  * @param coldef
4107  * @param scale
4108  * @param data pointer to host variable
4109  * @param buflen length of host variable
4110  * @param len output length pointer
4111  * @result ODBC error code
4112  */
4113 
4114 SQLRETURN SQL_API
SQLBindParameter(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT iotype,SQLSMALLINT buftype,SQLSMALLINT ptype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER data,SQLLEN buflen,SQLLEN * len)4115 SQLBindParameter(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT iotype,
4116 		 SQLSMALLINT buftype, SQLSMALLINT ptype, SQLULEN coldef,
4117 		 SQLSMALLINT scale,
4118 		 SQLPOINTER data, SQLLEN buflen, SQLLEN *len)
4119 {
4120     SQLRETURN ret;
4121 
4122     HSTMT_LOCK(stmt);
4123     ret = drvbindparam(stmt, pnum, iotype, buftype, ptype, coldef,
4124 		       scale, data, buflen, len);
4125     HSTMT_UNLOCK(stmt);
4126     return ret;
4127 }
4128 
4129 #ifndef HAVE_IODBC
4130 /**
4131  * Bind parameter on HSTMT.
4132  * @param stmt statement handle
4133  * @param pnum parameter number, starting at 1
4134  * @param vtype input/output type of parameter
4135  * @param ptype
4136  * @param lenprec
4137  * @param scale
4138  * @param val pointer to host variable
4139  * @param lenp output length pointer
4140  * @result ODBC error code
4141  */
4142 
4143 SQLRETURN SQL_API
SQLBindParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT vtype,SQLSMALLINT ptype,SQLULEN lenprec,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * lenp)4144 SQLBindParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT vtype,
4145 	     SQLSMALLINT ptype, SQLULEN lenprec,
4146 	     SQLSMALLINT scale, SQLPOINTER val,
4147 	     SQLLEN *lenp)
4148 {
4149     SQLRETURN ret;
4150 
4151     HSTMT_LOCK(stmt);
4152     ret = drvbindparam(stmt, pnum, SQL_PARAM_INPUT, vtype, ptype,
4153 		       lenprec, scale, val, 0, lenp);
4154     HSTMT_UNLOCK(stmt);
4155     return ret;
4156 }
4157 #endif
4158 
4159 /**
4160  * Return number of parameters.
4161  * @param stmt statement handle
4162  * @param nparam output parameter count
4163  * @result ODBC error code
4164  */
4165 
4166 SQLRETURN SQL_API
SQLNumParams(SQLHSTMT stmt,SQLSMALLINT * nparam)4167 SQLNumParams(SQLHSTMT stmt, SQLSMALLINT *nparam)
4168 {
4169     STMT *s;
4170     SQLSMALLINT dummy;
4171 
4172     HSTMT_LOCK(stmt);
4173     if (stmt == SQL_NULL_HSTMT) {
4174 	return SQL_INVALID_HANDLE;
4175     }
4176     s = (STMT *) stmt;
4177     if (!nparam) {
4178 	nparam = &dummy;
4179     }
4180     *nparam = s->nparams;
4181     HSTMT_UNLOCK(stmt);
4182     return SQL_SUCCESS;
4183 }
4184 
4185 /**
4186  * Setup parameter buffer for deferred parameter.
4187  * @param s pointer to STMT
4188  * @param p pointer to BINDPARM
4189  * @result ODBC error code (success indicated by SQL_NEED_DATA)
4190  */
4191 
4192 static SQLRETURN
setupparbuf(STMT * s,BINDPARM * p)4193 setupparbuf(STMT *s, BINDPARM *p)
4194 {
4195     if (!p->parbuf) {
4196 	if (*p->lenp == SQL_DATA_AT_EXEC) {
4197 	    p->len = p->max;
4198 	} else {
4199 	    p->len = SQL_LEN_DATA_AT_EXEC(*p->lenp);
4200 	}
4201 	if (p->len < 0 && p->len != SQL_NTS &&
4202 	    p->len != SQL_NULL_DATA) {
4203 	    setstat(s, -1, "invalid length", "HY009");
4204 	    return SQL_ERROR;
4205 	}
4206 	if (p->len >= 0) {
4207 	    p->parbuf = xmalloc(p->len + 1);
4208 	    if (!p->parbuf) {
4209 		return nomem(s);
4210 	    }
4211 	    p->param = p->parbuf;
4212 	} else {
4213 	    p->param = NULL;
4214 	}
4215     }
4216     return SQL_NEED_DATA;
4217 }
4218 
4219 /**
4220  * Retrieve next parameter for sending data to executing query.
4221  * @param stmt statement handle
4222  * @param pind pointer to output parameter indicator
4223  * @result ODBC error code
4224  */
4225 
4226 SQLRETURN SQL_API
SQLParamData(SQLHSTMT stmt,SQLPOINTER * pind)4227 SQLParamData(SQLHSTMT stmt, SQLPOINTER *pind)
4228 {
4229     STMT *s;
4230     int i;
4231     SQLPOINTER dummy;
4232     SQLRETURN ret;
4233     BINDPARM *p;
4234 
4235     HSTMT_LOCK(stmt);
4236     if (stmt == SQL_NULL_HSTMT) {
4237 	return SQL_INVALID_HANDLE;
4238     }
4239     s = (STMT *) stmt;
4240     if (!pind) {
4241 	pind = &dummy;
4242     }
4243     if (s->pdcount < s->nparams) {
4244 	s->pdcount++;
4245     }
4246     for (i = 0; i < s->pdcount; i++) {
4247 	p = &s->bindparms[i];
4248 	if (p->need > 0) {
4249 	    p->need = -1;
4250 	}
4251     }
4252     for (; i < s->nparams; i++) {
4253 	p = &s->bindparms[i];
4254 	if (p->need > 0) {
4255 	    *pind = (SQLPOINTER) p->param0;
4256 	    ret = setupparbuf(s, p);
4257 	    s->pdcount = i;
4258 	    goto done;
4259 	}
4260     }
4261     ret = drvexecute(stmt, 0);
4262 done:
4263     HSTMT_UNLOCK(stmt);
4264     return ret;
4265 }
4266 
4267 /**
4268  * Return information about parameter.
4269  * @param stmt statement handle
4270  * @param pnum parameter number, starting at 1
4271  * @param dtype output type indicator
4272  * @param size output size indicator
4273  * @param decdigits output number of digits
4274  * @param nullable output NULL allowed indicator
4275  * @result ODBC error code
4276  */
4277 
4278 SQLRETURN SQL_API
SQLDescribeParam(SQLHSTMT stmt,SQLUSMALLINT pnum,SQLSMALLINT * dtype,SQLULEN * size,SQLSMALLINT * decdigits,SQLSMALLINT * nullable)4279 SQLDescribeParam(SQLHSTMT stmt, SQLUSMALLINT pnum, SQLSMALLINT *dtype,
4280 		 SQLULEN *size, SQLSMALLINT *decdigits, SQLSMALLINT *nullable)
4281 {
4282     STMT *s;
4283     SQLRETURN ret = SQL_ERROR;
4284 
4285     HSTMT_LOCK(stmt);
4286     if (stmt == SQL_NULL_HSTMT) {
4287 	return SQL_INVALID_HANDLE;
4288     }
4289     s = (STMT *) stmt;
4290     --pnum;
4291     if (pnum >= s->nparams) {
4292 	setstat(s, -1, "invalid parameter index",
4293 		(*s->ov3) ? "HY000" : "S1000");
4294 	goto done;
4295     }
4296     if (dtype) {
4297 #ifdef SQL_LONGVARCHAR
4298 #ifdef WINTERFACE
4299 	*dtype = s->nowchar[0] ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
4300 #else
4301 	*dtype = SQL_LONGVARCHAR;
4302 #endif
4303 #else
4304 #ifdef WINTERFACE
4305 	*dtype = s->nowchar[0] ? SQL_VARCHAR : SQL_WVARCHAR;
4306 #else
4307 	*dtype = SQL_VARCHAR;
4308 #endif
4309 #endif
4310     }
4311     if (size) {
4312 #ifdef SQL_LONGVARCHAR
4313 	*size = 65536;
4314 #else
4315 	*size = 255;
4316 #endif
4317     }
4318     if (decdigits) {
4319 	*decdigits = 0;
4320     }
4321     if (nullable) {
4322 	*nullable = SQL_NULLABLE;
4323     }
4324     ret = SQL_SUCCESS;
4325 done:
4326     HSTMT_UNLOCK(stmt);
4327     return ret;
4328 }
4329 
4330 /**
4331  * Set information on parameter.
4332  * @param stmt statement handle
4333  * @param par parameter number, starting at 1
4334  * @param type type of host variable
4335  * @param sqltype
4336  * @param coldef
4337  * @param scale
4338  * @param val pointer to host variable
4339  * @param len output length pointer
4340  * @result ODBC error code
4341  */
4342 
4343 SQLRETURN SQL_API
SQLSetParam(SQLHSTMT stmt,SQLUSMALLINT par,SQLSMALLINT type,SQLSMALLINT sqltype,SQLULEN coldef,SQLSMALLINT scale,SQLPOINTER val,SQLLEN * nval)4344 SQLSetParam(SQLHSTMT stmt, SQLUSMALLINT par, SQLSMALLINT type,
4345 	    SQLSMALLINT sqltype, SQLULEN coldef,
4346 	    SQLSMALLINT scale, SQLPOINTER val, SQLLEN *nval)
4347 {
4348     SQLRETURN ret;
4349 
4350     HSTMT_LOCK(stmt);
4351     ret = drvbindparam(stmt, par, SQL_PARAM_INPUT,
4352 		       type, sqltype, coldef, scale, val,
4353 		       SQL_SETPARAM_VALUE_MAX, nval);
4354     HSTMT_UNLOCK(stmt);
4355     return ret;
4356 }
4357 
4358 /**
4359  * Function not implemented.
4360  */
4361 
4362 SQLRETURN SQL_API
SQLParamOptions(SQLHSTMT stmt,SQLULEN rows,SQLULEN * rowp)4363 SQLParamOptions(SQLHSTMT stmt, SQLULEN rows, SQLULEN *rowp)
4364 {
4365     SQLRETURN ret;
4366 
4367     HSTMT_LOCK(stmt);
4368     ret = drvunimplstmt(stmt);
4369     HSTMT_UNLOCK(stmt);
4370     return ret;
4371 }
4372 
4373 #ifndef WINTERFACE
4374 /**
4375  * Function not implemented.
4376  */
4377 
4378 SQLRETURN SQL_API
SQLGetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)4379 SQLGetDescField(SQLHDESC handle, SQLSMALLINT recno,
4380 		SQLSMALLINT fieldid, SQLPOINTER value,
4381 		SQLINTEGER buflen, SQLINTEGER *strlen)
4382 {
4383     return SQL_ERROR;
4384 }
4385 #endif
4386 
4387 #ifdef WINTERFACE
4388 /**
4389  * Function not implemented.
4390  */
4391 
4392 SQLRETURN SQL_API
SQLGetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen,SQLINTEGER * strlen)4393 SQLGetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
4394 		 SQLSMALLINT fieldid, SQLPOINTER value,
4395 		 SQLINTEGER buflen, SQLINTEGER *strlen)
4396 {
4397     return SQL_ERROR;
4398 }
4399 #endif
4400 
4401 #ifndef WINTERFACE
4402 /**
4403  * Function not implemented.
4404  */
4405 
4406 SQLRETURN SQL_API
SQLSetDescField(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)4407 SQLSetDescField(SQLHDESC handle, SQLSMALLINT recno,
4408 		SQLSMALLINT fieldid, SQLPOINTER value,
4409 		SQLINTEGER buflen)
4410 {
4411     return SQL_ERROR;
4412 }
4413 #endif
4414 
4415 #ifdef WINTERFACE
4416 /**
4417  * Function not implemented.
4418  */
4419 
4420 SQLRETURN SQL_API
SQLSetDescFieldW(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT fieldid,SQLPOINTER value,SQLINTEGER buflen)4421 SQLSetDescFieldW(SQLHDESC handle, SQLSMALLINT recno,
4422 		 SQLSMALLINT fieldid, SQLPOINTER value,
4423 		 SQLINTEGER buflen)
4424 {
4425     return SQL_ERROR;
4426 }
4427 #endif
4428 
4429 #ifndef WINTERFACE
4430 /**
4431  * Function not implemented.
4432  */
4433 
4434 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)4435 SQLGetDescRec(SQLHDESC handle, SQLSMALLINT recno,
4436 	      SQLCHAR *name, SQLSMALLINT buflen,
4437 	      SQLSMALLINT *strlen, SQLSMALLINT *type,
4438 	      SQLSMALLINT *subtype, SQLLEN *len,
4439 	      SQLSMALLINT *prec, SQLSMALLINT *scale,
4440 	      SQLSMALLINT *nullable)
4441 {
4442     return SQL_ERROR;
4443 }
4444 #endif
4445 
4446 #ifdef WINTERFACE
4447 /**
4448  * Function not implemented.
4449  */
4450 
4451 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)4452 SQLGetDescRecW(SQLHDESC handle, SQLSMALLINT recno,
4453 	       SQLWCHAR *name, SQLSMALLINT buflen,
4454 	       SQLSMALLINT *strlen, SQLSMALLINT *type,
4455 	       SQLSMALLINT *subtype, SQLLEN *len,
4456 	       SQLSMALLINT *prec, SQLSMALLINT *scale,
4457 	       SQLSMALLINT *nullable)
4458 {
4459     return SQL_ERROR;
4460 }
4461 #endif
4462 
4463 /**
4464  * Function not implemented.
4465  */
4466 
4467 SQLRETURN SQL_API
SQLSetDescRec(SQLHDESC handle,SQLSMALLINT recno,SQLSMALLINT type,SQLSMALLINT subtype,SQLLEN len,SQLSMALLINT prec,SQLSMALLINT scale,SQLPOINTER data,SQLLEN * strlen,SQLLEN * indicator)4468 SQLSetDescRec(SQLHDESC handle, SQLSMALLINT recno,
4469 	      SQLSMALLINT type, SQLSMALLINT subtype,
4470 	      SQLLEN len, SQLSMALLINT prec,
4471 	      SQLSMALLINT scale, SQLPOINTER data,
4472 	      SQLLEN *strlen, SQLLEN *indicator)
4473 {
4474     return SQL_ERROR;
4475 }
4476 
4477 /**
4478  * Setup empty result set from constant column specification.
4479  * @param stmt statement handle
4480  * @param colspec column specification array (default, ODBC2)
4481  * @param ncols number of columns (default, ODBC2)
4482  * @param colspec3 column specification array (ODBC3)
4483  * @param ncols3 number of columns (ODBC3)
4484  * @param nret returns number of columns
4485  * @result ODBC error code
4486  */
4487 
4488 static SQLRETURN
mkresultset(HSTMT stmt,COL * colspec,int ncols,COL * colspec3,int ncols3,int * nret)4489 mkresultset(HSTMT stmt, COL *colspec, int ncols, COL *colspec3,
4490 	    int ncols3, int *nret)
4491 {
4492     STMT *s;
4493     DBC *d;
4494 
4495     if (stmt == SQL_NULL_HSTMT) {
4496 	return SQL_INVALID_HANDLE;
4497     }
4498     s = (STMT *) stmt;
4499     if (s->dbc == SQL_NULL_HDBC) {
4500 noconn:
4501 	return noconn(s);
4502     }
4503     d = (DBC *) s->dbc;
4504     if (!d->sqlite) {
4505 	goto noconn;
4506     }
4507     vm_end_if(s);
4508     freeresult(s, 0);
4509     if (colspec3 && *s->ov3) {
4510 	s->ncols = ncols3;
4511 	s->cols = colspec3;
4512     } else {
4513 	s->ncols = ncols;
4514 	s->cols = colspec;
4515     }
4516     mkbindcols(s, s->ncols);
4517     s->nowchar[1] = 1;
4518     s->nrows = 0;
4519     s->rowp = -1;
4520     s->isselect = -1;
4521     if (nret) {
4522 	*nret = s->ncols;
4523     }
4524     return SQL_SUCCESS;
4525 }
4526 
4527 /**
4528  * Columns for result set of SQLTablePrivileges().
4529  */
4530 
4531 static COL tablePrivSpec2[] = {
4532     { "SYSTEM", "TABLEPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
4533     { "SYSTEM", "TABLEPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
4534     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
4535     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
4536     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
4537     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
4538     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
4539 };
4540 
4541 static COL tablePrivSpec3[] = {
4542     { "SYSTEM", "TABLEPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
4543     { "SYSTEM", "TABLEPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
4544     { "SYSTEM", "TABLEPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
4545     { "SYSTEM", "TABLEPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
4546     { "SYSTEM", "TABLEPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
4547     { "SYSTEM", "TABLEPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 },
4548     { "SYSTEM", "TABLEPRIV", "IS_GRANTABLE", SCOL_VARCHAR, 50 }
4549 };
4550 
4551 /**
4552  * Retrieve privileges on tables and/or views.
4553  * @param stmt statement handle
4554  * @param cat catalog name/pattern or NULL
4555  * @param catLen length of catalog name/pattern or SQL_NTS
4556  * @param schema schema name/pattern or NULL
4557  * @param schemaLen length of schema name/pattern or SQL_NTS
4558  * @param table table name/pattern or NULL
4559  * @param tableLen length of table name/pattern or SQL_NTS
4560  * @result ODBC error code
4561  */
4562 
4563 static SQLRETURN
drvtableprivileges(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)4564 drvtableprivileges(SQLHSTMT stmt,
4565 		   SQLCHAR *cat, SQLSMALLINT catLen,
4566 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
4567 		   SQLCHAR *table, SQLSMALLINT tableLen)
4568 {
4569     SQLRETURN ret;
4570     STMT *s;
4571     DBC *d;
4572     int ncols, rc, size, npatt;
4573     char *errp = NULL, tname[512];
4574 
4575     ret = mkresultset(stmt, tablePrivSpec2, array_size(tablePrivSpec2),
4576 		      tablePrivSpec3, array_size(tablePrivSpec3), NULL);
4577     if (ret != SQL_SUCCESS) {
4578 	return ret;
4579     }
4580     s = (STMT *) stmt;
4581     d = (DBC *) s->dbc;
4582     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
4583 	table = NULL;
4584 	goto doit;
4585     }
4586     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
4587 	schema[0] == '%') {
4588 	if ((!cat || catLen == 0 || !cat[0]) &&
4589 	    (!table || tableLen == 0 || !table[0])) {
4590 	    table = NULL;
4591 	    goto doit;
4592 	}
4593     }
4594 doit:
4595     if (!table) {
4596 	size = 1;
4597 	tname[0] = '%';
4598     } else {
4599 	if (tableLen == SQL_NTS) {
4600 	    size = sizeof (tname) - 1;
4601 	} else {
4602 	    size = min(sizeof (tname) - 1, tableLen);
4603 	}
4604 	strncpy(tname, (char *) table, size);
4605     }
4606     tname[size] = '\0';
4607     npatt = unescpat(tname);
4608     ret = starttran(s);
4609     if (ret != SQL_SUCCESS) {
4610 	return ret;
4611     }
4612 #if defined(_WIN32) || defined(_WIN64)
4613     if (npatt) {
4614 	rc = sqlite_get_table_printf(d->sqlite,
4615 				     "select %s as 'TABLE_QUALIFIER', "
4616 				     "%s as 'TABLE_OWNER', "
4617 				     "tbl_name as 'TABLE_NAME', "
4618 				     "'' as 'GRANTOR', "
4619 				     "'' as 'GRANTEE', "
4620 				     "'SELECT' AS 'PRIVILEGE', "
4621 				     "NULL as 'IS_GRANTABLE' "
4622 				     "from sqlite_master where "
4623 				     "(type = 'table' or type = 'view') "
4624 				     "and tbl_name like '%q' "
4625 				     "UNION "
4626 				     "select %s as 'TABLE_QUALIFIER', "
4627 				     "%s as 'TABLE_OWNER', "
4628 				     "tbl_name as 'TABLE_NAME', "
4629 				     "'' as 'GRANTOR', "
4630 				     "'' as 'GRANTEE', "
4631 				     "'UPDATE' AS 'PRIVILEGE', "
4632 				     "NULL as 'IS_GRANTABLE' "
4633 				     "from sqlite_master where "
4634 				     "(type = 'table' or type = 'view') "
4635 				     "and tbl_name like '%q' "
4636 				     "UNION "
4637 				     "select %s as 'TABLE_QUALIFIER', "
4638 				     "%s as 'TABLE_OWNER', "
4639 				     "tbl_name as 'TABLE_NAME', "
4640 				     "'' as 'GRANTOR', "
4641 				     "'' as 'GRANTEE', "
4642 				     "'DELETE' AS 'PRIVILEGE', "
4643 				     "NULL as 'IS_GRANTABLE' "
4644 				     "from sqlite_master where "
4645 				     "(type = 'table' or type = 'view') "
4646 				     "and tbl_name like '%q' "
4647 				     "UNION "
4648 				     "select %s as 'TABLE_QUALIFIER', "
4649 				     "%s as 'TABLE_OWNER', "
4650 				     "tbl_name as 'TABLE_NAME', "
4651 				     "'' as 'GRANTOR', "
4652 				     "'' as 'GRANTEE', "
4653 				     "'INSERT' AS 'PRIVILEGE', "
4654 				     "NULL as 'IS_GRANTABLE' "
4655 				     "from sqlite_master where "
4656 				     "(type = 'table' or type = 'view') "
4657 				     "and tbl_name like '%q' "
4658 				     "UNION "
4659 				     "select %s as 'TABLE_QUALIFIER', "
4660 				     "%s as 'TABLE_OWNER', "
4661 				     "tbl_name as 'TABLE_NAME', "
4662 				     "'' as 'GRANTOR', "
4663 				     "'' as 'GRANTEE', "
4664 				     "'REFERENCES' AS 'PRIVILEGE', "
4665 				     "NULL as 'IS_GRANTABLE' "
4666 				     "from sqlite_master where "
4667 				     "(type = 'table' or type = 'view') "
4668 				     "and tbl_name like '%q'",
4669 				     &s->rows, &s->nrows, &ncols, &errp,
4670 				     d->xcelqrx ? "'main'" : "NULL",
4671 				     d->xcelqrx ? "''" : "NULL", tname,
4672 				     d->xcelqrx ? "'main'" : "NULL",
4673 				     d->xcelqrx ? "''" : "NULL", tname,
4674 				     d->xcelqrx ? "'main'" : "NULL",
4675 				     d->xcelqrx ? "''" : "NULL", tname,
4676 				     d->xcelqrx ? "'main'" : "NULL",
4677 				     d->xcelqrx ? "''" : "NULL", tname,
4678 				     d->xcelqrx ? "'main'" : "NULL",
4679 				     d->xcelqrx ? "''" : "NULL", tname);
4680     } else {
4681 	rc = sqlite_get_table_printf(d->sqlite,
4682 				     "select %s as 'TABLE_QUALIFIER', "
4683 				     "%s as 'TABLE_OWNER', "
4684 				     "tbl_name as 'TABLE_NAME', "
4685 				     "'' as 'GRANTOR', "
4686 				     "'' as 'GRANTEE', "
4687 				     "'SELECT' AS 'PRIVILEGE', "
4688 				     "NULL as 'IS_GRANTABLE' "
4689 				     "from sqlite_master where "
4690 				     "(type = 'table' or type = 'view') "
4691 				     "and lower(tbl_name) = lower('%q') "
4692 				     "UNION "
4693 				     "select %s as 'TABLE_QUALIFIER', "
4694 				     "%s as 'TABLE_OWNER', "
4695 				     "tbl_name as 'TABLE_NAME', "
4696 				     "'' as 'GRANTOR', "
4697 				     "'' as 'GRANTEE', "
4698 				     "'UPDATE' AS 'PRIVILEGE', "
4699 				     "NULL as 'IS_GRANTABLE' "
4700 				     "from sqlite_master where "
4701 				     "(type = 'table' or type = 'view') "
4702 				     "and lower(tbl_name) = lower('%q') "
4703 				     "UNION "
4704 				     "select %s as 'TABLE_QUALIFIER', "
4705 				     "%s as 'TABLE_OWNER', "
4706 				     "tbl_name as 'TABLE_NAME', "
4707 				     "'' as 'GRANTOR', "
4708 				     "'' as 'GRANTEE', "
4709 				     "'DELETE' AS 'PRIVILEGE', "
4710 				     "NULL as 'IS_GRANTABLE' "
4711 				     "from sqlite_master where "
4712 				     "(type = 'table' or type = 'view') "
4713 				     "and lower(tbl_name) = lower('%q') "
4714 				     "UNION "
4715 				     "select %s as 'TABLE_QUALIFIER', "
4716 				     "%s as 'TABLE_OWNER', "
4717 				     "tbl_name as 'TABLE_NAME', "
4718 				     "'' as 'GRANTOR', "
4719 				     "'' as 'GRANTEE', "
4720 				     "'INSERT' AS 'PRIVILEGE', "
4721 				     "NULL as 'IS_GRANTABLE' "
4722 				     "from sqlite_master where "
4723 				     "(type = 'table' or type = 'view') "
4724 				     "and lower(tbl_name) = lower('%q') "
4725 				     "UNION "
4726 				     "select %s as 'TABLE_QUALIFIER', "
4727 				     "%s as 'TABLE_OWNER', "
4728 				     "tbl_name as 'TABLE_NAME', "
4729 				     "'' as 'GRANTOR', "
4730 				     "'' as 'GRANTEE', "
4731 				     "'REFERENCES' AS 'PRIVILEGE', "
4732 				     "NULL as 'IS_GRANTABLE' "
4733 				     "from sqlite_master where "
4734 				     "(type = 'table' or type = 'view') "
4735 				     "and lower(tbl_name) = lower('%q')",
4736 				     &s->rows, &s->nrows, &ncols, &errp,
4737 				     d->xcelqrx ? "'main'" : "NULL",
4738 				     d->xcelqrx ? "''" : "NULL", tname,
4739 				     d->xcelqrx ? "'main'" : "NULL",
4740 				     d->xcelqrx ? "''" : "NULL", tname,
4741 				     d->xcelqrx ? "'main'" : "NULL",
4742 				     d->xcelqrx ? "''" : "NULL", tname,
4743 				     d->xcelqrx ? "'main'" : "NULL",
4744 				     d->xcelqrx ? "''" : "NULL", tname,
4745 				     d->xcelqrx ? "'main'" : "NULL",
4746 				     d->xcelqrx ? "''" : "NULL", tname);
4747     }
4748 #else
4749     if (npatt) {
4750 	rc = sqlite_get_table_printf(d->sqlite,
4751 				     "select NULL as 'TABLE_QUALIFIER', "
4752 				     "NULL as 'TABLE_OWNER', "
4753 				     "tbl_name as 'TABLE_NAME', "
4754 				     "'' as 'GRANTOR', "
4755 				     "'' as 'GRANTEE', "
4756 				     "'SELECT' AS 'PRIVILEGE', "
4757 				     "NULL as 'IS_GRANTABLE' "
4758 				     "from sqlite_master where "
4759 				     "(type = 'table' or type = 'view') "
4760 				     "and tbl_name like '%q' "
4761 				     "UNION "
4762 				     "select NULL as 'TABLE_QUALIFIER', "
4763 				     "NULL as 'TABLE_OWNER', "
4764 				     "tbl_name as 'TABLE_NAME', "
4765 				     "'' as 'GRANTOR', "
4766 				     "'' as 'GRANTEE', "
4767 				     "'UPDATE' AS 'PRIVILEGE', "
4768 				     "NULL as 'IS_GRANTABLE' "
4769 				     "from sqlite_master where "
4770 				     "(type = 'table' or type = 'view') "
4771 				     "and tbl_name like '%q' "
4772 				     "UNION "
4773 				     "select NULL as 'TABLE_QUALIFIER', "
4774 				     "NULL as 'TABLE_OWNER', "
4775 				     "tbl_name as 'TABLE_NAME', "
4776 				     "'' as 'GRANTOR', "
4777 				     "'' as 'GRANTEE', "
4778 				     "'DELETE' AS 'PRIVILEGE', "
4779 				     "NULL as 'IS_GRANTABLE' "
4780 				     "from sqlite_master where "
4781 				     "(type = 'table' or type = 'view') "
4782 				     "and tbl_name like '%q' "
4783 				     "UNION "
4784 				     "select NULL as 'TABLE_QUALIFIER', "
4785 				     "NULL as 'TABLE_OWNER', "
4786 				     "tbl_name as 'TABLE_NAME', "
4787 				     "'' as 'GRANTOR', "
4788 				     "'' as 'GRANTEE', "
4789 				     "'INSERT' AS 'PRIVILEGE', "
4790 				     "NULL as 'IS_GRANTABLE' "
4791 				     "from sqlite_master where "
4792 				     "(type = 'table' or type = 'view') "
4793 				     "and tbl_name like '%q' "
4794 				     "UNION "
4795 				     "select NULL as 'TABLE_QUALIFIER', "
4796 				     "NULL as 'TABLE_OWNER', "
4797 				     "tbl_name as 'TABLE_NAME', "
4798 				     "'' as 'GRANTOR', "
4799 				     "'' as 'GRANTEE', "
4800 				     "'REFERENCES' AS 'PRIVILEGE', "
4801 				     "NULL as 'IS_GRANTABLE' "
4802 				     "from sqlite_master where "
4803 				     "(type = 'table' or type = 'view') "
4804 				     "and tbl_name like '%q'",
4805 				     &s->rows, &s->nrows, &ncols, &errp,
4806 				     tname, tname, tname, tname, tname);
4807     } else {
4808 	rc = sqlite_get_table_printf(d->sqlite,
4809 				     "select NULL as 'TABLE_QUALIFIER', "
4810 				     "NULL as 'TABLE_OWNER', "
4811 				     "tbl_name as 'TABLE_NAME', "
4812 				     "'' as 'GRANTOR', "
4813 				     "'' as 'GRANTEE', "
4814 				     "'SELECT' AS 'PRIVILEGE', "
4815 				     "NULL as 'IS_GRANTABLE' "
4816 				     "from sqlite_master where "
4817 				     "(type = 'table' or type = 'view') "
4818 				     "and lower(tbl_name) = lower('%q') "
4819 				     "UNION "
4820 				     "select NULL as 'TABLE_QUALIFIER', "
4821 				     "NULL as 'TABLE_OWNER', "
4822 				     "tbl_name as 'TABLE_NAME', "
4823 				     "'' as 'GRANTOR', "
4824 				     "'' as 'GRANTEE', "
4825 				     "'UPDATE' AS 'PRIVILEGE', "
4826 				     "NULL as 'IS_GRANTABLE' "
4827 				     "from sqlite_master where "
4828 				     "(type = 'table' or type = 'view') "
4829 				     "and lower(tbl_name) = lower('%q') "
4830 				     "UNION "
4831 				     "select NULL as 'TABLE_QUALIFIER', "
4832 				     "NULL as 'TABLE_OWNER', "
4833 				     "tbl_name as 'TABLE_NAME', "
4834 				     "'' as 'GRANTOR', "
4835 				     "'' as 'GRANTEE', "
4836 				     "'DELETE' AS 'PRIVILEGE', "
4837 				     "NULL as 'IS_GRANTABLE' "
4838 				     "from sqlite_master where "
4839 				     "(type = 'table' or type = 'view') "
4840 				     "and lower(tbl_name) = lower('%q') "
4841 				     "UNION "
4842 				     "select NULL as 'TABLE_QUALIFIER', "
4843 				     "NULL as 'TABLE_OWNER', "
4844 				     "tbl_name as 'TABLE_NAME', "
4845 				     "'' as 'GRANTOR', "
4846 				     "'' as 'GRANTEE', "
4847 				     "'INSERT' AS 'PRIVILEGE', "
4848 				     "NULL as 'IS_GRANTABLE' "
4849 				     "from sqlite_master where "
4850 				     "(type = 'table' or type = 'view') "
4851 				     "and lower(tbl_name) = lower('%q') "
4852 				     "UNION "
4853 				     "select NULL as 'TABLE_QUALIFIER', "
4854 				     "NULL as 'TABLE_OWNER', "
4855 				     "tbl_name as 'TABLE_NAME', "
4856 				     "'' as 'GRANTOR', "
4857 				     "'' as 'GRANTEE', "
4858 				     "'REFERENCES' AS 'PRIVILEGE', "
4859 				     "NULL as 'IS_GRANTABLE' "
4860 				     "from sqlite_master where "
4861 				     "(type = 'table' or type = 'view') "
4862 				     "and lower(tbl_name) = lower('%q')",
4863 				     &s->rows, &s->nrows, &ncols, &errp,
4864 				     tname, tname, tname, tname, tname);
4865     }
4866 #endif
4867     if (rc == SQLITE_OK) {
4868 	if (ncols != s->ncols) {
4869 	    freeresult(s, 0);
4870 	    s->nrows = 0;
4871 	} else {
4872 	    s->rowfree = sqlite_free_table;
4873 	}
4874     } else {
4875 	s->nrows = 0;
4876 	s->rows = NULL;
4877 	s->rowfree = NULL;
4878     }
4879     if (errp) {
4880 	sqlite_freemem(errp);
4881 	errp = NULL;
4882     }
4883     s->rowp = -1;
4884     return SQL_SUCCESS;
4885 }
4886 
4887 
4888 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
4889 /**
4890  * Retrieve privileges on tables and/or views.
4891  * @param stmt statement handle
4892  * @param catalog catalog name/pattern or NULL
4893  * @param catalogLen length of catalog name/pattern or SQL_NTS
4894  * @param schema schema name/pattern or NULL
4895  * @param schemaLen length of schema name/pattern or SQL_NTS
4896  * @param table table name/pattern or NULL
4897  * @param tableLen length of table name/pattern or SQL_NTS
4898  * @result ODBC error code
4899  */
4900 
4901 SQLRETURN SQL_API
SQLTablePrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)4902 SQLTablePrivileges(SQLHSTMT stmt,
4903 		   SQLCHAR *catalog, SQLSMALLINT catalogLen,
4904 		   SQLCHAR *schema, SQLSMALLINT schemaLen,
4905 		   SQLCHAR *table, SQLSMALLINT tableLen)
4906 {
4907     SQLRETURN ret;
4908 
4909     HSTMT_LOCK(stmt);
4910     ret = drvtableprivileges(stmt, catalog, catalogLen, schema, schemaLen,
4911 			     table, tableLen);
4912     HSTMT_UNLOCK(stmt);
4913     return ret;
4914 }
4915 #endif
4916 
4917 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
4918 #ifdef WINTERFACE
4919 /**
4920  * Retrieve privileges on tables and/or views (UNICODE version).
4921  * @param stmt statement handle
4922  * @param catalog catalog name/pattern or NULL
4923  * @param catalogLen length of catalog name/pattern or SQL_NTS
4924  * @param schema schema name/pattern or NULL
4925  * @param schemaLen length of schema name/pattern or SQL_NTS
4926  * @param table table name/pattern or NULL
4927  * @param tableLen length of table name/pattern or SQL_NTS
4928  * @result ODBC error code
4929  */
4930 
4931 SQLRETURN SQL_API
SQLTablePrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)4932 SQLTablePrivilegesW(SQLHSTMT stmt,
4933 		    SQLWCHAR *catalog, SQLSMALLINT catalogLen,
4934 		    SQLWCHAR *schema, SQLSMALLINT schemaLen,
4935 		    SQLWCHAR *table, SQLSMALLINT tableLen)
4936 {
4937     char *c = NULL, *s = NULL, *t = NULL;
4938     SQLRETURN ret;
4939 
4940     HSTMT_LOCK(stmt);
4941     if (catalog) {
4942 	c = uc_to_utf_c(catalog, catalogLen);
4943 	if (!c) {
4944 	    ret = nomem((STMT *) stmt);
4945 	    goto done;
4946 	}
4947     }
4948     if (schema) {
4949 	s = uc_to_utf_c(schema, schemaLen);
4950 	if (!s) {
4951 	    ret = nomem((STMT *) stmt);
4952 	    goto done;
4953 	}
4954     }
4955     if (table) {
4956 	t = uc_to_utf_c(table, tableLen);
4957 	if (!t) {
4958 	    ret = nomem((STMT *) stmt);
4959 	    goto done;
4960 	}
4961     }
4962     ret = drvtableprivileges(stmt, (SQLCHAR *) c, SQL_NTS,
4963 			     (SQLCHAR *) s, SQL_NTS,
4964 			     (SQLCHAR *) t, SQL_NTS);
4965 done:
4966     HSTMT_UNLOCK(stmt);
4967     uc_free(t);
4968     uc_free(s);
4969     uc_free(c);
4970     return ret;
4971 }
4972 #endif
4973 #endif
4974 
4975 /**
4976  * Columns for result set of SQLColumnPrivileges().
4977  */
4978 
4979 static COL colPrivSpec2[] = {
4980     { "SYSTEM", "COLPRIV", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
4981     { "SYSTEM", "COLPRIV", "TABLE_OWNER", SCOL_VARCHAR, 50 },
4982     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
4983     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
4984     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
4985     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
4986     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
4987 };
4988 
4989 static COL colPrivSpec3[] = {
4990     { "SYSTEM", "COLPRIV", "TABLE_CAT", SCOL_VARCHAR, 50 },
4991     { "SYSTEM", "COLPRIV", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
4992     { "SYSTEM", "COLPRIV", "TABLE_NAME", SCOL_VARCHAR, 255 },
4993     { "SYSTEM", "COLPRIV", "COLUMN_NAME", SCOL_VARCHAR, 255 },
4994     { "SYSTEM", "COLPRIV", "GRANTOR", SCOL_VARCHAR, 50 },
4995     { "SYSTEM", "COLPRIV", "GRANTEE", SCOL_VARCHAR, 50 },
4996     { "SYSTEM", "COLPRIV", "PRIVILEGE", SCOL_VARCHAR, 50 }
4997 };
4998 
4999 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
5000 /**
5001  * Retrieve privileges on columns.
5002  * @param stmt statement handle
5003  * @param catalog catalog name/pattern or NULL
5004  * @param catalogLen length of catalog name/pattern or SQL_NTS
5005  * @param schema schema name/pattern or NULL
5006  * @param schemaLen length of schema name/pattern or SQL_NTS
5007  * @param table table name/pattern or NULL
5008  * @param tableLen length of table name/pattern or SQL_NTS
5009  * @param column column name or NULL
5010  * @param columnLen length of column name or SQL_NTS
5011  * @result ODBC error code
5012  */
5013 
5014 SQLRETURN SQL_API
SQLColumnPrivileges(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * column,SQLSMALLINT columnLen)5015 SQLColumnPrivileges(SQLHSTMT stmt,
5016 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
5017 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
5018 		    SQLCHAR *table, SQLSMALLINT tableLen,
5019 		    SQLCHAR *column, SQLSMALLINT columnLen)
5020 {
5021     SQLRETURN ret;
5022 
5023     HSTMT_LOCK(stmt);
5024     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
5025 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
5026     HSTMT_UNLOCK(stmt);
5027     return ret;
5028 }
5029 #endif
5030 
5031 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
5032 #ifdef WINTERFACE
5033 /**
5034  * Retrieve privileges on columns (UNICODE version).
5035  * @param stmt statement handle
5036  * @param catalog catalog name/pattern or NULL
5037  * @param catalogLen length of catalog name/pattern or SQL_NTS
5038  * @param schema schema name/pattern or NULL
5039  * @param schemaLen length of schema name/pattern or SQL_NTS
5040  * @param table table name/pattern or NULL
5041  * @param tableLen length of table name/pattern or SQL_NTS
5042  * @param column column name or NULL
5043  * @param columnLen length of column name or SQL_NTS
5044  * @result ODBC error code
5045  */
5046 
5047 SQLRETURN SQL_API
SQLColumnPrivilegesW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * column,SQLSMALLINT columnLen)5048 SQLColumnPrivilegesW(SQLHSTMT stmt,
5049 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
5050 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
5051 		     SQLWCHAR *table, SQLSMALLINT tableLen,
5052 		     SQLWCHAR *column, SQLSMALLINT columnLen)
5053 {
5054     SQLRETURN ret;
5055 
5056     HSTMT_LOCK(stmt);
5057     ret = mkresultset(stmt, colPrivSpec2, array_size(colPrivSpec2),
5058 		      colPrivSpec3, array_size(colPrivSpec3), NULL);
5059     HSTMT_UNLOCK(stmt);
5060     return ret;
5061 }
5062 #endif
5063 #endif
5064 
5065 /**
5066  * Columns for result set of SQLPrimaryKeys().
5067  */
5068 
5069 static COL pkeySpec2[] = {
5070     { "SYSTEM", "PRIMARYKEY", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5071     { "SYSTEM", "PRIMARYKEY", "TABLE_OWNER", SCOL_VARCHAR, 50 },
5072     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
5073     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5074     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
5075     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
5076 };
5077 
5078 static COL pkeySpec3[] = {
5079     { "SYSTEM", "PRIMARYKEY", "TABLE_CAT", SCOL_VARCHAR, 50 },
5080     { "SYSTEM", "PRIMARYKEY", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
5081     { "SYSTEM", "PRIMARYKEY", "TABLE_NAME", SCOL_VARCHAR, 255 },
5082     { "SYSTEM", "PRIMARYKEY", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5083     { "SYSTEM", "PRIMARYKEY", "KEY_SEQ", SQL_SMALLINT, 50 },
5084     { "SYSTEM", "PRIMARYKEY", "PK_NAME", SCOL_VARCHAR, 50 }
5085 };
5086 
5087 /**
5088  * Internal retrieve information about indexed columns.
5089  * @param stmt statement handle
5090  * @param cat catalog name/pattern or NULL
5091  * @param catLen length of catalog name/pattern or SQL_NTS
5092  * @param schema schema name/pattern or NULL
5093  * @param schemaLen length of schema name/pattern or SQL_NTS
5094  * @param table table name/pattern or NULL
5095  * @param tableLen length of table name/pattern or SQL_NTS
5096  * @result ODBC error code
5097  */
5098 
5099 static SQLRETURN
drvprimarykeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5100 drvprimarykeys(SQLHSTMT stmt,
5101 	       SQLCHAR *cat, SQLSMALLINT catLen,
5102 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
5103 	       SQLCHAR *table, SQLSMALLINT tableLen)
5104 {
5105     STMT *s;
5106     DBC *d;
5107     SQLRETURN sret;
5108     int i, asize, ret, nrows, ncols, nrows2 = 0, ncols2 = 0;
5109     int namec = -1, uniquec = -1, namec2 = -1, uniquec2 = -1, offs, seq = 1;
5110     PTRDIFF_T size;
5111     char **rowp = NULL, **rowp2 = NULL, *errp = NULL, tname[512];
5112 
5113     sret = mkresultset(stmt, pkeySpec2, array_size(pkeySpec2),
5114 		       pkeySpec3, array_size(pkeySpec3), &asize);
5115     if (sret != SQL_SUCCESS) {
5116 	return sret;
5117     }
5118     s = (STMT *) stmt;
5119     d = (DBC *) s->dbc;
5120     if (!table || table[0] == '\0' || table[0] == '%') {
5121 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
5122 	return SQL_ERROR;
5123     }
5124     if (tableLen == SQL_NTS) {
5125 	size = sizeof (tname) - 1;
5126     } else {
5127 	size = min(sizeof (tname) - 1, tableLen);
5128     }
5129     strncpy(tname, (char *) table, size);
5130     tname[size] = '\0';
5131     unescpat(tname);
5132     sret = starttran(s);
5133     if (sret != SQL_SUCCESS) {
5134 	return sret;
5135     }
5136     ret = sqlite_get_table_printf(d->sqlite,
5137 				  "PRAGMA table_info('%q')", &rowp,
5138 				  &nrows, &ncols, &errp, tname);
5139     if (ret != SQLITE_OK) {
5140 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5141 		errp ? errp : "unknown error", ret);
5142 	if (errp) {
5143 	    sqlite_freemem(errp);
5144 	    errp = NULL;
5145 	}
5146 	return SQL_ERROR;
5147     }
5148     if (errp) {
5149 	sqlite_freemem(errp);
5150 	errp = NULL;
5151     }
5152     size = 0;
5153     if (ncols * nrows > 0) {
5154 	int typec;
5155 
5156 	namec = findcol(rowp, ncols, "name");
5157 	uniquec = findcol(rowp, ncols, "pk");
5158 	typec = findcol(rowp, ncols, "type");
5159 	if (namec >= 0 && uniquec >= 0 && typec >= 0) {
5160 	    for (i = 1; i <= nrows; i++) {
5161 		if (*rowp[i * ncols + uniquec] != '0') {
5162 		    size++;
5163 		}
5164 	    }
5165 	}
5166     }
5167     if (size == 0) {
5168 	ret = sqlite_get_table_printf(d->sqlite,
5169 				      "PRAGMA index_list('%q')", &rowp2,
5170 				      &nrows2, &ncols2, &errp, tname);
5171 	if (ret != SQLITE_OK) {
5172 	    sqlite_free_table(rowp);
5173 	    sqlite_free_table(rowp2);
5174 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5175 		    errp ? errp : "unknown error", ret);
5176 	    if (errp) {
5177 		sqlite_freemem(errp);
5178 		errp = NULL;
5179 	    }
5180 	    return SQL_ERROR;
5181 	}
5182 	if (errp) {
5183 	    sqlite_freemem(errp);
5184 	    errp = NULL;
5185 	}
5186     }
5187     if (ncols2 * nrows2 > 0) {
5188 	namec2 = findcol(rowp2, ncols, "name");
5189 	uniquec2 = findcol(rowp2, ncols, "unique");
5190 	if (namec2 >= 0 && uniquec2 >= 0) {
5191 	    for (i = 1; i <= nrows2; i++) {
5192 		int nnrows, nncols;
5193 		char **rowpp;
5194 
5195 		if (*rowp2[i * ncols2 + namec2] != '(' ||
5196 		    !strstr(rowp2[i * ncols2 + namec2], " autoindex ")) {
5197 		    continue;
5198 		}
5199 		if (*rowp2[i * ncols2 + uniquec2] != '0') {
5200 		    ret = sqlite_get_table_printf(d->sqlite,
5201 						  "PRAGMA index_info('%q')",
5202 						  &rowpp, &nnrows, &nncols,
5203 						  NULL,
5204 						  rowp2[i * ncols2 + namec2]);
5205 		    if (ret == SQLITE_OK) {
5206 			size += nnrows;
5207 			sqlite_free_table(rowpp);
5208 		    }
5209 		}
5210 	    }
5211 	}
5212     }
5213     if (size == 0) {
5214 	sqlite_free_table(rowp);
5215 	sqlite_free_table(rowp2);
5216 	return SQL_SUCCESS;
5217     }
5218     s->nrows = size;
5219     size = (size + 1) * asize;
5220     s->rows = xmalloc((size + 1) * sizeof (char *));
5221     if (!s->rows) {
5222 	s->nrows = 0;
5223 	sqlite_free_table(rowp);
5224 	sqlite_free_table(rowp2);
5225 	return nomem(s);
5226     }
5227     s->rows[0] = (char *) size;
5228     s->rows += 1;
5229     memset(s->rows, 0, sizeof (char *) * size);
5230     s->rowfree = freerows;
5231     offs = s->ncols;
5232     if (rowp) {
5233 	for (i = 1; i <= nrows; i++) {
5234 	    if (*rowp[i * ncols + uniquec] != '0') {
5235 		char buf[32];
5236 
5237 #if defined(_WIN32) || defined(_WIN64)
5238 		s->rows[offs + 0] = xstrdup(d->xcelqrx ? "main" : "");
5239 		s->rows[offs + 1] = xstrdup("");
5240 #else
5241 		s->rows[offs + 0] = xstrdup("");
5242 		s->rows[offs + 1] = xstrdup("");
5243 #endif
5244 		s->rows[offs + 2] = xstrdup(tname);
5245 		s->rows[offs + 3] = xstrdup(rowp[i * ncols + namec]);
5246 		sprintf(buf, "%d", seq++);
5247 		s->rows[offs + 4] = xstrdup(buf);
5248 		offs += s->ncols;
5249 	    }
5250 	}
5251     }
5252     if (rowp2) {
5253 	for (i = 1; i <= nrows2; i++) {
5254 	    int nnrows, nncols;
5255 	    char **rowpp;
5256 
5257 	    if (*rowp2[i * ncols2 + namec2] != '(' ||
5258 		!strstr(rowp2[i * ncols2 + namec2], " autoindex ")) {
5259 		continue;
5260 	    }
5261 	    if (*rowp2[i * ncols2 + uniquec2] != '0') {
5262 		int k;
5263 
5264 		ret = sqlite_get_table_printf(d->sqlite,
5265 					      "PRAGMA index_info('%q')",
5266 					      &rowpp,
5267 					      &nnrows, &nncols, NULL,
5268 					      rowp2[i * ncols2 + namec2]);
5269 		if (ret != SQLITE_OK) {
5270 		    continue;
5271 		}
5272 		for (k = 0; nnrows && k < nncols; k++) {
5273 		    if (strcmp(rowpp[k], "name") == 0) {
5274 			int m;
5275 
5276 			for (m = 1; m <= nnrows; m++) {
5277 			    int roffs = offs + (m - 1) * s->ncols;
5278 
5279 #if defined(_WIN32) || defined(_WIN64)
5280 			    s->rows[roffs + 0] =
5281 				xstrdup(d->xcelqrx ? "main" : "");
5282 			    s->rows[roffs + 1] = xstrdup("");
5283 #else
5284 			    s->rows[roffs + 0] = xstrdup("");
5285 			    s->rows[roffs + 1] = xstrdup("");
5286 #endif
5287 			    s->rows[roffs + 2] = xstrdup(tname);
5288 			    s->rows[roffs + 3] =
5289 				xstrdup(rowpp[m * nncols + k]);
5290 			    s->rows[roffs + 5] =
5291 				xstrdup(rowp2[i * ncols2 + namec2]);
5292 			}
5293 		    } else if (strcmp(rowpp[k], "seqno") == 0) {
5294 			int m;
5295 
5296 			for (m = 1; m <= nnrows; m++) {
5297 			    int roffs = offs + (m - 1) * s->ncols;
5298 			    int pos = m - 1;
5299 			    char buf[32];
5300 
5301 			    sscanf(rowpp[m * nncols + k], "%d", &pos);
5302 			    sprintf(buf, "%d", pos + 1);
5303 			    s->rows[roffs + 4] = xstrdup(buf);
5304 			}
5305 		    }
5306 		}
5307 		offs += nnrows * s->ncols;
5308 		sqlite_free_table(rowpp);
5309 	    }
5310 	}
5311     }
5312     sqlite_free_table(rowp);
5313     sqlite_free_table(rowp2);
5314     return SQL_SUCCESS;
5315 }
5316 
5317 #ifndef WINTERFACE
5318 /**
5319  * Retrieve information about indexed columns.
5320  * @param stmt statement handle
5321  * @param cat catalog name/pattern or NULL
5322  * @param catLen length of catalog name/pattern or SQL_NTS
5323  * @param schema schema name/pattern or NULL
5324  * @param schemaLen length of schema name/pattern or SQL_NTS
5325  * @param table table name/pattern or NULL
5326  * @param tableLen length of table name/pattern or SQL_NTS
5327  * @result ODBC error code
5328  */
5329 
5330 SQLRETURN SQL_API
SQLPrimaryKeys(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen)5331 SQLPrimaryKeys(SQLHSTMT stmt,
5332 	       SQLCHAR *cat, SQLSMALLINT catLen,
5333 	       SQLCHAR *schema, SQLSMALLINT schemaLen,
5334 	       SQLCHAR *table, SQLSMALLINT tableLen)
5335 {
5336     SQLRETURN ret;
5337 
5338     HSTMT_LOCK(stmt);
5339     ret = drvprimarykeys(stmt, cat, catLen, schema, schemaLen,
5340 			 table, tableLen);
5341     HSTMT_UNLOCK(stmt);
5342     return ret;
5343 }
5344 #endif
5345 
5346 #ifdef WINTERFACE
5347 /**
5348  * Retrieve information about indexed columns (UNICODE version).
5349  * @param stmt statement handle
5350  * @param cat catalog name/pattern or NULL
5351  * @param catLen length of catalog name/pattern or SQL_NTS
5352  * @param schema schema name/pattern or NULL
5353  * @param schemaLen length of schema name/pattern or SQL_NTS
5354  * @param table table name/pattern or NULL
5355  * @param tableLen length of table name/pattern or SQL_NTS
5356  * @result ODBC error code
5357  */
5358 
5359 SQLRETURN SQL_API
SQLPrimaryKeysW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen)5360 SQLPrimaryKeysW(SQLHSTMT stmt,
5361 		SQLWCHAR *cat, SQLSMALLINT catLen,
5362 		SQLWCHAR *schema, SQLSMALLINT schemaLen,
5363 		SQLWCHAR *table, SQLSMALLINT tableLen)
5364 {
5365     char *c = NULL, *s = NULL, *t = NULL;
5366     SQLRETURN ret;
5367 
5368     HSTMT_LOCK(stmt);
5369     if (cat) {
5370 	c = uc_to_utf_c(cat, catLen);
5371 	if (!c) {
5372 	    ret = nomem((STMT *) stmt);
5373 	    goto done;
5374 	}
5375     }
5376     if (schema) {
5377 	s = uc_to_utf_c(schema, schemaLen);
5378 	if (!s) {
5379 	    ret = nomem((STMT *) stmt);
5380 	    goto done;
5381 	}
5382     }
5383     if (table) {
5384 	t = uc_to_utf_c(table, tableLen);
5385 	if (!t) {
5386 	    ret = nomem((STMT *) stmt);
5387 	    goto done;
5388 	}
5389     }
5390     ret = drvprimarykeys(stmt, (SQLCHAR *) c, SQL_NTS,
5391 			 (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS);
5392 done:
5393     HSTMT_UNLOCK(stmt);
5394     uc_free(t);
5395     uc_free(s);
5396     uc_free(c);
5397     return ret;
5398 }
5399 #endif
5400 
5401 /**
5402  * Columns for result set of SQLSpecialColumns().
5403  */
5404 
5405 static COL scolSpec2[] = {
5406     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
5407     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5408     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
5409     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
5410     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
5411     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
5412     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
5413     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
5414     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
5415 };
5416 
5417 static COL scolSpec3[] = {
5418     { "SYSTEM", "COLUMN", "SCOPE", SQL_SMALLINT, 1 },
5419     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
5420     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
5421     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
5422     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
5423     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
5424     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_INTEGER, 50 },
5425     { "SYSTEM", "COLUMN", "PSEUDO_COLUMN", SQL_SMALLINT, 1 },
5426     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 1 }
5427 };
5428 
5429 /**
5430  * Internal retrieve information about indexed columns.
5431  * @param stmt statement handle
5432  * @param id type of information, e.g. best row id
5433  * @param cat catalog name/pattern or NULL
5434  * @param catLen length of catalog name/pattern or SQL_NTS
5435  * @param schema schema name/pattern or NULL
5436  * @param schemaLen length of schema name/pattern or SQL_NTS
5437  * @param table table name/pattern or NULL
5438  * @param tableLen length of table name/pattern or SQL_NTS
5439  * @param scope
5440  * @param nullable
5441  * @result ODBC error code
5442  */
5443 
5444 static SQLRETURN
drvspecialcolumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)5445 drvspecialcolumns(SQLHSTMT stmt, SQLUSMALLINT id,
5446 		  SQLCHAR *cat, SQLSMALLINT catLen,
5447 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
5448 		  SQLCHAR *table, SQLSMALLINT tableLen,
5449 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
5450 {
5451     STMT *s;
5452     DBC *d;
5453     SQLRETURN sret;
5454     int i, asize, ret, nrows, ncols, nnnrows, nnncols, offs;
5455     int namec = -1, uniquec = -1, namecc = -1, typecc = -1;
5456     int notnullcc = -1, mkrowid = 0;
5457     PTRDIFF_T size;
5458     char *errp = NULL, tname[512];
5459     char **rowp = NULL, **rowppp = NULL;
5460 
5461     sret = mkresultset(stmt, scolSpec2, array_size(scolSpec2),
5462 		       scolSpec3, array_size(scolSpec3), &asize);
5463     if (sret != SQL_SUCCESS) {
5464 	return sret;
5465     }
5466     s = (STMT *) stmt;
5467     d = (DBC *) s->dbc;
5468     if (!table || table[0] == '\0' || table[0] == '%') {
5469 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
5470 	return SQL_ERROR;
5471     }
5472     if (tableLen == SQL_NTS) {
5473 	size = sizeof (tname) - 1;
5474     } else {
5475 	size = min(sizeof (tname) - 1, tableLen);
5476     }
5477     strncpy(tname, (char *) table, size);
5478     tname[size] = '\0';
5479     unescpat(tname);
5480     if (id != SQL_BEST_ROWID) {
5481 	return SQL_SUCCESS;
5482     }
5483     sret = starttran(s);
5484     if (sret != SQL_SUCCESS) {
5485 	return sret;
5486     }
5487     ret = sqlite_get_table_printf(d->sqlite, "PRAGMA index_list('%q')",
5488 				  &rowp, &nrows, &ncols, &errp, tname);
5489     if (ret != SQLITE_OK) {
5490 doerr:
5491 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5492 		errp ? errp : "unknown error", ret);
5493 	if (errp) {
5494 	    sqlite_freemem(errp);
5495 	    errp = NULL;
5496 	}
5497 	return SQL_ERROR;
5498     }
5499     if (errp) {
5500 	sqlite_freemem(errp);
5501 	errp = NULL;
5502     }
5503     size = 0;	/* number result rows */
5504     if (ncols * nrows <= 0) {
5505 	goto nodata_but_rowid;
5506     }
5507     ret = sqlite_get_table_printf(d->sqlite, "PRAGMA table_info('%q')",
5508 				  &rowppp, &nnnrows, &nnncols, &errp, tname);
5509     if (ret != SQLITE_OK) {
5510 	sqlite_free_table(rowp);
5511 	goto doerr;
5512     }
5513     if (errp) {
5514 	sqlite_freemem(errp);
5515 	errp = NULL;
5516     }
5517     namec = findcol(rowp, ncols, "name");
5518     uniquec = findcol(rowp, ncols, "unique");
5519     if (namec < 0 || uniquec < 0) {
5520 	goto nodata_but_rowid;
5521     }
5522     namecc = findcol(rowppp, nnncols, "name");
5523     typecc = findcol(rowppp, nnncols, "type");
5524     notnullcc = findcol(rowppp, nnncols, "notnull");
5525     for (i = 1; i <= nrows; i++) {
5526 	int nnrows, nncols;
5527 	char **rowpp;
5528 
5529 	if (*rowp[i * ncols + uniquec] != '0') {
5530 	    ret = sqlite_get_table_printf(d->sqlite,
5531 					  "PRAGMA index_info('%q')", &rowpp,
5532 					  &nnrows, &nncols, NULL,
5533 					  rowp[i * ncols + namec]);
5534 	    if (ret == SQLITE_OK) {
5535 		size += nnrows;
5536 		sqlite_free_table(rowpp);
5537 	    }
5538 	}
5539     }
5540 nodata_but_rowid:
5541     if (size == 0) {
5542 	size = 1;
5543 	mkrowid = 1;
5544     }
5545     s->nrows = size;
5546     size = (size + 1) * asize;
5547     s->rows = xmalloc((size + 1) * sizeof (char *));
5548     if (!s->rows) {
5549 	s->nrows = 0;
5550 	sqlite_free_table(rowp);
5551 	sqlite_free_table(rowppp);
5552 	return nomem(s);
5553     }
5554     s->rows[0] = (char *) size;
5555     s->rows += 1;
5556     memset(s->rows, 0, sizeof (char *) * size);
5557     s->rowfree = freerows;
5558     if (mkrowid) {
5559 	s->nrows = 0;
5560 	goto mkrowid;
5561     }
5562     offs = 0;
5563     for (i = 1; i <= nrows; i++) {
5564 	int nnrows, nncols;
5565 	char **rowpp;
5566 
5567 	if (*rowp[i * ncols + uniquec] != '0') {
5568 	    int k;
5569 
5570 	    ret = sqlite_get_table_printf(d->sqlite,
5571 					  "PRAGMA index_info('%q')", &rowpp,
5572 					  &nnrows, &nncols, NULL,
5573 					  rowp[i * ncols + namec]);
5574 	    if (ret != SQLITE_OK) {
5575 		continue;
5576 	    }
5577 	    for (k = 0; nnrows && k < nncols; k++) {
5578 		if (strcmp(rowpp[k], "name") == 0) {
5579 		    int m;
5580 
5581 		    for (m = 1; m <= nnrows; m++) {
5582 			int roffs = (offs + m) * s->ncols;
5583 
5584 			s->rows[roffs + 0] =
5585 			    xstrdup(stringify(SQL_SCOPE_SESSION));
5586 			s->rows[roffs + 1] = xstrdup(rowpp[m * nncols + k]);
5587 			s->rows[roffs + 4] = xstrdup("0");
5588 			s->rows[roffs + 7] =
5589 			    xstrdup(stringify(SQL_PC_NOT_PSEUDO));
5590 			if (namecc >= 0 && typecc >= 0) {
5591 			    int ii;
5592 
5593 			    for (ii = 1; ii <= nnnrows; ii++) {
5594 				if (strcmp(rowppp[ii * nnncols + namecc],
5595 					   rowpp[m * nncols + k]) == 0) {
5596 				    char *typen = rowppp[ii * nnncols + typecc];
5597 				    int sqltype, mm, dd, isnullable = 0;
5598 				    char buf[32];
5599 
5600 				    s->rows[roffs + 3] = xstrdup(typen);
5601 				    sqltype = mapsqltype(typen, NULL, *s->ov3,
5602 							 s->nowchar[0]);
5603 				    getmd(typen, sqltype, &mm, &dd);
5604 #ifdef SQL_LONGVARCHAR
5605 				    if (sqltype == SQL_VARCHAR && mm > 255) {
5606 					sqltype = SQL_LONGVARCHAR;
5607 				    }
5608 #endif
5609 #ifdef WINTERFACE
5610 #ifdef SQL_WLONGVARCHAR
5611 				    if (sqltype == SQL_WVARCHAR && mm > 255) {
5612 					sqltype = SQL_WLONGVARCHAR;
5613 				    }
5614 #endif
5615 #endif
5616 #if (HAVE_ENCDEC)
5617 				    if (sqltype == SQL_VARBINARY && mm > 255) {
5618 					sqltype = SQL_LONGVARBINARY;
5619 				    }
5620 #endif
5621 				    sprintf(buf, "%d", sqltype);
5622 				    s->rows[roffs + 2] = xstrdup(buf);
5623 				    sprintf(buf, "%d", mm);
5624 				    s->rows[roffs + 5] = xstrdup(buf);
5625 				    sprintf(buf, "%d", dd);
5626 				    s->rows[roffs + 6] = xstrdup(buf);
5627 				    if (notnullcc >= 0) {
5628 					char *inp =
5629 					   rowppp[ii * nnncols + notnullcc];
5630 
5631 					isnullable = inp[0] != '0';
5632 				    }
5633 				    sprintf(buf, "%d", isnullable);
5634 				    s->rows[roffs + 8] = xstrdup(buf);
5635 				}
5636 			    }
5637 			}
5638 		    }
5639 		}
5640 	    }
5641 	    offs += nnrows;
5642 	    sqlite_free_table(rowpp);
5643 	}
5644     }
5645     if (nullable == SQL_NO_NULLS) {
5646 	for (i = 1; i < s->nrows; i++) {
5647 	    if (s->rows[i * s->ncols + 8][0] == '0') {
5648 		int m, i1 = i + 1;
5649 
5650 		for (m = 0; m < s->ncols; m++) {
5651 		    freep(&s->rows[i * s->ncols + m]);
5652 		}
5653 		size = s->ncols * sizeof (char *) * (s->nrows - i1);
5654 		if (size > 0) {
5655 		    memmove(s->rows + i * s->ncols,
5656 			    s->rows + i1 * s->ncols,
5657 			    size);
5658 		    memset(s->rows + s->nrows * s->ncols, 0,
5659 			   s->ncols * sizeof (char *));
5660 		}
5661 		s->nrows--;
5662 		--i;
5663 	    }
5664 	}
5665     }
5666 mkrowid:
5667     sqlite_free_table(rowp);
5668     sqlite_free_table(rowppp);
5669     if (s->nrows == 0) {
5670 	s->rows[s->ncols + 0] = xstrdup(stringify(SQL_SCOPE_SESSION));
5671 	s->rows[s->ncols + 1] = xstrdup("_ROWID_");
5672 	s->rows[s->ncols + 2] = xstrdup(stringify(SQL_INTEGER));
5673 	s->rows[s->ncols + 3] = xstrdup("integer");
5674 	s->rows[s->ncols + 4] = xstrdup("0");
5675 	s->rows[s->ncols + 5] = xstrdup("10");
5676 	s->rows[s->ncols + 6] = xstrdup("9");
5677 	s->rows[s->ncols + 7] = xstrdup(stringify(SQL_PC_PSEUDO));
5678 	s->rows[s->ncols + 8] = xstrdup(stringify(SQL_FALSE));
5679 	s->nrows = 1;
5680     }
5681     return SQL_SUCCESS;
5682 }
5683 
5684 #ifndef WINTERFACE
5685 /**
5686  * Retrieve information about indexed columns.
5687  * @param stmt statement handle
5688  * @param id type of information, e.g. best row id
5689  * @param cat catalog name/pattern or NULL
5690  * @param catLen length of catalog name/pattern or SQL_NTS
5691  * @param schema schema name/pattern or NULL
5692  * @param schemaLen length of schema name/pattern or SQL_NTS
5693  * @param table table name/pattern or NULL
5694  * @param tableLen length of table name/pattern or SQL_NTS
5695  * @param scope
5696  * @param nullable
5697  * @result ODBC error code
5698  */
5699 
5700 SQLRETURN SQL_API
SQLSpecialColumns(SQLHSTMT stmt,SQLUSMALLINT id,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)5701 SQLSpecialColumns(SQLHSTMT stmt, SQLUSMALLINT id,
5702 		  SQLCHAR *cat, SQLSMALLINT catLen,
5703 		  SQLCHAR *schema, SQLSMALLINT schemaLen,
5704 		  SQLCHAR *table, SQLSMALLINT tableLen,
5705 		  SQLUSMALLINT scope, SQLUSMALLINT nullable)
5706 {
5707     SQLRETURN ret;
5708 
5709     HSTMT_LOCK(stmt);
5710     ret = drvspecialcolumns(stmt, id, cat, catLen, schema, schemaLen,
5711 			    table, tableLen, scope, nullable);
5712     HSTMT_UNLOCK(stmt);
5713     return ret;
5714 }
5715 #endif
5716 
5717 #ifdef WINTERFACE
5718 /**
5719  * Retrieve information about indexed columns (UNICODE version).
5720  * @param stmt statement handle
5721  * @param id type of information, e.g. best row id
5722  * @param cat catalog name/pattern or NULL
5723  * @param catLen length of catalog name/pattern or SQL_NTS
5724  * @param schema schema name/pattern or NULL
5725  * @param schemaLen length of schema name/pattern or SQL_NTS
5726  * @param table table name/pattern or NULL
5727  * @param tableLen length of table name/pattern or SQL_NTS
5728  * @param scope
5729  * @param nullable
5730  * @result ODBC error code
5731  */
5732 
5733 SQLRETURN SQL_API
SQLSpecialColumnsW(SQLHSTMT stmt,SQLUSMALLINT id,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT scope,SQLUSMALLINT nullable)5734 SQLSpecialColumnsW(SQLHSTMT stmt, SQLUSMALLINT id,
5735 		   SQLWCHAR *cat, SQLSMALLINT catLen,
5736 		   SQLWCHAR *schema, SQLSMALLINT schemaLen,
5737 		   SQLWCHAR *table, SQLSMALLINT tableLen,
5738 		   SQLUSMALLINT scope, SQLUSMALLINT nullable)
5739 {
5740     char *c = NULL, *s = NULL, *t = NULL;
5741     SQLRETURN ret;
5742 
5743     HSTMT_LOCK(stmt);
5744     if (cat) {
5745 	c = uc_to_utf_c(cat, catLen);
5746 	if (!c) {
5747 	    ret = nomem((STMT *) stmt);
5748 	    goto done;
5749 	}
5750     }
5751     if (schema) {
5752 	s = uc_to_utf_c(schema, schemaLen);
5753 	if (!s) {
5754 	    ret = nomem((STMT *) stmt);
5755 	    goto done;
5756 	}
5757     }
5758     if (table) {
5759 	t = uc_to_utf_c(table, tableLen);
5760 	if (!t) {
5761 	    ret = nomem((STMT *) stmt);
5762 	    goto done;
5763 	}
5764     }
5765     ret = drvspecialcolumns(stmt, id, (SQLCHAR *) c, SQL_NTS,
5766 			    (SQLCHAR *) s, SQL_NTS, (SQLCHAR *) t, SQL_NTS,
5767 			    scope, nullable);
5768 done:
5769     HSTMT_UNLOCK(stmt);
5770     uc_free(t);
5771     uc_free(s);
5772     uc_free(c);
5773     return ret;
5774 }
5775 #endif
5776 
5777 /**
5778  * Columns for result set of SQLForeignKeys().
5779  */
5780 
5781 static COL fkeySpec2[] = {
5782     { "SYSTEM", "FOREIGNKEY", "PKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5783     { "SYSTEM", "FOREIGNKEY", "PKTABLE_OWNER", SCOL_VARCHAR, 50 },
5784     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
5785     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
5786     { "SYSTEM", "FOREIGNKEY", "FKTABLE_QUALIFIER", SCOL_VARCHAR, 50 },
5787     { "SYSTEM", "FOREIGNKEY", "FKTABLE_OWNER", SCOL_VARCHAR, 50 },
5788     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
5789     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
5790     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
5791     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
5792     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
5793     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
5794     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
5795     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
5796 };
5797 
5798 static COL fkeySpec3[] = {
5799     { "SYSTEM", "FOREIGNKEY", "PKTABLE_CAT", SCOL_VARCHAR, 50 },
5800     { "SYSTEM", "FOREIGNKEY", "PKTABLE_SCHEM", SCOL_VARCHAR, 50 },
5801     { "SYSTEM", "FOREIGNKEY", "PKTABLE_NAME", SCOL_VARCHAR, 255 },
5802     { "SYSTEM", "FOREIGNKEY", "PKCOLUMN_NAME", SCOL_VARCHAR, 255 },
5803     { "SYSTEM", "FOREIGNKEY", "FKTABLE_CAT", SCOL_VARCHAR, 50 },
5804     { "SYSTEM", "FOREIGNKEY", "FKTABLE_SCHEM", SCOL_VARCHAR, 50 },
5805     { "SYSTEM", "FOREIGNKEY", "FKTABLE_NAME", SCOL_VARCHAR, 255 },
5806     { "SYSTEM", "FOREIGNKEY", "FKCOLUMN_NAME", SCOL_VARCHAR, 255 },
5807     { "SYSTEM", "FOREIGNKEY", "KEY_SEQ", SQL_SMALLINT, 5 },
5808     { "SYSTEM", "FOREIGNKEY", "UPDATE_RULE", SQL_SMALLINT, 5 },
5809     { "SYSTEM", "FOREIGNKEY", "DELETE_RULE", SQL_SMALLINT, 5 },
5810     { "SYSTEM", "FOREIGNKEY", "FK_NAME", SCOL_VARCHAR, 255 },
5811     { "SYSTEM", "FOREIGNKEY", "PK_NAME", SCOL_VARCHAR, 255 },
5812     { "SYSTEM", "FOREIGNKEY", "DEFERRABILITY", SQL_SMALLINT, 5 }
5813 };
5814 
5815 /**
5816  * Internal retrieve information about primary/foreign keys.
5817  * @param stmt statement handle
5818  * @param PKcatalog primary key catalog name/pattern or NULL
5819  * @param PKcatalogLen length of PKcatalog or SQL_NTS
5820  * @param PKschema primary key schema name/pattern or NULL
5821  * @param PKschemaLen length of PKschema or SQL_NTS
5822  * @param PKtable primary key table name/pattern or NULL
5823  * @param PKtableLen length of PKtable or SQL_NTS
5824  * @param FKcatalog foreign key catalog name/pattern or NULL
5825  * @param FKcatalogLen length of FKcatalog or SQL_NTS
5826  * @param FKschema foreign key schema name/pattern or NULL
5827  * @param FKschemaLen length of FKschema or SQL_NTS
5828  * @param FKtable foreign key table name/pattern or NULL
5829  * @param FKtableLen length of FKtable or SQL_NTS
5830  * @result ODBC error code
5831  */
5832 
5833 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)5834 drvforeignkeys(SQLHSTMT stmt,
5835 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
5836 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
5837 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
5838 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
5839 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
5840 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
5841 {
5842     STMT *s;
5843     DBC *d;
5844     SQLRETURN sret;
5845     int i, asize, ret, nrows, ncols, offs, namec, seqc, fromc, toc;
5846     PTRDIFF_T size;
5847     char **rowp, *errp = NULL, pname[512], fname[512];
5848 
5849     sret = mkresultset(stmt, fkeySpec2, array_size(fkeySpec2),
5850 		       fkeySpec3, array_size(fkeySpec3), &asize);
5851     if (sret != SQL_SUCCESS) {
5852 	return sret;
5853     }
5854     s = (STMT *) stmt;
5855     sret = starttran(s);
5856     if (sret != SQL_SUCCESS) {
5857 	return sret;
5858     }
5859     d = (DBC *) s->dbc;
5860     if ((!PKtable || PKtable[0] == '\0' || PKtable[0] == '%') &&
5861 	(!FKtable || FKtable[0] == '\0' || FKtable[0] == '%')) {
5862 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
5863 	return SQL_ERROR;
5864     }
5865     size = 0;
5866     if (PKtable) {
5867 	if (PKtableLen == SQL_NTS) {
5868 	    size = sizeof (pname) - 1;
5869 	} else {
5870 	    size = min(sizeof (pname) - 1, PKtableLen);
5871 	}
5872 	strncpy(pname, (char *) PKtable, size);
5873     }
5874     pname[size] = '\0';
5875     size = 0;
5876     if (FKtable) {
5877 	if (FKtableLen == SQL_NTS) {
5878 	    size = sizeof (fname) - 1;
5879 	} else {
5880 	    size = min(sizeof (fname) - 1, FKtableLen);
5881 	}
5882 	strncpy(fname, (char *) FKtable, size);
5883     }
5884     fname[size] = '\0';
5885     if (fname[0] != '\0') {
5886 	int plen;
5887 
5888 	ret = sqlite_get_table_printf(d->sqlite,
5889 				      "PRAGMA foreign_key_list('%q')", &rowp,
5890 				      &nrows, &ncols, &errp, fname);
5891 	if (ret != SQLITE_OK) {
5892 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5893 		    errp ? errp : "unknown error", ret);
5894 	    if (errp) {
5895 		sqlite_freemem(errp);
5896 		errp = NULL;
5897 	    }
5898 	    return SQL_ERROR;
5899 	}
5900 	if (errp) {
5901 	    sqlite_freemem(errp);
5902 	    errp = NULL;
5903 	}
5904 	if (ncols * nrows <= 0) {
5905 nodata:
5906 	    sqlite_free_table(rowp);
5907 	    return SQL_SUCCESS;
5908 	}
5909 	size = 0;
5910 	namec = findcol(rowp, ncols, "table");
5911 	seqc = findcol(rowp, ncols, "seq");
5912 	fromc = findcol(rowp, ncols, "from");
5913 	toc = findcol(rowp, ncols, "to");
5914 	if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
5915 	    goto nodata;
5916 	}
5917 	plen = strlen(pname);
5918 	for (i = 1; i <= nrows; i++) {
5919 	    char *ptab = unquote(rowp[i * ncols + namec]);
5920 
5921 	    if (plen && ptab) {
5922 		int len = strlen(ptab);
5923 
5924 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
5925 		    continue;
5926 		}
5927 	    }
5928 	    size++;
5929 	}
5930 	if (size == 0) {
5931 	    goto nodata;
5932 	}
5933 	s->nrows = size;
5934 	size = (size + 1) * asize;
5935 	s->rows = xmalloc((size + 1) * sizeof (char *));
5936 	if (!s->rows) {
5937 	    s->nrows = 0;
5938 	    return nomem(s);
5939 	}
5940 	s->rows[0] = (char *) size;
5941 	s->rows += 1;
5942 	memset(s->rows, 0, sizeof (char *) * size);
5943 	s->rowfree = freerows;
5944 	offs = 0;
5945 	for (i = 1; i <= nrows; i++) {
5946 	    int pos = 0, roffs = (offs + 1) * s->ncols;
5947 	    char *ptab = rowp[i * ncols + namec];
5948 	    char buf[32];
5949 
5950 	    if (plen && ptab) {
5951 		int len = strlen(ptab);
5952 
5953 		if (plen != len || strncasecmp(pname, ptab, plen) != 0) {
5954 		    continue;
5955 		}
5956 	    }
5957 #if defined(_WIN32) || defined(_WIN64)
5958 	    s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
5959 	    s->rows[roffs + 1] = xstrdup("");
5960 #else
5961 	    s->rows[roffs + 0] = xstrdup("");
5962 	    s->rows[roffs + 1] = xstrdup("");
5963 #endif
5964 	    s->rows[roffs + 2] = xstrdup(ptab);
5965 	    s->rows[roffs + 3] = xstrdup(rowp[i * ncols + toc]);
5966 	    s->rows[roffs + 4] = xstrdup("");
5967 	    s->rows[roffs + 5] = xstrdup("");
5968 	    s->rows[roffs + 6] = xstrdup(fname);
5969 	    s->rows[roffs + 7] = xstrdup(rowp[i * ncols + fromc]);
5970 	    sscanf(rowp[i * ncols + seqc], "%d", &pos);
5971 	    sprintf(buf, "%d", pos + 1);
5972 	    s->rows[roffs + 8] = xstrdup(buf);
5973 	    s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
5974 	    s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
5975 	    s->rows[roffs + 11] = NULL;
5976 	    s->rows[roffs + 12] = NULL;
5977 	    s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
5978 	    offs++;
5979 	}
5980 	sqlite_free_table(rowp);
5981     } else {
5982 	int nnrows, nncols, plen = strlen(pname);
5983 	char **rowpp;
5984 
5985 	ret = sqlite_get_table(d->sqlite,
5986 			       "select name from sqlite_master "
5987 			       "where type='table'", &rowp,
5988 			       &nrows, &ncols, &errp);
5989 	if (ret != SQLITE_OK) {
5990 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
5991 		    errp ? errp : "unknown error", ret);
5992 	    if (errp) {
5993 		sqlite_freemem(errp);
5994 		errp = NULL;
5995 	    }
5996 	    return SQL_ERROR;
5997 	}
5998 	if (errp) {
5999 	    sqlite_freemem(errp);
6000 	    errp = NULL;
6001 	}
6002 	if (ncols * nrows <= 0) {
6003 	    goto nodata;
6004 	}
6005 	size = 0;
6006 	for (i = 1; i <= nrows; i++) {
6007 	    int k;
6008 
6009 	    if (!rowp[i]) {
6010 		continue;
6011 	    }
6012 	    ret = sqlite_get_table_printf(d->sqlite,
6013 					  "PRAGMA foreign_key_list('%q')",
6014 					  &rowpp,
6015 					  &nnrows, &nncols, NULL, rowp[i]);
6016 	    if (ret != SQLITE_OK || nncols * nnrows <= 0) {
6017 		sqlite_free_table(rowpp);
6018 		continue;
6019 	    }
6020 	    namec = findcol(rowpp, nncols, "table");
6021 	    seqc = findcol(rowpp, nncols, "seq");
6022 	    fromc = findcol(rowpp, nncols, "from");
6023 	    toc = findcol(rowpp, nncols, "to");
6024 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
6025 		sqlite_free_table(rowpp);
6026 		continue;
6027 	    }
6028 	    for (k = 1; k <= nnrows; k++) {
6029 		char *ptab = unquote(rowpp[k * nncols + namec]);
6030 
6031 		if (plen && ptab) {
6032 		    int len = strlen(ptab);
6033 
6034 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
6035 			continue;
6036 		    }
6037 		}
6038 		size++;
6039 	    }
6040 	    sqlite_free_table(rowpp);
6041 	}
6042 	if (size == 0) {
6043 	    goto nodata;
6044 	}
6045 	s->nrows = size;
6046 	size = (size + 1) * asize;
6047 	s->rows = xmalloc((size + 1) * sizeof (char *));
6048 	if (!s->rows) {
6049 	    s->nrows = 0;
6050 	    return nomem(s);
6051 	}
6052 	s->rows[0] = (char *) size;
6053 	s->rows += 1;
6054 	memset(s->rows, 0, sizeof (char *) * size);
6055 	s->rowfree = freerows;
6056 	offs = 0;
6057 	for (i = 1; i <= nrows; i++) {
6058 	    int k;
6059 
6060 	    if (!rowp[i]) {
6061 		continue;
6062 	    }
6063 	    ret = sqlite_get_table_printf(d->sqlite,
6064 					  "PRAGMA foreign_key_list('%q')",
6065 					  &rowpp,
6066 					  &nnrows, &nncols, NULL, rowp[i]);
6067 	    if (ret != SQLITE_OK || nncols * nnrows <= 0) {
6068 		sqlite_free_table(rowpp);
6069 		continue;
6070 	    }
6071 	    namec = findcol(rowpp, nncols, "table");
6072 	    seqc = findcol(rowpp, nncols, "seq");
6073 	    fromc = findcol(rowpp, nncols, "from");
6074 	    toc = findcol(rowpp, nncols, "to");
6075 	    if (namec < 0 || seqc < 0 || fromc < 0 || toc < 0) {
6076 		sqlite_free_table(rowpp);
6077 		continue;
6078 	    }
6079 	    for (k = 1; k <= nnrows; k++) {
6080 		int pos = 0, roffs = (offs + 1) * s->ncols;
6081 		char *ptab = unquote(rowpp[k * nncols + namec]);
6082 		char buf[32];
6083 
6084 		if (plen && ptab) {
6085 		    int len = strlen(ptab);
6086 
6087 		    if (len != plen || strncasecmp(pname, ptab, plen) != 0) {
6088 			continue;
6089 		    }
6090 		}
6091 #if defined(_WIN32) || defined(_WIN64)
6092 		s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
6093 		s->rows[roffs + 1] = xstrdup("");
6094 #else
6095 		s->rows[roffs + 0] = xstrdup("");
6096 		s->rows[roffs + 1] = xstrdup("");
6097 #endif
6098 		s->rows[roffs + 2] = xstrdup(ptab);
6099 		s->rows[roffs + 3] = xstrdup(rowpp[k * nncols + toc]);
6100 		s->rows[roffs + 4] = xstrdup("");
6101 		s->rows[roffs + 5] = xstrdup("");
6102 		s->rows[roffs + 6] = xstrdup(rowp[i]);
6103 		s->rows[roffs + 7] = xstrdup(rowpp[k * nncols + fromc]);
6104 		sscanf(rowpp[k * nncols + seqc], "%d", &pos);
6105 		sprintf(buf, "%d", pos + 1);
6106 		s->rows[roffs + 8] = xstrdup(buf);
6107 		s->rows[roffs + 9] = xstrdup(stringify(SQL_NO_ACTION));
6108 		s->rows[roffs + 10] = xstrdup(stringify(SQL_NO_ACTION));
6109 		s->rows[roffs + 11] = NULL;
6110 		s->rows[roffs + 12] = NULL;
6111 		s->rows[roffs + 13] = xstrdup(stringify(SQL_NOT_DEFERRABLE));
6112 		offs++;
6113 	    }
6114 	    sqlite_free_table(rowpp);
6115 	}
6116 	sqlite_free_table(rowp);
6117     }
6118     return SQL_SUCCESS;
6119 }
6120 
6121 #ifndef WINTERFACE
6122 /**
6123  * Retrieve information about primary/foreign keys.
6124  * @param stmt statement handle
6125  * @param PKcatalog primary key catalog name/pattern or NULL
6126  * @param PKcatalogLen length of PKcatalog or SQL_NTS
6127  * @param PKschema primary key schema name/pattern or NULL
6128  * @param PKschemaLen length of PKschema or SQL_NTS
6129  * @param PKtable primary key table name/pattern or NULL
6130  * @param PKtableLen length of PKtable or SQL_NTS
6131  * @param FKcatalog foreign key catalog name/pattern or NULL
6132  * @param FKcatalogLen length of FKcatalog or SQL_NTS
6133  * @param FKschema foreign key schema name/pattern or NULL
6134  * @param FKschemaLen length of FKschema or SQL_NTS
6135  * @param FKtable foreign key table name/pattern or NULL
6136  * @param FKtableLen length of FKtable or SQL_NTS
6137  * @result ODBC error code
6138  */
6139 
6140 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)6141 SQLForeignKeys(SQLHSTMT stmt,
6142 	       SQLCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
6143 	       SQLCHAR *PKschema, SQLSMALLINT PKschemaLen,
6144 	       SQLCHAR *PKtable, SQLSMALLINT PKtableLen,
6145 	       SQLCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
6146 	       SQLCHAR *FKschema, SQLSMALLINT FKschemaLen,
6147 	       SQLCHAR *FKtable, SQLSMALLINT FKtableLen)
6148 {
6149     SQLRETURN ret;
6150 
6151     HSTMT_LOCK(stmt);
6152     ret = drvforeignkeys(stmt,
6153 			 PKcatalog, PKcatalogLen,
6154 			 PKschema, PKschemaLen, PKtable, PKtableLen,
6155 			 FKcatalog, FKcatalogLen,
6156 			 FKschema, FKschemaLen,
6157 			 FKtable, FKtableLen);
6158     HSTMT_UNLOCK(stmt);
6159     return ret;
6160 }
6161 #endif
6162 
6163 #ifdef WINTERFACE
6164 /**
6165  * Retrieve information about primary/foreign keys (UNICODE version).
6166  * @param stmt statement handle
6167  * @param PKcatalog primary key catalog name/pattern or NULL
6168  * @param PKcatalogLen length of PKcatalog or SQL_NTS
6169  * @param PKschema primary key schema name/pattern or NULL
6170  * @param PKschemaLen length of PKschema or SQL_NTS
6171  * @param PKtable primary key table name/pattern or NULL
6172  * @param PKtableLen length of PKtable or SQL_NTS
6173  * @param FKcatalog foreign key catalog name/pattern or NULL
6174  * @param FKcatalogLen length of FKcatalog or SQL_NTS
6175  * @param FKschema foreign key schema name/pattern or NULL
6176  * @param FKschemaLen length of FKschema or SQL_NTS
6177  * @param FKtable foreign key table name/pattern or NULL
6178  * @param FKtableLen length of FKtable or SQL_NTS
6179  * @result ODBC error code
6180  */
6181 
6182 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)6183 SQLForeignKeysW(SQLHSTMT stmt,
6184 		SQLWCHAR *PKcatalog, SQLSMALLINT PKcatalogLen,
6185 		SQLWCHAR *PKschema, SQLSMALLINT PKschemaLen,
6186 		SQLWCHAR *PKtable, SQLSMALLINT PKtableLen,
6187 		SQLWCHAR *FKcatalog, SQLSMALLINT FKcatalogLen,
6188 		SQLWCHAR *FKschema, SQLSMALLINT FKschemaLen,
6189 		SQLWCHAR *FKtable, SQLSMALLINT FKtableLen)
6190 {
6191     char *pc = NULL, *ps = NULL, *pt = NULL;
6192     char *fc = NULL, *fs = NULL, *ft = NULL;
6193     SQLRETURN ret;
6194 
6195     HSTMT_LOCK(stmt);
6196     if (PKcatalog) {
6197 	pc = uc_to_utf_c(PKcatalog, PKcatalogLen);
6198 	if (!pc) {
6199 	    ret = nomem((STMT *) stmt);
6200 	    goto done;
6201 	}
6202     }
6203     if (PKschema) {
6204 	ps = uc_to_utf_c(PKschema, PKschemaLen);
6205 	if (!ps) {
6206 	    ret = nomem((STMT *) stmt);
6207 	    goto done;
6208 	}
6209     }
6210     if (PKtable) {
6211 	pt = uc_to_utf_c(PKtable, PKtableLen);
6212 	if (!pt) {
6213 	    ret = nomem((STMT *) stmt);
6214 	    goto done;
6215 	}
6216     }
6217     if (FKcatalog) {
6218 	fc = uc_to_utf_c(FKcatalog, FKcatalogLen);
6219 	if (!fc) {
6220 	    ret = nomem((STMT *) stmt);
6221 	    goto done;
6222 	}
6223     }
6224     if (FKschema) {
6225 	fs = uc_to_utf_c(FKschema, FKschemaLen);
6226 	if (!fs) {
6227 	    ret = nomem((STMT *) stmt);
6228 	    goto done;
6229 	}
6230     }
6231     if (FKtable) {
6232 	ft = uc_to_utf_c(FKtable, FKtableLen);
6233 	if (!ft) {
6234 	    ret = nomem((STMT *) stmt);
6235 	    goto done;
6236 	}
6237     }
6238     ret = drvforeignkeys(stmt, (SQLCHAR *) pc, SQL_NTS,
6239 			 (SQLCHAR *) ps, SQL_NTS, (SQLCHAR *) pt, SQL_NTS,
6240 			 (SQLCHAR *) fc, SQL_NTS, (SQLCHAR *) fs, SQL_NTS,
6241 			 (SQLCHAR *) ft, SQL_NTS);
6242 done:
6243     HSTMT_UNLOCK(stmt);
6244     uc_free(ft);
6245     uc_free(fs);
6246     uc_free(fc);
6247     uc_free(pt);
6248     uc_free(ps);
6249     uc_free(pc);
6250     return ret;
6251 }
6252 #endif
6253 
6254 /**
6255  * Start transaction when autocommit off
6256  * @param s statement pointer
6257  * @result ODBC error code
6258  */
6259 
6260 static SQLRETURN
starttran(STMT * s)6261 starttran(STMT *s)
6262 {
6263     int ret = SQL_SUCCESS, rc;
6264     char *errp = NULL;
6265     DBC *d = (DBC *) s->dbc;
6266 
6267     if (!d->autocommit && !d->intrans && !d->trans_disable) {
6268 	rc = sqlite_exec(d->sqlite, "BEGIN TRANSACTION", NULL, NULL, &errp);
6269 	dbtracerc(d, rc, errp);
6270 	if (rc != SQLITE_OK) {
6271 	    setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
6272 		    errp ? errp : "unknown error", rc);
6273 	    ret = SQL_ERROR;
6274 	} else {
6275 	    d->intrans = 1;
6276 	}
6277 	if (errp) {
6278 	    sqlite_freemem(errp);
6279 	    errp = NULL;
6280 	}
6281     }
6282     return ret;
6283 }
6284 
6285 /**
6286  * Internal commit or rollback transaction.
6287  * @param d database connection pointer
6288  * @param comptype type of transaction's end, SQL_COMMIT or SQL_ROLLBACK
6289  * @param force force action regardless of DBC's autocommit state
6290  * @result ODBC error code
6291  */
6292 
6293 static SQLRETURN
endtran(DBC * d,SQLSMALLINT comptype,int force)6294 endtran(DBC *d, SQLSMALLINT comptype, int force)
6295 {
6296     int ret;
6297     char *sql, *errp = NULL;
6298 
6299     if (!d->sqlite) {
6300 	setstatd(d, -1, "not connected", (*d->ov3) ? "HY000" : "S1000");
6301 	return SQL_ERROR;
6302     }
6303     if ((!force && d->autocommit) || !d->intrans) {
6304 	return SQL_SUCCESS;
6305     }
6306     switch (comptype) {
6307     case SQL_COMMIT:
6308 	sql = "COMMIT TRANSACTION";
6309 	goto doit;
6310     case SQL_ROLLBACK:
6311 	sql = "ROLLBACK TRANSACTION";
6312     doit:
6313 	ret = sqlite_exec(d->sqlite, sql, NULL, NULL, &errp);
6314 	dbtracerc(d, ret, errp);
6315 	if (ret != SQLITE_OK) {
6316 	    setstatd(d, ret, "%s", (*d->ov3) ? "HY000" : "S1000",
6317 		     errp ? errp : "transaction failed");
6318 	    if (errp) {
6319 		sqlite_freemem(errp);
6320 		errp = NULL;
6321 	    }
6322 	    return SQL_ERROR;
6323 	}
6324 	if (errp) {
6325 	    sqlite_freemem(errp);
6326 	    errp = NULL;
6327 	}
6328 	d->intrans = 0;
6329 	return SQL_SUCCESS;
6330     }
6331     setstatd(d, -1, "invalid completion type", (*d->ov3) ? "HY000" : "S1000");
6332     return SQL_ERROR;
6333 }
6334 
6335 /**
6336  * Internal commit or rollback transaction.
6337  * @param type type of handle
6338  * @param handle HDBC, HENV, or HSTMT handle
6339  * @param comptype SQL_COMMIT or SQL_ROLLBACK
6340  * @result ODBC error code
6341  */
6342 
6343 static SQLRETURN
drvendtran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)6344 drvendtran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
6345 {
6346     DBC *dbc = NULL;
6347     int fail = 0;
6348     SQLRETURN ret;
6349 #if defined(_WIN32) || defined(_WIN64)
6350     ENV *env;
6351 #endif
6352 
6353     switch (type) {
6354     case SQL_HANDLE_DBC:
6355 	HDBC_LOCK((SQLHDBC) handle);
6356 	if (handle == SQL_NULL_HDBC) {
6357 	    return SQL_INVALID_HANDLE;
6358 	}
6359 	dbc = (DBC *) handle;
6360 	ret = endtran(dbc, comptype, 0);
6361 	HDBC_UNLOCK((SQLHDBC) handle);
6362 	return ret;
6363     case SQL_HANDLE_ENV:
6364 	if (handle == SQL_NULL_HENV) {
6365 	    return SQL_INVALID_HANDLE;
6366 	}
6367 #if defined(_WIN32) || defined(_WIN64)
6368 	env = (ENV *) handle;
6369 	if (env->magic != ENV_MAGIC) {
6370 	    return SQL_INVALID_HANDLE;
6371 	}
6372 	EnterCriticalSection(&env->cs);
6373 #endif
6374 	dbc = ((ENV *) handle)->dbcs;
6375 	while (dbc) {
6376 	    HDBC_LOCK((SQLHDBC) dbc);
6377 	    ret = endtran(dbc, comptype, 0);
6378 	    HDBC_UNLOCK((SQLHDBC) dbc);
6379 	    if (ret != SQL_SUCCESS) {
6380 		fail++;
6381 	    }
6382 	    dbc = dbc->next;
6383 	}
6384 #if defined(_WIN32) || defined(_WIN64)
6385 	LeaveCriticalSection(&env->cs);
6386 #endif
6387 	return fail ? SQL_ERROR : SQL_SUCCESS;
6388     }
6389     return SQL_INVALID_HANDLE;
6390 }
6391 
6392 /**
6393  * Commit or rollback transaction.
6394  * @param type type of handle
6395  * @param handle HDBC, HENV, or HSTMT handle
6396  * @param comptype SQL_COMMIT or SQL_ROLLBACK
6397  * @result ODBC error code
6398  */
6399 
6400 SQLRETURN SQL_API
SQLEndTran(SQLSMALLINT type,SQLHANDLE handle,SQLSMALLINT comptype)6401 SQLEndTran(SQLSMALLINT type, SQLHANDLE handle, SQLSMALLINT comptype)
6402 {
6403     return drvendtran(type, handle, comptype);
6404 }
6405 
6406 /**
6407  * Commit or rollback transaction.
6408  * @param env environment handle or NULL
6409  * @param dbc database connection handle or NULL
6410  * @param type SQL_COMMIT or SQL_ROLLBACK
6411  * @result ODBC error code
6412  */
6413 
6414 SQLRETURN SQL_API
SQLTransact(SQLHENV env,SQLHDBC dbc,SQLUSMALLINT type)6415 SQLTransact(SQLHENV env, SQLHDBC dbc, SQLUSMALLINT type)
6416 {
6417     if (dbc != SQL_NULL_HDBC) {
6418 	return drvendtran(SQL_HANDLE_DBC, (SQLHANDLE) dbc, type);
6419     }
6420     return drvendtran(SQL_HANDLE_ENV, (SQLHANDLE) env, type);
6421 }
6422 
6423 /**
6424  * Function not implemented.
6425  */
6426 
6427 SQLRETURN SQL_API
SQLCopyDesc(SQLHDESC source,SQLHDESC target)6428 SQLCopyDesc(SQLHDESC source, SQLHDESC target)
6429 {
6430     return SQL_ERROR;
6431 }
6432 
6433 #ifndef WINTERFACE
6434 /**
6435  * Translate SQL string.
6436  * @param stmt statement handle
6437  * @param sqlin input string
6438  * @param sqlinLen length of input string
6439  * @param sql output string
6440  * @param sqlMax max space in output string
6441  * @param sqlLen value return for length of output string
6442  * @result ODBC error code
6443  */
6444 
6445 SQLRETURN SQL_API
SQLNativeSql(SQLHSTMT stmt,SQLCHAR * sqlin,SQLINTEGER sqlinLen,SQLCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)6446 SQLNativeSql(SQLHSTMT stmt, SQLCHAR *sqlin, SQLINTEGER sqlinLen,
6447 	     SQLCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
6448 {
6449     int outLen = 0;
6450     SQLRETURN ret = SQL_SUCCESS;
6451 
6452     HSTMT_LOCK(stmt);
6453     if (sqlinLen == SQL_NTS) {
6454 	sqlinLen = strlen((char *) sqlin);
6455     }
6456     if (sql) {
6457 	if (sqlMax > 0) {
6458 	    strncpy((char *) sql, (char *) sqlin, sqlMax - 1);
6459 	    sqlin[sqlMax - 1] = '\0';
6460 	    outLen = min(sqlMax - 1, sqlinLen);
6461 	}
6462     } else {
6463 	outLen = sqlinLen;
6464     }
6465     if (sqlLen) {
6466 	*sqlLen = outLen;
6467     }
6468     if (sql && outLen < sqlinLen) {
6469 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
6470 	ret = SQL_SUCCESS_WITH_INFO;
6471     }
6472     HSTMT_UNLOCK(stmt);
6473     return ret;
6474 }
6475 #endif
6476 
6477 #ifdef WINTERFACE
6478 /**
6479  * Translate SQL string (UNICODE version).
6480  * @param stmt statement handle
6481  * @param sqlin input string
6482  * @param sqlinLen length of input string
6483  * @param sql output string
6484  * @param sqlMax max space in output string
6485  * @param sqlLen value return for length of output string
6486  * @result ODBC error code
6487  */
6488 
6489 SQLRETURN SQL_API
SQLNativeSqlW(SQLHSTMT stmt,SQLWCHAR * sqlin,SQLINTEGER sqlinLen,SQLWCHAR * sql,SQLINTEGER sqlMax,SQLINTEGER * sqlLen)6490 SQLNativeSqlW(SQLHSTMT stmt, SQLWCHAR *sqlin, SQLINTEGER sqlinLen,
6491 	      SQLWCHAR *sql, SQLINTEGER sqlMax, SQLINTEGER *sqlLen)
6492 {
6493     int outLen = 0;
6494     SQLRETURN ret = SQL_SUCCESS;
6495 
6496     HSTMT_LOCK(stmt);
6497     if (sqlinLen == SQL_NTS) {
6498 	sqlinLen = uc_strlen(sqlin);
6499     }
6500     if (sql) {
6501 	if (sqlMax > 0) {
6502 	    uc_strncpy(sql, sqlin, sqlMax - 1);
6503 	    sqlin[sqlMax - 1] = 0;
6504 	    outLen = min(sqlMax  - 1, sqlinLen);
6505 	}
6506     } else {
6507 	outLen = sqlinLen;
6508     }
6509     if (sqlLen) {
6510 	*sqlLen = outLen;
6511     }
6512     if (sql && outLen < sqlinLen) {
6513 	setstat((STMT *) stmt, -1, "data right truncated", "01004");
6514 	ret = SQL_SUCCESS_WITH_INFO;
6515     }
6516     HSTMT_UNLOCK(stmt);
6517     return ret;
6518 }
6519 #endif
6520 
6521 /**
6522  * Columns for result set of SQLProcedures().
6523  */
6524 
6525 static COL procSpec2[] = {
6526     { "SYSTEM", "PROCEDURE", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
6527     { "SYSTEM", "PROCEDURE", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
6528     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
6529     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
6530     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
6531     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
6532     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
6533     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
6534 };
6535 
6536 static COL procSpec3[] = {
6537     { "SYSTEM", "PROCEDURE", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
6538     { "SYSTEM", "PROCEDURE", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
6539     { "SYSTEM", "PROCEDURE", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
6540     { "SYSTEM", "PROCEDURE", "NUM_INPUT_PARAMS", SQL_SMALLINT, 5 },
6541     { "SYSTEM", "PROCEDURE", "NUM_OUTPUT_PARAMS", SQL_SMALLINT, 5 },
6542     { "SYSTEM", "PROCEDURE", "NUM_RESULT_SETS", SQL_SMALLINT, 5 },
6543     { "SYSTEM", "PROCEDURE", "REMARKS", SCOL_VARCHAR, 255 },
6544     { "SYSTEM", "PROCEDURE", "PROCEDURE_TYPE", SQL_SMALLINT, 5 }
6545 };
6546 
6547 #ifndef WINTERFACE
6548 /**
6549  * Retrieve information about stored procedures.
6550  * @param stmt statement handle
6551  * @param catalog catalog name/pattern or NULL
6552  * @param catalogLen length of catalog or SQL_NTS
6553  * @param schema schema name/pattern or NULL
6554  * @param schemaLen length of schema or SQL_NTS
6555  * @param proc procedure name/pattern or NULL
6556  * @param procLen length of proc or SQL_NTS
6557  * @result ODBC error code
6558  */
6559 
6560 SQLRETURN SQL_API
SQLProcedures(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen)6561 SQLProcedures(SQLHSTMT stmt,
6562 	      SQLCHAR *catalog, SQLSMALLINT catalogLen,
6563 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
6564 	      SQLCHAR *proc, SQLSMALLINT procLen)
6565 {
6566     SQLRETURN ret;
6567 
6568     HSTMT_LOCK(stmt);
6569     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
6570 		      procSpec3, array_size(procSpec3), NULL);
6571     HSTMT_UNLOCK(stmt);
6572     return ret;
6573 }
6574 #endif
6575 
6576 #ifdef WINTERFACE
6577 /**
6578  * Retrieve information about stored procedures (UNICODE version).
6579  * @param stmt statement handle
6580  * @param catalog catalog name/pattern or NULL
6581  * @param catalogLen length of catalog or SQL_NTS
6582  * @param schema schema name/pattern or NULL
6583  * @param schemaLen length of schema or SQL_NTS
6584  * @param proc procedure name/pattern or NULL
6585  * @param procLen length of proc or SQL_NTS
6586  * @result ODBC error code
6587  */
6588 
6589 SQLRETURN SQL_API
SQLProceduresW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen)6590 SQLProceduresW(SQLHSTMT stmt,
6591 	       SQLWCHAR *catalog, SQLSMALLINT catalogLen,
6592 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
6593 	       SQLWCHAR *proc, SQLSMALLINT procLen)
6594 {
6595     SQLRETURN ret;
6596 
6597     HSTMT_LOCK(stmt);
6598     ret = mkresultset(stmt, procSpec2, array_size(procSpec2),
6599 		      procSpec3, array_size(procSpec3), NULL);
6600     HSTMT_UNLOCK(stmt);
6601     return ret;
6602 }
6603 #endif
6604 
6605 /**
6606  * Columns for result set of SQLProcedureColumns().
6607  */
6608 
6609 static COL procColSpec2[] = {
6610     { "SYSTEM", "PROCCOL", "PROCEDURE_QUALIFIER", SCOL_VARCHAR, 50 },
6611     { "SYSTEM", "PROCCOL", "PROCEDURE_OWNER", SCOL_VARCHAR, 50 },
6612     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
6613     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6614     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
6615     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
6616     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
6617     { "SYSTEM", "PROCCOL", "PRECISION", SQL_INTEGER, 10 },
6618     { "SYSTEM", "PROCCOL", "LENGTH", SQL_INTEGER, 10 },
6619     { "SYSTEM", "PROCCOL", "SCALE", SQL_SMALLINT, 5 },
6620     { "SYSTEM", "PROCCOL", "RADIX", SQL_SMALLINT, 5 },
6621     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
6622     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
6623     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
6624     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
6625     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
6626     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
6627     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
6628     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
6629 };
6630 
6631 static COL procColSpec3[] = {
6632     { "SYSTEM", "PROCCOL", "PROCEDURE_CAT", SCOL_VARCHAR, 50 },
6633     { "SYSTEM", "PROCCOL", "PROCEDURE_SCHEM", SCOL_VARCHAR, 50 },
6634     { "SYSTEM", "PROCCOL", "PROCEDURE_NAME", SCOL_VARCHAR, 255 },
6635     { "SYSTEM", "PROCCOL", "COLUMN_NAME", SCOL_VARCHAR, 255 },
6636     { "SYSTEM", "PROCCOL", "COLUMN_TYPE", SQL_SMALLINT, 5 },
6637     { "SYSTEM", "PROCCOL", "DATA_TYPE", SQL_SMALLINT, 5 },
6638     { "SYSTEM", "PROCCOL", "TYPE_NAME", SCOL_VARCHAR, 50 },
6639     { "SYSTEM", "PROCCOL", "COLUMN_SIZE", SQL_INTEGER, 10 },
6640     { "SYSTEM", "PROCCOL", "BUFFER_LENGTH", SQL_INTEGER, 10 },
6641     { "SYSTEM", "PROCCOL", "DECIMAL_DIGITS", SQL_SMALLINT, 5 },
6642     { "SYSTEM", "PROCCOL", "NUM_PREC_RADIX", SQL_SMALLINT, 5 },
6643     { "SYSTEM", "PROCCOL", "NULLABLE", SQL_SMALLINT, 5 },
6644     { "SYSTEM", "PROCCOL", "REMARKS", SCOL_VARCHAR, 50 },
6645     { "SYSTEM", "PROCCOL", "COLUMN_DEF", SCOL_VARCHAR, 50 },
6646     { "SYSTEM", "PROCCOL", "SQL_DATA_TYPE", SQL_SMALLINT, 5 },
6647     { "SYSTEM", "PROCCOL", "SQL_DATETIME_SUB", SQL_SMALLINT, 5 },
6648     { "SYSTEM", "PROCCOL", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 5 },
6649     { "SYSTEM", "PROCCOL", "ORDINAL_POSITION", SQL_SMALLINT, 5 },
6650     { "SYSTEM", "PROCCOL", "IS_NULLABLE", SCOL_VARCHAR, 50 }
6651 };
6652 
6653 #ifndef WINTERFACE
6654 /**
6655  * Retrieve information about columns in result set of stored procedures.
6656  * @param stmt statement handle
6657  * @param catalog catalog name/pattern or NULL
6658  * @param catalogLen length of catalog or SQL_NTS
6659  * @param schema schema name/pattern or NULL
6660  * @param schemaLen length of schema or SQL_NTS
6661  * @param proc procedure name/pattern or NULL
6662  * @param procLen length of proc or SQL_NTS
6663  * @param column column name/pattern or NULL
6664  * @param columnLen length of column or SQL_NTS
6665  * @result ODBC error code
6666  */
6667 
6668 SQLRETURN SQL_API
SQLProcedureColumns(SQLHSTMT stmt,SQLCHAR * catalog,SQLSMALLINT catalogLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * proc,SQLSMALLINT procLen,SQLCHAR * column,SQLSMALLINT columnLen)6669 SQLProcedureColumns(SQLHSTMT stmt,
6670 		    SQLCHAR *catalog, SQLSMALLINT catalogLen,
6671 		    SQLCHAR *schema, SQLSMALLINT schemaLen,
6672 		    SQLCHAR *proc, SQLSMALLINT procLen,
6673 		    SQLCHAR *column, SQLSMALLINT columnLen)
6674 {
6675     SQLRETURN ret;
6676 
6677     HSTMT_LOCK(stmt);
6678     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
6679 		      procColSpec3, array_size(procColSpec3), NULL);
6680     HSTMT_UNLOCK(stmt);
6681     return ret;
6682 }
6683 #endif
6684 
6685 #ifdef WINTERFACE
6686 /**
6687  * Retrieve information about columns in result
6688  * set of stored procedures (UNICODE version).
6689  * @param stmt statement handle
6690  * @param catalog catalog name/pattern or NULL
6691  * @param catalogLen length of catalog or SQL_NTS
6692  * @param schema schema name/pattern or NULL
6693  * @param schemaLen length of schema or SQL_NTS
6694  * @param proc procedure name/pattern or NULL
6695  * @param procLen length of proc or SQL_NTS
6696  * @param column column name/pattern or NULL
6697  * @param columnLen length of column or SQL_NTS
6698  * @result ODBC error code
6699  */
6700 
6701 SQLRETURN SQL_API
SQLProcedureColumnsW(SQLHSTMT stmt,SQLWCHAR * catalog,SQLSMALLINT catalogLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * proc,SQLSMALLINT procLen,SQLWCHAR * column,SQLSMALLINT columnLen)6702 SQLProcedureColumnsW(SQLHSTMT stmt,
6703 		     SQLWCHAR *catalog, SQLSMALLINT catalogLen,
6704 		     SQLWCHAR *schema, SQLSMALLINT schemaLen,
6705 		     SQLWCHAR *proc, SQLSMALLINT procLen,
6706 		     SQLWCHAR *column, SQLSMALLINT columnLen)
6707 {
6708     SQLRETURN ret;
6709 
6710     HSTMT_LOCK(stmt);
6711     ret = mkresultset(stmt, procColSpec2, array_size(procColSpec2),
6712 		      procColSpec3, array_size(procColSpec3), NULL);
6713     HSTMT_UNLOCK(stmt);
6714     return ret;
6715 }
6716 #endif
6717 
6718 /**
6719  * Get information of HENV.
6720  * @param env environment handle
6721  * @param attr attribute to be retrieved
6722  * @param val output buffer
6723  * @param len length of output buffer
6724  * @param lenp output length
6725  * @result ODBC error code
6726  */
6727 
6728 SQLRETURN SQL_API
SQLGetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len,SQLINTEGER * lenp)6729 SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val,
6730 	      SQLINTEGER len, SQLINTEGER *lenp)
6731 {
6732     ENV *e;
6733     SQLRETURN ret = SQL_ERROR;
6734 
6735     if (env == SQL_NULL_HENV) {
6736 	return SQL_INVALID_HANDLE;
6737     }
6738     e = (ENV *) env;
6739     if (!e || e->magic != ENV_MAGIC) {
6740 	return SQL_INVALID_HANDLE;
6741     }
6742 #if defined(_WIN32) || defined(_WIN64)
6743     EnterCriticalSection(&e->cs);
6744 #endif
6745     switch (attr) {
6746     case SQL_ATTR_CONNECTION_POOLING:
6747 	if (val) {
6748 	    *((SQLINTEGER *) val) = e->pool ?
6749 		SQL_CP_ONE_PER_DRIVER : SQL_CP_OFF;
6750 	}
6751 	if (lenp) {
6752 	    *lenp = sizeof (SQLINTEGER);
6753 	}
6754 	ret = SQL_SUCCESS;
6755 	break;
6756     case SQL_ATTR_CP_MATCH:
6757 	*((SQLINTEGER *) val) = SQL_CP_RELAXED_MATCH;
6758 	if (lenp) {
6759 	    *lenp = sizeof (SQLINTEGER);
6760 	}
6761 	ret = SQL_SUCCESS;
6762 	break;
6763     case SQL_ATTR_OUTPUT_NTS:
6764 	if (val) {
6765 	    *((SQLINTEGER *) val) = SQL_TRUE;
6766 	}
6767 	if (lenp) {
6768 	    *lenp = sizeof (SQLINTEGER);
6769 	}
6770 	ret = SQL_SUCCESS;
6771 	break;
6772     case SQL_ATTR_ODBC_VERSION:
6773 	if (val) {
6774 	    *((SQLINTEGER *) val) = e->ov3 ? SQL_OV_ODBC3 : SQL_OV_ODBC2;
6775 	}
6776 	if (lenp) {
6777 	    *lenp = sizeof (SQLINTEGER);
6778 	}
6779 	ret = SQL_SUCCESS;
6780 	break;
6781     }
6782 #if defined(_WIN32) || defined(_WIN64)
6783     LeaveCriticalSection(&e->cs);
6784 #endif
6785     return ret;
6786 }
6787 
6788 /**
6789  * Set information in HENV.
6790  * @param env environment handle
6791  * @param attr attribute to be retrieved
6792  * @param val parameter buffer
6793  * @param len length of parameter
6794  * @result ODBC error code
6795  */
6796 
6797 SQLRETURN SQL_API
SQLSetEnvAttr(SQLHENV env,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)6798 SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
6799 {
6800     ENV *e;
6801     SQLRETURN ret = SQL_ERROR;
6802 
6803     if (env == SQL_NULL_HENV) {
6804 	return SQL_INVALID_HANDLE;
6805     }
6806     e = (ENV *) env;
6807     if (!e || e->magic != ENV_MAGIC) {
6808 	return SQL_INVALID_HANDLE;
6809     }
6810 #if defined(_WIN32) || defined(_WIN64)
6811     EnterCriticalSection(&e->cs);
6812 #endif
6813     switch (attr) {
6814     case SQL_ATTR_CONNECTION_POOLING:
6815 	if (val == (SQLPOINTER) SQL_CP_ONE_PER_DRIVER) {
6816 	    e->pool = 1;
6817 	    ret = SQL_SUCCESS;
6818 	} else if (val == (SQLPOINTER) SQL_CP_OFF) {
6819 	    e->pool = 0;
6820 	    ret = SQL_SUCCESS;
6821 	}
6822 	break;
6823     case SQL_ATTR_CP_MATCH:
6824 	ret = SQL_SUCCESS;
6825 	break;
6826     case SQL_ATTR_OUTPUT_NTS:
6827 	if (val == (SQLPOINTER) SQL_TRUE) {
6828 	    ret = SQL_SUCCESS;
6829 	}
6830 	break;
6831     case SQL_ATTR_ODBC_VERSION:
6832 	if (!val) {
6833 	    ret = SQL_ERROR;
6834 	    break;
6835 	}
6836 	if (val == (SQLPOINTER) SQL_OV_ODBC2) {
6837 	    e->ov3 = 0;
6838 	    ret = SQL_SUCCESS;
6839 	} else if (val == (SQLPOINTER) SQL_OV_ODBC3) {
6840 	    e->ov3 = 1;
6841 	    ret = SQL_SUCCESS;
6842 	}
6843 	break;
6844     }
6845 #if defined(_WIN32) || defined(_WIN64)
6846     LeaveCriticalSection(&e->cs);
6847 #endif
6848     return ret;
6849 }
6850 
6851 /**
6852  * Internal get error message given handle (HENV, HDBC, or HSTMT).
6853  * @param htype handle type
6854  * @param handle HENV, HDBC, or HSTMT
6855  * @param recno
6856  * @param sqlstate output buffer for SQL state
6857  * @param nativeerr output buffer of native error code
6858  * @param msg output buffer for error message
6859  * @param buflen length of output buffer
6860  * @param msglen output length
6861  * @result ODBC error code
6862  */
6863 
6864 static SQLRETURN
drvgetdiagrec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)6865 drvgetdiagrec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
6866 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
6867 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
6868 {
6869     DBC *d = NULL;
6870     STMT *s = NULL;
6871     int len, naterr;
6872     char *logmsg, *sqlst;
6873     SQLRETURN ret = SQL_ERROR;
6874 
6875     if (handle == SQL_NULL_HANDLE) {
6876 	return SQL_INVALID_HANDLE;
6877     }
6878     if (sqlstate) {
6879 	sqlstate[0] = '\0';
6880     }
6881     if (msg && buflen > 0) {
6882 	msg[0] = '\0';
6883     }
6884     if (msglen) {
6885 	*msglen = 0;
6886     }
6887     if (nativeerr) {
6888 	*nativeerr = 0;
6889     }
6890     switch (htype) {
6891     case SQL_HANDLE_ENV:
6892     case SQL_HANDLE_DESC:
6893 	return SQL_NO_DATA;
6894     case SQL_HANDLE_DBC:
6895 	HDBC_LOCK((SQLHDBC) handle);
6896 	d = (DBC *) handle;
6897 	logmsg = (char *) d->logmsg;
6898 	sqlst = d->sqlstate;
6899 	naterr = d->naterr;
6900 	break;
6901     case SQL_HANDLE_STMT:
6902 	HSTMT_LOCK((SQLHSTMT) handle);
6903 	s = (STMT *) handle;
6904 	logmsg = (char *) s->logmsg;
6905 	sqlst = s->sqlstate;
6906 	naterr = s->naterr;
6907 	break;
6908     default:
6909 	return SQL_INVALID_HANDLE;
6910     }
6911     if (buflen < 0) {
6912 	ret = SQL_ERROR;
6913 	goto done;
6914     }
6915     if (recno > 1) {
6916 	ret = SQL_NO_DATA;
6917 	goto done;
6918     }
6919     len = strlen(logmsg);
6920     if (len == 0) {
6921 	ret = SQL_NO_DATA;
6922 	goto done;
6923     }
6924     if (nativeerr) {
6925 	*nativeerr = naterr;
6926     }
6927     if (sqlstate) {
6928 	strcpy((char *) sqlstate, sqlst);
6929     }
6930     if (msglen) {
6931 	*msglen = len;
6932     }
6933     if (len >= buflen) {
6934 	if (msg && buflen > 0) {
6935 	    strncpy((char *) msg, logmsg, buflen);
6936 	    msg[buflen - 1] = '\0';
6937 	    logmsg[0] = '\0';
6938 	}
6939     } else if (msg) {
6940 	strcpy((char *) msg, logmsg);
6941 	logmsg[0] = '\0';
6942     }
6943     ret = SQL_SUCCESS;
6944 done:
6945     switch (htype) {
6946     case SQL_HANDLE_DBC:
6947 	HDBC_UNLOCK((SQLHDBC) handle);
6948 	break;
6949     case SQL_HANDLE_STMT:
6950 	HSTMT_UNLOCK((SQLHSTMT) handle);
6951 	break;
6952     }
6953     return ret;
6954 }
6955 
6956 #if !defined(WINTERFACE) || (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC))
6957 /**
6958  * Get error message given handle (HENV, HDBC, or HSTMT).
6959  * @param htype handle type
6960  * @param handle HENV, HDBC, or HSTMT
6961  * @param recno
6962  * @param sqlstate output buffer for SQL state
6963  * @param nativeerr output buffer of native error code
6964  * @param msg output buffer for error message
6965  * @param buflen length of output buffer
6966  * @param msglen output length
6967  * @result ODBC error code
6968  */
6969 
6970 SQLRETURN SQL_API
SQLGetDiagRec(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLCHAR * sqlstate,SQLINTEGER * nativeerr,SQLCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)6971 SQLGetDiagRec(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
6972 	      SQLCHAR *sqlstate, SQLINTEGER *nativeerr, SQLCHAR *msg,
6973 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
6974 {
6975     return drvgetdiagrec(htype, handle, recno, sqlstate,
6976 			 nativeerr, msg, buflen, msglen);
6977 }
6978 #endif
6979 
6980 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
6981 #ifdef WINTERFACE
6982 /**
6983  * Get error message given handle (HENV, HDBC, or HSTMT)
6984  * (UNICODE version).
6985  * @param htype handle type
6986  * @param handle HENV, HDBC, or HSTMT
6987  * @param recno
6988  * @param sqlstate output buffer for SQL state
6989  * @param nativeerr output buffer of native error code
6990  * @param msg output buffer for error message
6991  * @param buflen length of output buffer
6992  * @param msglen output length
6993  * @result ODBC error code
6994  */
6995 
6996 SQLRETURN SQL_API
SQLGetDiagRecW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLWCHAR * sqlstate,SQLINTEGER * nativeerr,SQLWCHAR * msg,SQLSMALLINT buflen,SQLSMALLINT * msglen)6997 SQLGetDiagRecW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
6998 	      SQLWCHAR *sqlstate, SQLINTEGER *nativeerr, SQLWCHAR *msg,
6999 	      SQLSMALLINT buflen, SQLSMALLINT *msglen)
7000 {
7001     char state[16];
7002     SQLSMALLINT len;
7003     SQLRETURN ret;
7004 
7005     ret = drvgetdiagrec(htype, handle, recno, (SQLCHAR *) state,
7006 			nativeerr, (SQLCHAR *) msg, buflen, &len);
7007     if (ret == SQL_SUCCESS) {
7008 	if (sqlstate) {
7009 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlstate,
7010 			    6 * sizeof (SQLWCHAR));
7011 	}
7012 	if (msg) {
7013 	    if (len > 0) {
7014 		SQLWCHAR *m = NULL;
7015 
7016 		m = uc_from_utf((unsigned char *) msg, len);
7017 		if (m) {
7018 		    if (buflen) {
7019 			buflen /= sizeof (SQLWCHAR);
7020 			uc_strncpy(msg, m, buflen);
7021 			m[len] = 0;
7022 			len = min(buflen, uc_strlen(m));
7023 		    } else {
7024 			len = uc_strlen(m);
7025 		    }
7026 		    uc_free(m);
7027 		} else {
7028 		    len = 0;
7029 		}
7030 	    }
7031 	    if (len <= 0) {
7032 		len = 0;
7033 		if (buflen > 0) {
7034 		    msg[0] = 0;
7035 		}
7036 	    }
7037 	} else {
7038 	    /* estimated length !!! */
7039 	    len *= sizeof (SQLWCHAR);
7040 	}
7041 	if (msglen) {
7042 	    *msglen = len;
7043 	}
7044     } else if (ret == SQL_NO_DATA) {
7045 	if (sqlstate) {
7046 	    sqlstate[0] = 0;
7047 	}
7048 	if (msg) {
7049 	    if (buflen > 0) {
7050 		msg[0] = 0;
7051 	    }
7052 	}
7053 	if (msglen) {
7054 	    *msglen = 0;
7055 	}
7056     }
7057     return ret;
7058 }
7059 #endif
7060 #endif
7061 
7062 /**
7063  * Get error record given handle (HDBC or HSTMT).
7064  * @param htype handle type
7065  * @param handle HDBC or HSTMT
7066  * @param recno diag record number for which info to be retrieved
7067  * @param id diag id for which info to be retrieved
7068  * @param info output buffer for error message
7069  * @param buflen length of output buffer
7070  * @param stringlen output length
7071  * @result ODBC error code
7072  */
7073 
7074 static SQLRETURN
drvgetdiagfield(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)7075 drvgetdiagfield(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
7076 		SQLSMALLINT id, SQLPOINTER info,
7077 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
7078 {
7079     DBC *d = NULL;
7080     STMT *s = NULL;
7081     int len, naterr, strbuf = 1;
7082     char *logmsg, *sqlst, *clrmsg = NULL;
7083     SQLRETURN ret = SQL_ERROR;
7084 
7085     if (handle == SQL_NULL_HANDLE) {
7086 	return SQL_INVALID_HANDLE;
7087     }
7088     if (stringlen) {
7089 	*stringlen = 0;
7090     }
7091     switch (htype) {
7092     case SQL_HANDLE_ENV:
7093     case SQL_HANDLE_DESC:
7094 	return SQL_NO_DATA;
7095     case SQL_HANDLE_DBC:
7096 	HDBC_LOCK((SQLHDBC) handle);
7097 	d = (DBC *) handle;
7098 	logmsg = (char *) d->logmsg;
7099 	sqlst = d->sqlstate;
7100 	naterr = d->naterr;
7101 	break;
7102     case SQL_HANDLE_STMT:
7103 	HSTMT_LOCK((SQLHSTMT) handle);
7104 	s = (STMT *) handle;
7105 	d = (DBC *) s->dbc;
7106 	logmsg = (char *) s->logmsg;
7107 	sqlst = s->sqlstate;
7108 	naterr = s->naterr;
7109 	break;
7110     default:
7111 	return SQL_INVALID_HANDLE;
7112     }
7113     if (buflen < 0) {
7114 	switch (buflen) {
7115 	case SQL_IS_POINTER:
7116 	case SQL_IS_UINTEGER:
7117 	case SQL_IS_INTEGER:
7118 	case SQL_IS_USMALLINT:
7119 	case SQL_IS_SMALLINT:
7120 	    strbuf = 0;
7121 	    break;
7122 	default:
7123 	    ret = SQL_ERROR;
7124 	    goto done;
7125 	}
7126     }
7127     if (recno > 1) {
7128 	ret = SQL_NO_DATA;
7129 	goto done;
7130     }
7131     switch (id) {
7132     case SQL_DIAG_CLASS_ORIGIN:
7133 	logmsg = "ISO 9075";
7134 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
7135 	    logmsg = "ODBC 3.0";
7136 	}
7137 	break;
7138     case SQL_DIAG_SUBCLASS_ORIGIN:
7139 	logmsg = "ISO 9075";
7140 	if (sqlst[0] == 'I' && sqlst[1] == 'M') {
7141 	    logmsg = "ODBC 3.0";
7142 	} else if (sqlst[0] == 'H' && sqlst[1] == 'Y') {
7143 	    logmsg = "ODBC 3.0";
7144 	} else if (sqlst[0] == '2' || sqlst[0] == '0' || sqlst[0] == '4') {
7145 	    logmsg = "ODBC 3.0";
7146 	}
7147 	break;
7148     case SQL_DIAG_CONNECTION_NAME:
7149     case SQL_DIAG_SERVER_NAME:
7150 	logmsg = d->dsn ? d->dsn : "No DSN";
7151 	break;
7152     case SQL_DIAG_SQLSTATE:
7153 	logmsg = sqlst;
7154 	break;
7155     case SQL_DIAG_MESSAGE_TEXT:
7156 	if (info) {
7157 	    clrmsg = logmsg;
7158 	}
7159 	break;
7160     case SQL_DIAG_NUMBER:
7161 	naterr = 1;
7162 	/* fall through */
7163     case SQL_DIAG_NATIVE:
7164 	len = strlen(logmsg);
7165 	if (len == 0) {
7166 	    ret = SQL_NO_DATA;
7167 	    goto done;
7168 	}
7169 	if (info) {
7170 	    *((SQLINTEGER *) info) = naterr;
7171 	}
7172 	ret = SQL_SUCCESS;
7173 	goto done;
7174     case SQL_DIAG_DYNAMIC_FUNCTION:
7175 	logmsg = "";
7176 	break;
7177     case SQL_DIAG_CURSOR_ROW_COUNT:
7178 	if (htype == SQL_HANDLE_STMT) {
7179 	    SQLULEN count;
7180 
7181 	    count = (s->isselect == 1 || s->isselect == -1) ? s->nrows : 0;
7182 	    *((SQLULEN *) info) = count;
7183 	    ret = SQL_SUCCESS;
7184 	}
7185 	goto done;
7186     case SQL_DIAG_ROW_COUNT:
7187 	if (htype == SQL_HANDLE_STMT) {
7188 	    SQLULEN count;
7189 
7190 	    count = s->isselect ? 0 : s->nrows;
7191 	    *((SQLULEN *) info) = count;
7192 	    ret = SQL_SUCCESS;
7193 	}
7194 	goto done;
7195     default:
7196 	ret = SQL_ERROR;
7197 	goto done;
7198     }
7199     if (info && buflen > 0) {
7200 	((char *) info)[0] = '\0';
7201     }
7202     len = strlen(logmsg);
7203     if (len == 0) {
7204 	ret = SQL_NO_DATA;
7205 	goto done;
7206     }
7207     if (stringlen) {
7208 	*stringlen = len;
7209     }
7210     if (strbuf) {
7211 	if (len >= buflen) {
7212 	    if (info && buflen > 0) {
7213 		if (stringlen) {
7214 		    *stringlen = buflen - 1;
7215 		}
7216 		strncpy((char *) info, logmsg, buflen);
7217 		((char *) info)[buflen - 1] = '\0';
7218 	    }
7219 	} else if (info) {
7220 	    strcpy((char *) info, logmsg);
7221 	}
7222     }
7223     if (clrmsg) {
7224 	*clrmsg = '\0';
7225     }
7226     ret = SQL_SUCCESS;
7227 done:
7228     switch (htype) {
7229     case SQL_HANDLE_DBC:
7230 	HDBC_UNLOCK((SQLHDBC) handle);
7231 	break;
7232     case SQL_HANDLE_STMT:
7233 	HSTMT_UNLOCK((SQLHSTMT) handle);
7234 	break;
7235     }
7236     return ret;
7237 }
7238 
7239 #ifndef WINTERFACE
7240 /**
7241  * Get error record given handle (HDBC or HSTMT).
7242  * @param htype handle type
7243  * @param handle HDBC or HSTMT
7244  * @param recno diag record number for which info to be retrieved
7245  * @param id diag id for which info to be retrieved
7246  * @param info output buffer for error message
7247  * @param buflen length of output buffer
7248  * @param stringlen output length
7249  * @result ODBC error code
7250  */
7251 
7252 SQLRETURN SQL_API
SQLGetDiagField(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)7253 SQLGetDiagField(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
7254 		SQLSMALLINT id, SQLPOINTER info,
7255 		SQLSMALLINT buflen, SQLSMALLINT *stringlen)
7256 {
7257     return drvgetdiagfield(htype, handle, recno, id, info, buflen, stringlen);
7258 }
7259 #endif
7260 
7261 #ifdef WINTERFACE
7262 /**
7263  * Get error record given handle (HDBC or HSTMT).
7264  * @param htype handle type
7265  * @param handle HDBC or HSTMT
7266  * @param recno diag record number for which info to be retrieved
7267  * @param id diag id for which info to be retrieved
7268  * @param info output buffer for error message
7269  * @param buflen length of output buffer
7270  * @param stringlen output length
7271  * @result ODBC error code
7272  */
7273 
7274 SQLRETURN SQL_API
SQLGetDiagFieldW(SQLSMALLINT htype,SQLHANDLE handle,SQLSMALLINT recno,SQLSMALLINT id,SQLPOINTER info,SQLSMALLINT buflen,SQLSMALLINT * stringlen)7275 SQLGetDiagFieldW(SQLSMALLINT htype, SQLHANDLE handle, SQLSMALLINT recno,
7276 		 SQLSMALLINT id, SQLPOINTER info,
7277 		 SQLSMALLINT buflen, SQLSMALLINT *stringlen)
7278 {
7279     SQLSMALLINT len;
7280     SQLRETURN ret;
7281 
7282     ret = drvgetdiagfield(htype, handle, recno, id, info, buflen, &len);
7283     if (ret == SQL_SUCCESS) {
7284 	if (info) {
7285 	    switch (id) {
7286 	    case SQL_DIAG_CLASS_ORIGIN:
7287 	    case SQL_DIAG_SUBCLASS_ORIGIN:
7288 	    case SQL_DIAG_CONNECTION_NAME:
7289 	    case SQL_DIAG_SERVER_NAME:
7290 	    case SQL_DIAG_SQLSTATE:
7291 	    case SQL_DIAG_MESSAGE_TEXT:
7292 	    case SQL_DIAG_DYNAMIC_FUNCTION:
7293 		if (len > 0) {
7294 		    SQLWCHAR *m = NULL;
7295 
7296 		    m = uc_from_utf((unsigned char *) info, len);
7297 		    if (m) {
7298 			if (buflen) {
7299 			    buflen /= sizeof (SQLWCHAR);
7300 			    uc_strncpy(info, m, buflen);
7301 			    m[len] = 0;
7302 			    len = min(buflen, uc_strlen(m));
7303 			} else {
7304 			    len = uc_strlen(m);
7305 			}
7306 			uc_free(m);
7307 			len *= sizeof (SQLWCHAR);
7308 		    } else {
7309 			len = 0;
7310 		    }
7311 		}
7312 		if (len <= 0) {
7313 		    len = 0;
7314 		    if (buflen > 0) {
7315 			((SQLWCHAR *) info)[0] = 0;
7316 		    }
7317 		}
7318 	    }
7319 	} else {
7320 	    switch (id) {
7321 	    case SQL_DIAG_CLASS_ORIGIN:
7322 	    case SQL_DIAG_SUBCLASS_ORIGIN:
7323 	    case SQL_DIAG_CONNECTION_NAME:
7324 	    case SQL_DIAG_SERVER_NAME:
7325 	    case SQL_DIAG_SQLSTATE:
7326 	    case SQL_DIAG_MESSAGE_TEXT:
7327 	    case SQL_DIAG_DYNAMIC_FUNCTION:
7328 		len *= sizeof (SQLWCHAR);
7329 		break;
7330 	    }
7331 	}
7332 	if (stringlen) {
7333 	    *stringlen = len;
7334 	}
7335     }
7336     return ret;
7337 }
7338 #endif
7339 
7340 /**
7341  * Internal get option of HSTMT.
7342  * @param stmt statement handle
7343  * @param attr attribute to be retrieved
7344  * @param val output buffer
7345  * @param bufmax length of output buffer
7346  * @param buflen output length
7347  * @result ODBC error code
7348  */
7349 
7350 static SQLRETURN
drvgetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)7351 drvgetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
7352 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
7353 {
7354     STMT *s = (STMT *) stmt;
7355     DBC *d = (DBC *) s->dbc;
7356     SQLUINTEGER *uval = (SQLUINTEGER *) val;
7357     SQLINTEGER dummy;
7358     char dummybuf[16];
7359 
7360     if (!buflen) {
7361 	buflen = &dummy;
7362     }
7363     if (!uval) {
7364 	uval = (SQLPOINTER) dummybuf;
7365     }
7366     switch (attr) {
7367     case SQL_QUERY_TIMEOUT:
7368 	*uval = 0;
7369 	*buflen = sizeof (SQLUINTEGER);
7370 	return SQL_SUCCESS;
7371     case SQL_ATTR_CURSOR_TYPE:
7372 	*uval = s->curtype;
7373 	*buflen = sizeof (SQLUINTEGER);
7374 	return SQL_SUCCESS;
7375     case SQL_ATTR_CURSOR_SCROLLABLE:
7376 	*uval = (s->curtype != SQL_CURSOR_FORWARD_ONLY) ?
7377 	    SQL_SCROLLABLE : SQL_NONSCROLLABLE;
7378 	*buflen = sizeof (SQLUINTEGER);
7379 	return SQL_SUCCESS;
7380 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
7381     case SQL_ATTR_CURSOR_SENSITIVITY:
7382 	*uval = SQL_UNSPECIFIED;
7383 	*buflen = sizeof (SQLUINTEGER);
7384 	return SQL_SUCCESS;
7385 #endif
7386     case SQL_ATTR_ROW_NUMBER:
7387 	if (s == d->vm_stmt) {
7388 	    *uval = (d->vm_rownum < 0) ?
7389 		    SQL_ROW_NUMBER_UNKNOWN : (d->vm_rownum + 1);
7390 	} else {
7391 	    *uval = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
7392 	}
7393 	*buflen = sizeof (SQLUINTEGER);
7394 	return SQL_SUCCESS;
7395     case SQL_ATTR_ASYNC_ENABLE:
7396 	*uval = SQL_ASYNC_ENABLE_OFF;
7397 	*buflen = sizeof (SQLUINTEGER);
7398 	return SQL_SUCCESS;
7399     case SQL_CONCURRENCY:
7400 	*uval = SQL_CONCUR_LOCK;
7401 	*buflen = sizeof (SQLUINTEGER);
7402 	return SQL_SUCCESS;
7403     case SQL_ATTR_RETRIEVE_DATA:
7404 	*uval = s->retr_data;
7405 	*buflen = sizeof (SQLUINTEGER);
7406 	return SQL_SUCCESS;
7407     case SQL_ROWSET_SIZE:
7408     case SQL_ATTR_ROW_ARRAY_SIZE:
7409 	*uval = s->rowset_size;
7410 	*buflen = sizeof (SQLUINTEGER);
7411 	return SQL_SUCCESS;
7412     /* Needed for some driver managers, but dummies for now */
7413     case SQL_ATTR_IMP_ROW_DESC:
7414     case SQL_ATTR_APP_ROW_DESC:
7415     case SQL_ATTR_IMP_PARAM_DESC:
7416     case SQL_ATTR_APP_PARAM_DESC:
7417 	*((SQLHDESC *) uval) = (SQLHDESC) DEAD_MAGIC;
7418 	*buflen = sizeof (SQLHDESC);
7419 	return SQL_SUCCESS;
7420     case SQL_ATTR_ROW_STATUS_PTR:
7421 	*((SQLUSMALLINT **) uval) = s->row_status;
7422 	*buflen = sizeof (SQLUSMALLINT *);
7423 	return SQL_SUCCESS;
7424     case SQL_ATTR_ROWS_FETCHED_PTR:
7425 	*((SQLULEN **) uval) = s->row_count;
7426 	*buflen = sizeof (SQLULEN *);
7427 	return SQL_SUCCESS;
7428     case SQL_ATTR_USE_BOOKMARKS: {
7429 	STMT *s = (STMT *) stmt;
7430 
7431 	*(SQLUINTEGER *) uval = s->bkmrk ? SQL_UB_ON : SQL_UB_OFF;
7432 	*buflen = sizeof (SQLUINTEGER);
7433 	return SQL_SUCCESS;
7434     }
7435     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
7436 	*((SQLULEN **) uval) = s->parm_bind_offs;
7437 	*buflen = sizeof (SQLULEN *);
7438 	return SQL_SUCCESS;
7439     case SQL_ATTR_PARAM_BIND_TYPE:
7440 	*((SQLUINTEGER *) uval) = SQL_PARAM_BIND_BY_COLUMN;
7441 	*buflen = sizeof (SQLUINTEGER);
7442 	return SQL_SUCCESS;
7443     case SQL_ATTR_PARAM_OPERATION_PTR:
7444 	*((SQLUSMALLINT **) uval) = s->parm_oper;
7445 	*buflen = sizeof (SQLUSMALLINT *);
7446 	return SQL_SUCCESS;
7447     case SQL_ATTR_PARAM_STATUS_PTR:
7448 	*((SQLUSMALLINT **) uval) = s->parm_status;
7449 	*buflen = sizeof (SQLUSMALLINT *);
7450 	return SQL_SUCCESS;
7451     case SQL_ATTR_PARAMS_PROCESSED_PTR:
7452 	*((SQLULEN **) uval) = s->parm_proc;
7453 	*buflen = sizeof (SQLULEN *);
7454 	return SQL_SUCCESS;
7455     case SQL_ATTR_PARAMSET_SIZE:
7456 	*((SQLUINTEGER *) uval) = s->paramset_size;
7457 	*buflen = sizeof (SQLUINTEGER);
7458 	return SQL_SUCCESS;
7459     case SQL_ATTR_ROW_BIND_TYPE:
7460 	*(SQLUINTEGER *) uval = s->bind_type;
7461 	*buflen = sizeof (SQLUINTEGER);
7462 	return SQL_SUCCESS;
7463     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
7464 	*((SQLULEN **) uval) = s->bind_offs;
7465 	*buflen = sizeof (SQLULEN *);
7466 	return SQL_SUCCESS;
7467     case SQL_ATTR_NOSCAN:
7468 	*((SQLUINTEGER **) uval) = SQL_NOSCAN_OFF;
7469 	*buflen = sizeof (SQLUINTEGER *);
7470 	return SQL_SUCCESS;
7471     case SQL_ATTR_MAX_ROWS:
7472 	*((SQLULEN *) uval) = 1000000000;
7473 	*buflen = sizeof (SQLULEN);
7474 	return SQL_SUCCESS;
7475     case SQL_ATTR_MAX_LENGTH:
7476 	*((SQLULEN *) uval) = 1000000000;
7477 	*buflen = sizeof (SQLULEN);
7478 	return SQL_SUCCESS;
7479     }
7480     return drvunimplstmt(stmt);
7481 }
7482 
7483 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
7484 /**
7485  * Get option of HSTMT.
7486  * @param stmt statement handle
7487  * @param attr attribute to be retrieved
7488  * @param val output buffer
7489  * @param bufmax length of output buffer
7490  * @param buflen output length
7491  * @result ODBC error code
7492  */
7493 
7494 SQLRETURN SQL_API
SQLGetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)7495 SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
7496 	       SQLINTEGER bufmax, SQLINTEGER *buflen)
7497 {
7498     SQLRETURN ret;
7499 
7500     HSTMT_LOCK(stmt);
7501     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
7502     HSTMT_UNLOCK(stmt);
7503     return ret;
7504 }
7505 #endif
7506 
7507 #ifdef WINTERFACE
7508 /**
7509  * Get option of HSTMT (UNICODE version).
7510  * @param stmt statement handle
7511  * @param attr attribute to be retrieved
7512  * @param val output buffer
7513  * @param bufmax length of output buffer
7514  * @param buflen output length
7515  * @result ODBC error code
7516  */
7517 
7518 SQLRETURN SQL_API
SQLGetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)7519 SQLGetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
7520 		SQLINTEGER bufmax, SQLINTEGER *buflen)
7521 {
7522     SQLRETURN ret;
7523 
7524     HSTMT_LOCK(stmt);
7525     ret = drvgetstmtattr(stmt, attr, val, bufmax, buflen);
7526     HSTMT_UNLOCK(stmt);
7527     return ret;
7528 }
7529 #endif
7530 
7531 /**
7532  * Internal set option on HSTMT.
7533  * @param stmt statement handle
7534  * @param attr attribute to be set
7535  * @param val input buffer (attribute value)
7536  * @param buflen length of input buffer
7537  * @result ODBC error code
7538  */
7539 
7540 static SQLRETURN
drvsetstmtattr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)7541 drvsetstmtattr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
7542 	       SQLINTEGER buflen)
7543 {
7544     STMT *s = (STMT *) stmt;
7545 #if defined(SQL_BIGINT) && defined(__WORDSIZE) && (__WORDSIZE == 64)
7546     SQLBIGINT uval;
7547 
7548     uval = (SQLBIGINT) val;
7549 #else
7550     SQLULEN uval;
7551 
7552     uval = (SQLULEN) val;
7553 #endif
7554     switch (attr) {
7555     case SQL_ATTR_CURSOR_TYPE:
7556 	if (val == (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY) {
7557 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
7558 	} else {
7559 	    s->curtype = SQL_CURSOR_STATIC;
7560 	}
7561 	if (val != (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY &&
7562 	    val != (SQLPOINTER) SQL_CURSOR_STATIC) {
7563 	    goto e01s02;
7564 	}
7565 	return SQL_SUCCESS;
7566     case SQL_ATTR_CURSOR_SCROLLABLE:
7567 	if (val == (SQLPOINTER) SQL_NONSCROLLABLE) {
7568 	    s->curtype = SQL_CURSOR_FORWARD_ONLY;
7569 	} else {
7570 	    s->curtype = SQL_CURSOR_STATIC;
7571 	}
7572 	return SQL_SUCCESS;
7573     case SQL_ATTR_ASYNC_ENABLE:
7574 	if (val != (SQLPOINTER) SQL_ASYNC_ENABLE_OFF) {
7575     e01s02:
7576 	    setstat(s, -1, "option value changed", "01S02");
7577 	    return SQL_SUCCESS_WITH_INFO;
7578 	}
7579 	return SQL_SUCCESS;
7580     case SQL_CONCURRENCY:
7581 	if (val != (SQLPOINTER) SQL_CONCUR_LOCK) {
7582 	    goto e01s02;
7583 	}
7584 	return SQL_SUCCESS;
7585 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
7586     case SQL_ATTR_CURSOR_SENSITIVITY:
7587 	if (val != (SQLPOINTER) SQL_UNSPECIFIED) {
7588 	    goto e01s02;
7589 	}
7590 	return SQL_SUCCESS;
7591 #endif
7592     case SQL_ATTR_QUERY_TIMEOUT:
7593 	return SQL_SUCCESS;
7594     case SQL_ATTR_RETRIEVE_DATA:
7595 	if (val != (SQLPOINTER) SQL_RD_ON &&
7596 	    val != (SQLPOINTER) SQL_RD_OFF) {
7597 	    goto e01s02;
7598 	}
7599 	s->retr_data = uval;
7600 	return SQL_SUCCESS;
7601     case SQL_ROWSET_SIZE:
7602     case SQL_ATTR_ROW_ARRAY_SIZE:
7603 	if (uval < 1) {
7604 	    setstat(s, -1, "invalid rowset size", "HY000");
7605 	    return SQL_ERROR;
7606 	} else {
7607 	    SQLUSMALLINT *rst = &s->row_status1;
7608 
7609 	    if (uval > 1) {
7610 		rst = xmalloc(sizeof (SQLUSMALLINT) * uval);
7611 		if (!rst) {
7612 		    return nomem(s);
7613 		}
7614 	    }
7615 	    if (s->row_status0 != &s->row_status1) {
7616 		freep(&s->row_status0);
7617 	    }
7618 	    s->row_status0 = rst;
7619 	    s->rowset_size = uval;
7620 	}
7621 	return SQL_SUCCESS;
7622     case SQL_ATTR_ROW_STATUS_PTR:
7623 	s->row_status = (SQLUSMALLINT *) val;
7624 	return SQL_SUCCESS;
7625     case SQL_ATTR_ROWS_FETCHED_PTR:
7626 	s->row_count = (SQLULEN *) val;
7627 	return SQL_SUCCESS;
7628     case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
7629 	s->parm_bind_offs = (SQLULEN *) val;
7630 	return SQL_SUCCESS;
7631     case SQL_ATTR_PARAM_BIND_TYPE:
7632 	s->parm_bind_type = uval;
7633 	return SQL_SUCCESS;
7634     case SQL_ATTR_PARAM_OPERATION_PTR:
7635 	s->parm_oper = (SQLUSMALLINT *) val;
7636 	return SQL_SUCCESS;
7637     case SQL_ATTR_PARAM_STATUS_PTR:
7638 	s->parm_status = (SQLUSMALLINT *) val;
7639 	return SQL_SUCCESS;
7640     case SQL_ATTR_PARAMS_PROCESSED_PTR:
7641 	s->parm_proc = (SQLULEN *) val;
7642 	return SQL_SUCCESS;
7643     case SQL_ATTR_PARAMSET_SIZE:
7644 	if ((PTRDIFF_T) val < 1) {
7645 	    goto e01s02;
7646 	}
7647 	s->paramset_size = uval;
7648 	s->paramset_count = 0;
7649 	return SQL_SUCCESS;
7650     case SQL_ATTR_ROW_BIND_TYPE:
7651 	s->bind_type = uval;
7652 	return SQL_SUCCESS;
7653     case SQL_ATTR_ROW_BIND_OFFSET_PTR:
7654 	s->bind_offs = (SQLULEN *) val;
7655 	return SQL_SUCCESS;
7656     case SQL_ATTR_USE_BOOKMARKS:
7657 	if (val != (SQLPOINTER) SQL_UB_OFF &&
7658 	    val != (SQLPOINTER) SQL_UB_ON) {
7659 	    goto e01s02;
7660 	}
7661 	s->bkmrk = val == (SQLPOINTER) SQL_UB_ON;
7662 	return SQL_SUCCESS;
7663     case SQL_ATTR_NOSCAN:
7664 	if (val != (SQLPOINTER) SQL_NOSCAN_OFF) {
7665 	    goto e01s02;
7666 	}
7667 	return SQL_SUCCESS;
7668     case SQL_ATTR_MAX_ROWS:
7669     case SQL_ATTR_MAX_LENGTH:
7670 	if (val != (SQLPOINTER) 1000000000) {
7671 	    goto e01s02;
7672 	}
7673 	return SQL_SUCCESS;
7674     }
7675     return drvunimplstmt(stmt);
7676 }
7677 
7678 #if (defined(HAVE_UNIXODBC) && HAVE_UNIXODBC) || !defined(WINTERFACE)
7679 /**
7680  * Set option on HSTMT.
7681  * @param stmt statement handle
7682  * @param attr attribute to be set
7683  * @param val input buffer (attribute value)
7684  * @param buflen length of input buffer
7685  * @result ODBC error code
7686  */
7687 
7688 SQLRETURN SQL_API
SQLSetStmtAttr(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)7689 SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
7690 	       SQLINTEGER buflen)
7691 {
7692     SQLRETURN ret;
7693 
7694     HSTMT_LOCK(stmt);
7695     ret = drvsetstmtattr(stmt, attr, val, buflen);
7696     HSTMT_UNLOCK(stmt);
7697     return ret;
7698 }
7699 #endif
7700 
7701 #ifdef WINTERFACE
7702 /**
7703  * Set option on HSTMT (UNICODE version).
7704  * @param stmt statement handle
7705  * @param attr attribute to be set
7706  * @param val input buffer (attribute value)
7707  * @param buflen length of input buffer
7708  * @result ODBC error code
7709  */
7710 
7711 SQLRETURN SQL_API
SQLSetStmtAttrW(SQLHSTMT stmt,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER buflen)7712 SQLSetStmtAttrW(SQLHSTMT stmt, SQLINTEGER attr, SQLPOINTER val,
7713 		SQLINTEGER buflen)
7714 {
7715     SQLRETURN ret;
7716 
7717     HSTMT_LOCK(stmt);
7718     ret = drvsetstmtattr(stmt, attr, val, buflen);
7719     HSTMT_UNLOCK(stmt);
7720     return ret;
7721 }
7722 #endif
7723 
7724 /**
7725  * Internal get option of HSTMT.
7726  * @param stmt statement handle
7727  * @param opt option to be retrieved
7728  * @param param output buffer
7729  * @result ODBC error code
7730  */
7731 
7732 static SQLRETURN
drvgetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)7733 drvgetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
7734 {
7735     STMT *s = (STMT *) stmt;
7736     DBC *d = (DBC *) s->dbc;
7737     SQLUINTEGER *ret = (SQLUINTEGER *) param;
7738 
7739     switch (opt) {
7740     case SQL_QUERY_TIMEOUT:
7741 	*ret = 0;
7742 	return SQL_SUCCESS;
7743     case SQL_CURSOR_TYPE:
7744 	*ret = s->curtype;
7745 	return SQL_SUCCESS;
7746     case SQL_ROW_NUMBER:
7747 	if (s == d->vm_stmt) {
7748 	    *ret = (d->vm_rownum < 0) ?
7749 		   SQL_ROW_NUMBER_UNKNOWN : (d->vm_rownum + 1);
7750 	} else {
7751 	    *ret = (s->rowp < 0) ? SQL_ROW_NUMBER_UNKNOWN : (s->rowp + 1);
7752 	}
7753 	return SQL_SUCCESS;
7754     case SQL_ASYNC_ENABLE:
7755 	*ret = SQL_ASYNC_ENABLE_OFF;
7756 	return SQL_SUCCESS;
7757     case SQL_CONCURRENCY:
7758 	*ret = SQL_CONCUR_LOCK;
7759 	return SQL_SUCCESS;
7760     case SQL_ATTR_RETRIEVE_DATA:
7761 	*ret = s->retr_data;
7762 	return SQL_SUCCESS;
7763     case SQL_ROWSET_SIZE:
7764     case SQL_ATTR_ROW_ARRAY_SIZE:
7765 	*ret = s->rowset_size;
7766 	return SQL_SUCCESS;
7767     case SQL_ATTR_NOSCAN:
7768 	*ret = SQL_NOSCAN_OFF;
7769 	return SQL_SUCCESS;
7770     case SQL_ATTR_MAX_ROWS:
7771     case SQL_ATTR_MAX_LENGTH:
7772 	*ret = 1000000000;
7773 	return SQL_SUCCESS;
7774     }
7775     return drvunimplstmt(stmt);
7776 }
7777 
7778 /**
7779  * Get option of HSTMT.
7780  * @param stmt statement handle
7781  * @param opt option to be retrieved
7782  * @param param output buffer
7783  * @result ODBC error code
7784  */
7785 
7786 SQLRETURN SQL_API
SQLGetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)7787 SQLGetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
7788 {
7789     SQLRETURN ret;
7790 
7791     HSTMT_LOCK(stmt);
7792     ret = drvgetstmtoption(stmt, opt, param);
7793     HSTMT_UNLOCK(stmt);
7794     return ret;
7795 }
7796 
7797 #ifdef WINTERFACE
7798 /**
7799  * Get option of HSTMT (UNICODE version).
7800  * @param stmt statement handle
7801  * @param opt option to be retrieved
7802  * @param param output buffer
7803  * @result ODBC error code
7804  */
7805 
7806 SQLRETURN SQL_API
SQLGetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SQLPOINTER param)7807 SQLGetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt, SQLPOINTER param)
7808 {
7809     SQLRETURN ret;
7810 
7811     HSTMT_LOCK(stmt);
7812     ret = drvgetstmtoption(stmt, opt, param);
7813     HSTMT_UNLOCK(stmt);
7814     return ret;
7815 }
7816 #endif
7817 
7818 /**
7819  * Internal set option on HSTMT.
7820  * @param stmt statement handle
7821  * @param opt option to be set
7822  * @param param input buffer (option value)
7823  * @result ODBC error code
7824  */
7825 
7826 static SQLRETURN
drvsetstmtoption(SQLHSTMT stmt,SQLUSMALLINT opt,SQLUINTEGER param)7827 drvsetstmtoption(SQLHSTMT stmt, SQLUSMALLINT opt, SQLUINTEGER param)
7828 {
7829     STMT *s = (STMT *) stmt;
7830 
7831     switch (opt) {
7832     case SQL_CURSOR_TYPE:
7833 	if (param == SQL_CURSOR_FORWARD_ONLY) {
7834 	    s->curtype = param;
7835 	} else {
7836 	    s->curtype = SQL_CURSOR_STATIC;
7837 	}
7838 	if (param != SQL_CURSOR_FORWARD_ONLY &&
7839 	    param != SQL_CURSOR_STATIC) {
7840 	    goto e01s02;
7841 	}
7842 	return SQL_SUCCESS;
7843     case SQL_ASYNC_ENABLE:
7844 	if (param != SQL_ASYNC_ENABLE_OFF) {
7845 	    goto e01s02;
7846 	}
7847 	return SQL_SUCCESS;
7848     case SQL_CONCURRENCY:
7849 	if (param != SQL_CONCUR_LOCK) {
7850 	    goto e01s02;
7851 	}
7852 	return SQL_SUCCESS;
7853     case SQL_QUERY_TIMEOUT:
7854 	return SQL_SUCCESS;
7855     case SQL_RETRIEVE_DATA:
7856 	if (param != SQL_RD_ON && param != SQL_RD_OFF) {
7857     e01s02:
7858 	    setstat(s, -1, "option value changed", "01S02");
7859 	    return SQL_SUCCESS_WITH_INFO;
7860 	}
7861 	s->retr_data = (int) param;
7862 	return SQL_SUCCESS;
7863     case SQL_ROWSET_SIZE:
7864     case SQL_ATTR_ROW_ARRAY_SIZE:
7865 	if (param < 1) {
7866 	    setstat(s, -1, "invalid rowset size", "HY000");
7867 	    return SQL_ERROR;
7868 	} else {
7869 	    SQLUSMALLINT *rst = &s->row_status1;
7870 
7871 	    if (param > 1) {
7872 		rst = xmalloc(sizeof (SQLUSMALLINT) * param);
7873 		if (!rst) {
7874 		    return nomem(s);
7875 		}
7876 	    }
7877 	    if (s->row_status0 != &s->row_status1) {
7878 		freep(&s->row_status0);
7879 	    }
7880 	    s->row_status0 = rst;
7881 	    s->rowset_size = param;
7882 	}
7883 	return SQL_SUCCESS;
7884     case SQL_ATTR_NOSCAN:
7885 	if (param != SQL_NOSCAN_OFF) {
7886 	    goto e01s02;
7887 	}
7888 	return SQL_SUCCESS;
7889     case SQL_ATTR_MAX_ROWS:
7890     case SQL_ATTR_MAX_LENGTH:
7891 	if (param != 1000000000) {
7892 	    goto e01s02;
7893 	}
7894 	return SQL_SUCCESS;
7895     }
7896     return drvunimplstmt(stmt);
7897 }
7898 
7899 /**
7900  * Set option on HSTMT.
7901  * @param stmt statement handle
7902  * @param opt option to be set
7903  * @param param input buffer (option value)
7904  * @result ODBC error code
7905  */
7906 
7907 SQLRETURN SQL_API
SQLSetStmtOption(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)7908 SQLSetStmtOption(SQLHSTMT stmt, SQLUSMALLINT opt,
7909 		 SETSTMTOPTION_LAST_ARG_TYPE param)
7910 {
7911     SQLRETURN ret;
7912 
7913     HSTMT_LOCK(stmt);
7914     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
7915     HSTMT_UNLOCK(stmt);
7916     return ret;
7917 }
7918 
7919 #ifdef WINTERFACE
7920 /**
7921  * Set option on HSTMT (UNICODE version).
7922  * @param stmt statement handle
7923  * @param opt option to be set
7924  * @param param input buffer (option value)
7925  * @result ODBC error code
7926  */
7927 
7928 SQLRETURN SQL_API
SQLSetStmtOptionW(SQLHSTMT stmt,SQLUSMALLINT opt,SETSTMTOPTION_LAST_ARG_TYPE param)7929 SQLSetStmtOptionW(SQLHSTMT stmt, SQLUSMALLINT opt,
7930 		  SETSTMTOPTION_LAST_ARG_TYPE param)
7931 {
7932     SQLRETURN ret;
7933 
7934     HSTMT_LOCK(stmt);
7935     ret = drvsetstmtoption(stmt, opt, (SQLUINTEGER) param);
7936     HSTMT_UNLOCK(stmt);
7937     return ret;
7938 }
7939 #endif
7940 
7941 /*
7942  * Internal set position on result in HSTMT.
7943  * @param stmt statement handle
7944  * @param row row to be positioned
7945  * @param op operation code
7946  * @param lock locking type
7947  * @result ODBC error code
7948  */
7949 
7950 static SQLRETURN
drvsetpos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)7951 drvsetpos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
7952 {
7953     STMT *s = (STMT *) stmt;
7954     int rowp;
7955 
7956     if (op != SQL_POSITION) {
7957 	return drvunimplstmt(stmt);
7958     }
7959     rowp = s->rowp + row - 1;
7960     if (!s->rows || row <= 0 || rowp < -1 || rowp >= s->nrows) {
7961 	setstat(s, -1, "row out of range", (*s->ov3) ? "HY107" : "S1107");
7962 	return SQL_ERROR;
7963     }
7964     s->rowp = rowp;
7965     return SQL_SUCCESS;
7966 }
7967 
7968 /**
7969  * Set position on result in HSTMT.
7970  * @param stmt statement handle
7971  * @param row row to be positioned
7972  * @param op operation code
7973  * @param lock locking type
7974  * @result ODBC error code
7975  */
7976 
7977 SQLRETURN SQL_API
SQLSetPos(SQLHSTMT stmt,SQLSETPOSIROW row,SQLUSMALLINT op,SQLUSMALLINT lock)7978 SQLSetPos(SQLHSTMT stmt, SQLSETPOSIROW row, SQLUSMALLINT op, SQLUSMALLINT lock)
7979 {
7980     SQLRETURN ret;
7981 
7982     HSTMT_LOCK(stmt);
7983     ret = drvsetpos(stmt, row, op, lock);
7984     HSTMT_UNLOCK(stmt);
7985     return ret;
7986 }
7987 
7988 /**
7989  * Function not implemented.
7990  */
7991 
7992 SQLRETURN SQL_API
SQLSetScrollOptions(SQLHSTMT stmt,SQLUSMALLINT concur,SQLLEN rowkeyset,SQLUSMALLINT rowset)7993 SQLSetScrollOptions(SQLHSTMT stmt, SQLUSMALLINT concur, SQLLEN rowkeyset,
7994 		    SQLUSMALLINT rowset)
7995 {
7996     SQLRETURN ret;
7997 
7998     HSTMT_LOCK(stmt);
7999     ret = drvunimplstmt(stmt);
8000     HSTMT_UNLOCK(stmt);
8001     return ret;
8002 }
8003 
8004 #define strmak(dst, src, max, lenp) { \
8005     int len = strlen(src); \
8006     int cnt = min(len + 1, max); \
8007     strncpy(dst, src, cnt); \
8008     *lenp = (cnt > len) ? len : cnt; \
8009 }
8010 
8011 /**
8012  * Internal return information about what this ODBC driver supports.
8013  * @param dbc database connection handle
8014  * @param type type of information to be retrieved
8015  * @param val output buffer
8016  * @param valMax length of output buffer
8017  * @param valLen output length
8018  * @result ODBC error code
8019  */
8020 
8021 static SQLRETURN
drvgetinfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)8022 drvgetinfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
8023 	   SQLSMALLINT *valLen)
8024 {
8025     DBC *d;
8026     char dummyc[16];
8027     SQLSMALLINT dummy;
8028 #if defined(_WIN32) || defined(_WIN64)
8029     char pathbuf[301], *drvname;
8030 #else
8031     static char drvname[] =
8032 #ifdef __OS2__
8033 	"SQLLODBC.DLL";
8034 #else
8035 	"sqliteodbc.so";
8036 #endif
8037 #endif
8038 
8039     if (dbc == SQL_NULL_HDBC) {
8040 	return SQL_INVALID_HANDLE;
8041     }
8042     d = (DBC *) dbc;
8043     if (valMax) {
8044 	valMax--;
8045     }
8046     if (!valLen) {
8047 	valLen = &dummy;
8048     }
8049     if (!val) {
8050 	val = dummyc;
8051 	valMax = sizeof (dummyc) - 1;
8052     }
8053     switch (type) {
8054     case SQL_MAX_USER_NAME_LEN:
8055 	*((SQLSMALLINT *) val) = 16;
8056 	*valLen = sizeof (SQLSMALLINT);
8057 	break;
8058     case SQL_USER_NAME:
8059 	strmak(val, "", valMax, valLen);
8060 	break;
8061     case SQL_DRIVER_ODBC_VER:
8062 #if 0
8063 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
8064 #else
8065 	strmak(val, "03.00", valMax, valLen);
8066 #endif
8067 	break;
8068     case SQL_ACTIVE_CONNECTIONS:
8069     case SQL_ACTIVE_STATEMENTS:
8070 	*((SQLSMALLINT *) val) = 0;
8071 	*valLen = sizeof (SQLSMALLINT);
8072 	break;
8073 #ifdef SQL_ASYNC_MODE
8074     case SQL_ASYNC_MODE:
8075 	*((SQLUINTEGER *) val) = SQL_AM_NONE;
8076 	*valLen = sizeof (SQLUINTEGER);
8077 	break;
8078 #endif
8079 #ifdef SQL_CREATE_TABLE
8080     case SQL_CREATE_TABLE:
8081 	*((SQLUINTEGER *) val) = SQL_CT_CREATE_TABLE |
8082 				 SQL_CT_COLUMN_DEFAULT |
8083 				 SQL_CT_COLUMN_CONSTRAINT |
8084 				 SQL_CT_CONSTRAINT_NON_DEFERRABLE;
8085 	*valLen = sizeof (SQLUINTEGER);
8086 	break;
8087 #endif
8088 #ifdef SQL_CREATE_VIEW
8089     case SQL_CREATE_VIEW:
8090 	*((SQLUINTEGER *) val) = SQL_CV_CREATE_VIEW;
8091 	*valLen = sizeof (SQLUINTEGER);
8092 	break;
8093 #endif
8094 #ifdef SQL_DDL_INDEX
8095     case SQL_DDL_INDEX:
8096 	*((SQLUINTEGER *) val) = SQL_DI_CREATE_INDEX | SQL_DI_DROP_INDEX;
8097 	*valLen = sizeof (SQLUINTEGER);
8098 	break;
8099 #endif
8100 #ifdef SQL_DROP_TABLE
8101     case SQL_DROP_TABLE:
8102 	*((SQLUINTEGER *) val) = SQL_DT_DROP_TABLE;
8103 	*valLen = sizeof (SQLUINTEGER);
8104 	break;
8105 #endif
8106 #ifdef SQL_DROP_VIEW
8107     case SQL_DROP_VIEW:
8108 	*((SQLUINTEGER *) val) = SQL_DV_DROP_VIEW;
8109 	*valLen = sizeof (SQLUINTEGER);
8110 	break;
8111 #endif
8112 #ifdef SQL_INDEX_KEYWORDS
8113     case SQL_INDEX_KEYWORDS:
8114 	*((SQLUINTEGER *) val) = SQL_IK_ALL;
8115 	*valLen = sizeof (SQLUINTEGER);
8116 	break;
8117 #endif
8118     case SQL_DATA_SOURCE_NAME:
8119 	strmak(val, d->dsn ? d->dsn : "", valMax, valLen);
8120 	break;
8121     case SQL_DRIVER_NAME:
8122 #if defined(_WIN32) || defined(_WIN64)
8123 	GetModuleFileName(hModule, pathbuf, sizeof (pathbuf));
8124 	drvname = strrchr(pathbuf, '\\');
8125 	if (drvname == NULL) {
8126 	    drvname = strrchr(pathbuf, '/');
8127 	}
8128 	if (drvname == NULL) {
8129 	    drvname = pathbuf;
8130 	} else {
8131 	    drvname++;
8132 	}
8133 #endif
8134 	strmak(val, drvname, valMax, valLen);
8135 	break;
8136     case SQL_DRIVER_VER:
8137 	strmak(val, DRIVER_VER_INFO, valMax, valLen);
8138 	break;
8139     case SQL_FETCH_DIRECTION:
8140 	*((SQLUINTEGER *) val) = SQL_FD_FETCH_NEXT | SQL_FD_FETCH_FIRST |
8141 	    SQL_FD_FETCH_LAST | SQL_FD_FETCH_PRIOR | SQL_FD_FETCH_ABSOLUTE;
8142 	*valLen = sizeof (SQLUINTEGER);
8143 	break;
8144     case SQL_ODBC_VER:
8145 	strmak(val, (*d->ov3) ? "03.00" : "02.50", valMax, valLen);
8146 	break;
8147     case SQL_ODBC_SAG_CLI_CONFORMANCE:
8148 	*((SQLSMALLINT *) val) = SQL_OSCC_NOT_COMPLIANT;
8149 	*valLen = sizeof (SQLSMALLINT);
8150 	break;
8151     case SQL_STANDARD_CLI_CONFORMANCE:
8152 	*((SQLUINTEGER *) val) = SQL_SCC_XOPEN_CLI_VERSION1;
8153 	*valLen = sizeof (SQLUINTEGER);
8154 	break;
8155     case SQL_SQL_CONFORMANCE:
8156 	*((SQLUINTEGER *) val) = SQL_SC_SQL92_ENTRY;
8157 	*valLen = sizeof (SQLUINTEGER);
8158 	break;
8159     case SQL_SERVER_NAME:
8160     case SQL_DATABASE_NAME:
8161 	strmak(val, d->dbname ? d->dbname : "", valMax, valLen);
8162 	break;
8163     case SQL_SEARCH_PATTERN_ESCAPE:
8164 	strmak(val, "\\", valMax, valLen);
8165 	break;
8166     case SQL_ODBC_SQL_CONFORMANCE:
8167 	*((SQLSMALLINT *) val) = SQL_OSC_MINIMUM;
8168 	*valLen = sizeof (SQLSMALLINT);
8169 	break;
8170     case SQL_ODBC_API_CONFORMANCE:
8171 	*((SQLSMALLINT *) val) = SQL_OAC_LEVEL1;
8172 	*valLen = sizeof (SQLSMALLINT);
8173 	break;
8174     case SQL_DBMS_NAME:
8175 	strmak(val, "SQLite", valMax, valLen);
8176 	break;
8177     case SQL_DBMS_VER:
8178 	strmak(val, SQLITE_VERSION, valMax, valLen);
8179 	break;
8180     case SQL_COLUMN_ALIAS:
8181     case SQL_NEED_LONG_DATA_LEN:
8182 	strmak(val, "Y", valMax, valLen);
8183 	break;
8184     case SQL_ROW_UPDATES:
8185     case SQL_ACCESSIBLE_PROCEDURES:
8186     case SQL_PROCEDURES:
8187     case SQL_EXPRESSIONS_IN_ORDERBY:
8188     case SQL_ODBC_SQL_OPT_IEF:
8189     case SQL_LIKE_ESCAPE_CLAUSE:
8190     case SQL_ORDER_BY_COLUMNS_IN_SELECT:
8191     case SQL_OUTER_JOINS:
8192     case SQL_ACCESSIBLE_TABLES:
8193     case SQL_MULT_RESULT_SETS:
8194     case SQL_MULTIPLE_ACTIVE_TXN:
8195     case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
8196 	strmak(val, "N", valMax, valLen);
8197 	break;
8198 #ifdef SQL_CATALOG_NAME
8199     case SQL_CATALOG_NAME:
8200 #if defined(_WIN32) || defined(_WIN64)
8201 	strmak(val, d->xcelqrx ? "Y": "N", valMax, valLen);
8202 #else
8203 	strmak(val, "N", valMax, valLen);
8204 #endif
8205 	break;
8206 #endif
8207     case SQL_DATA_SOURCE_READ_ONLY:
8208 	strmak(val, "N", valMax, valLen);
8209 	break;
8210 #ifdef SQL_OJ_CAPABILITIES
8211     case SQL_OJ_CAPABILITIES:
8212 	*((SQLUINTEGER *) val) = 0;
8213 	*valLen = sizeof (SQLUINTEGER);
8214 	break;
8215 #endif
8216 #ifdef SQL_MAX_IDENTIFIER_LEN
8217     case SQL_MAX_IDENTIFIER_LEN:
8218 	*((SQLUSMALLINT *) val) = 255;
8219 	*valLen = sizeof (SQLUSMALLINT);
8220 	break;
8221 #endif
8222     case SQL_CONCAT_NULL_BEHAVIOR:
8223 	*((SQLSMALLINT *) val) = SQL_CB_NULL;
8224 	*valLen = sizeof (SQLSMALLINT);
8225 	break;
8226     case SQL_CURSOR_COMMIT_BEHAVIOR:
8227     case SQL_CURSOR_ROLLBACK_BEHAVIOR:
8228 	*((SQLSMALLINT *) val) = SQL_CB_PRESERVE;
8229 	*valLen = sizeof (SQLSMALLINT);
8230 	break;
8231 #ifdef SQL_CURSOR_SENSITIVITY
8232     case SQL_CURSOR_SENSITIVITY:
8233 	*((SQLUINTEGER *) val) = SQL_UNSPECIFIED;
8234 	*valLen = sizeof (SQLUINTEGER);
8235 	break;
8236 #endif
8237     case SQL_DEFAULT_TXN_ISOLATION:
8238 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
8239 	*valLen = sizeof (SQLUINTEGER);
8240 	break;
8241 #ifdef SQL_DESCRIBE_PARAMETER
8242     case SQL_DESCRIBE_PARAMETER:
8243 	strmak(val, "Y", valMax, valLen);
8244 	break;
8245 #endif
8246     case SQL_TXN_ISOLATION_OPTION:
8247 	*((SQLUINTEGER *) val) = SQL_TXN_SERIALIZABLE;
8248 	*valLen = sizeof (SQLUINTEGER);
8249 	break;
8250     case SQL_IDENTIFIER_CASE:
8251 	*((SQLSMALLINT *) val) = SQL_IC_SENSITIVE;
8252 	*valLen = sizeof (SQLSMALLINT);
8253 	break;
8254     case SQL_IDENTIFIER_QUOTE_CHAR:
8255 	strmak(val, "\"", valMax, valLen);
8256 	break;
8257     case SQL_MAX_TABLE_NAME_LEN:
8258     case SQL_MAX_COLUMN_NAME_LEN:
8259 	*((SQLSMALLINT *) val) = 255;
8260 	*valLen = sizeof (SQLSMALLINT);
8261 	break;
8262     case SQL_MAX_CURSOR_NAME_LEN:
8263 	*((SWORD *) val) = 255;
8264 	*valLen = sizeof (SWORD);
8265 	break;
8266     case SQL_MAX_PROCEDURE_NAME_LEN:
8267 	*((SQLSMALLINT *) val) = 0;
8268 	break;
8269     case SQL_MAX_QUALIFIER_NAME_LEN:
8270     case SQL_MAX_OWNER_NAME_LEN:
8271 	*((SQLSMALLINT *) val) = 255;
8272 	break;
8273     case SQL_OWNER_TERM:
8274 	strmak(val, "", valMax, valLen);
8275 	break;
8276     case SQL_PROCEDURE_TERM:
8277 	strmak(val, "PROCEDURE", valMax, valLen);
8278 	break;
8279     case SQL_QUALIFIER_NAME_SEPARATOR:
8280 	strmak(val, ".", valMax, valLen);
8281 	break;
8282     case SQL_QUALIFIER_TERM:
8283 #if defined(_WIN32) || defined(_WIN64)
8284 	strmak(val, d->xcelqrx ? "CATALOG" : "", valMax, valLen);
8285 #else
8286 	strmak(val, "", valMax, valLen);
8287 #endif
8288 	break;
8289     case SQL_QUALIFIER_USAGE:
8290 #if defined(_WIN32) || defined(_WIN64)
8291 	*((SQLUINTEGER *) val) = d->xcelqrx ?
8292 	    (SQL_CU_DML_STATEMENTS | SQL_CU_INDEX_DEFINITION |
8293 	     SQL_CU_TABLE_DEFINITION) : 0;
8294 #else
8295 	*((SQLUINTEGER *) val) = 0;
8296 #endif
8297 	*valLen = sizeof (SQLUINTEGER);
8298 	break;
8299     case SQL_SCROLL_CONCURRENCY:
8300 	*((SQLUINTEGER *) val) = SQL_SCCO_LOCK;
8301 	*valLen = sizeof (SQLUINTEGER);
8302 	break;
8303     case SQL_SCROLL_OPTIONS:
8304 	*((SQLUINTEGER *) val) = SQL_SO_STATIC | SQL_SO_FORWARD_ONLY;
8305 	*valLen = sizeof (SQLUINTEGER);
8306 	break;
8307     case SQL_TABLE_TERM:
8308 	strmak(val, "TABLE", valMax, valLen);
8309 	break;
8310     case SQL_TXN_CAPABLE:
8311 	*((SQLSMALLINT *) val) = SQL_TC_ALL;
8312 	*valLen = sizeof (SQLSMALLINT);
8313 	break;
8314     case SQL_CONVERT_FUNCTIONS:
8315 	*((SQLUINTEGER *) val) = 0;
8316 	*valLen = sizeof (SQLUINTEGER);
8317        break;
8318     case SQL_SYSTEM_FUNCTIONS:
8319     case SQL_NUMERIC_FUNCTIONS:
8320     case SQL_STRING_FUNCTIONS:
8321     case SQL_TIMEDATE_FUNCTIONS:
8322 	*((SQLUINTEGER *) val) = 0;
8323 	*valLen = sizeof (SQLUINTEGER);
8324 	break;
8325     case SQL_CONVERT_BIGINT:
8326     case SQL_CONVERT_BIT:
8327     case SQL_CONVERT_CHAR:
8328     case SQL_CONVERT_DATE:
8329     case SQL_CONVERT_DECIMAL:
8330     case SQL_CONVERT_DOUBLE:
8331     case SQL_CONVERT_FLOAT:
8332     case SQL_CONVERT_INTEGER:
8333     case SQL_CONVERT_LONGVARCHAR:
8334     case SQL_CONVERT_NUMERIC:
8335     case SQL_CONVERT_REAL:
8336     case SQL_CONVERT_SMALLINT:
8337     case SQL_CONVERT_TIME:
8338     case SQL_CONVERT_TIMESTAMP:
8339     case SQL_CONVERT_TINYINT:
8340     case SQL_CONVERT_VARCHAR:
8341 	*((SQLUINTEGER *) val) =
8342 	    SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
8343 	    SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT | SQL_CVT_REAL |
8344 	    SQL_CVT_DOUBLE | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
8345 	    SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_BIGINT |
8346 	    SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
8347 	*valLen = sizeof (SQLUINTEGER);
8348 	break;
8349     case SQL_CONVERT_BINARY:
8350     case SQL_CONVERT_VARBINARY:
8351     case SQL_CONVERT_LONGVARBINARY:
8352 	*((SQLUINTEGER *) val) = 0;
8353 	*valLen = sizeof (SQLUINTEGER);
8354 	break;
8355     case SQL_POSITIONED_STATEMENTS:
8356     case SQL_LOCK_TYPES:
8357 	*((SQLUINTEGER *) val) = 0;
8358 	*valLen = sizeof (SQLUINTEGER);
8359 	break;
8360     case SQL_BOOKMARK_PERSISTENCE:
8361 	*((SQLUINTEGER *) val) = SQL_BP_SCROLL;
8362 	*valLen = sizeof (SQLUINTEGER);
8363 	break;
8364     case SQL_UNION:
8365 	*((SQLUINTEGER *) val) = SQL_U_UNION | SQL_U_UNION_ALL;
8366 	*valLen = sizeof (SQLUINTEGER);
8367 	break;
8368     case SQL_OWNER_USAGE:
8369     case SQL_SUBQUERIES:
8370     case SQL_TIMEDATE_ADD_INTERVALS:
8371     case SQL_TIMEDATE_DIFF_INTERVALS:
8372 	*((SQLUINTEGER *) val) = 0;
8373 	*valLen = sizeof (SQLUINTEGER);
8374 	break;
8375     case SQL_QUOTED_IDENTIFIER_CASE:
8376 	*((SQLUSMALLINT *) val) = SQL_IC_SENSITIVE;
8377 	*valLen = sizeof (SQLUSMALLINT);
8378 	break;
8379     case SQL_POS_OPERATIONS:
8380 	*((SQLUINTEGER *) val) = 0;
8381 	*valLen = sizeof (SQLUINTEGER);
8382 	break;
8383     case SQL_ALTER_TABLE:
8384 	*((SQLUINTEGER *) val) = 0;
8385 	*valLen = sizeof (SQLUINTEGER);
8386 	break;
8387     case SQL_CORRELATION_NAME:
8388 	*((SQLSMALLINT *) val) = SQL_CN_DIFFERENT;
8389 	*valLen = sizeof (SQLSMALLINT);
8390 	break;
8391     case SQL_NON_NULLABLE_COLUMNS:
8392 	*((SQLSMALLINT *) val) = SQL_NNC_NON_NULL;
8393 	*valLen = sizeof (SQLSMALLINT);
8394 	break;
8395     case SQL_NULL_COLLATION:
8396 	*((SQLSMALLINT *) val) = SQL_NC_START;
8397 	*valLen = sizeof(SQLSMALLINT);
8398 	break;
8399     case SQL_MAX_COLUMNS_IN_GROUP_BY:
8400     case SQL_MAX_COLUMNS_IN_ORDER_BY:
8401     case SQL_MAX_COLUMNS_IN_SELECT:
8402     case SQL_MAX_COLUMNS_IN_TABLE:
8403     case SQL_MAX_ROW_SIZE:
8404     case SQL_MAX_TABLES_IN_SELECT:
8405 	*((SQLSMALLINT *) val) = 0;
8406 	*valLen = sizeof (SQLSMALLINT);
8407 	break;
8408     case SQL_MAX_BINARY_LITERAL_LEN:
8409     case SQL_MAX_CHAR_LITERAL_LEN:
8410 	*((SQLUINTEGER *) val) = 0;
8411 	*valLen = sizeof (SQLUINTEGER);
8412 	break;
8413     case SQL_MAX_COLUMNS_IN_INDEX:
8414 	*((SQLSMALLINT *) val) = 0;
8415 	*valLen = sizeof (SQLSMALLINT);
8416 	break;
8417     case SQL_MAX_INDEX_SIZE:
8418 	*((SQLUINTEGER *) val) = 0;
8419 	*valLen = sizeof(SQLUINTEGER);
8420 	break;
8421 #ifdef SQL_MAX_IDENTIFIER_LENGTH
8422     case SQL_MAX_IDENTIFIER_LENGTH:
8423 	*((SQLUINTEGER *) val) = 255;
8424 	*valLen = sizeof (SQLUINTEGER);
8425 	break;
8426 #endif
8427     case SQL_MAX_STATEMENT_LEN:
8428 	*((SQLUINTEGER *) val) = 16384;
8429 	*valLen = sizeof (SQLUINTEGER);
8430 	break;
8431     case SQL_QUALIFIER_LOCATION:
8432 	*((SQLSMALLINT *) val) = SQL_QL_START;
8433 	*valLen = sizeof (SQLSMALLINT);
8434 	break;
8435     case SQL_GETDATA_EXTENSIONS:
8436 	*((SQLUINTEGER *) val) =
8437 	    SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND;
8438 	*valLen = sizeof (SQLUINTEGER);
8439 	break;
8440     case SQL_STATIC_SENSITIVITY:
8441 	*((SQLUINTEGER *) val) = 0;
8442 	*valLen = sizeof (SQLUINTEGER);
8443 	break;
8444     case SQL_FILE_USAGE:
8445 #if defined(_WIN32) || defined(_WIN64)
8446 	*((SQLSMALLINT *) val) =
8447 	    d->xcelqrx ? SQL_FILE_CATALOG : SQL_FILE_NOT_SUPPORTED;
8448 #else
8449 	*((SQLSMALLINT *) val) = SQL_FILE_NOT_SUPPORTED;
8450 #endif
8451 	*valLen = sizeof (SQLSMALLINT);
8452 	break;
8453     case SQL_GROUP_BY:
8454 	*((SQLSMALLINT *) val) = SQL_GB_GROUP_BY_EQUALS_SELECT;
8455 	*valLen = sizeof (SQLSMALLINT);
8456 	break;
8457     case SQL_KEYWORDS:
8458 	strmak(val, "CREATE,SELECT,DROP,DELETE,UPDATE,INSERT,"
8459 	       "INTO,VALUES,TABLE,INDEX,FROM,SET,WHERE,AND,CURRENT,OF",
8460 	       valMax, valLen);
8461 	break;
8462     case SQL_SPECIAL_CHARACTERS:
8463 #ifdef SQL_COLLATION_SEQ
8464     case SQL_COLLATION_SEQ:
8465 #endif
8466 	strmak(val, "", valMax, valLen);
8467 	break;
8468     case SQL_BATCH_SUPPORT:
8469     case SQL_BATCH_ROW_COUNT:
8470     case SQL_PARAM_ARRAY_ROW_COUNTS:
8471 	*((SQLUINTEGER *) val) = 0;
8472 	*valLen = sizeof (SQLUINTEGER);
8473 	break;
8474     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
8475 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_BOOKMARK;
8476 	*valLen = sizeof (SQLUINTEGER);
8477 	break;
8478     case SQL_STATIC_CURSOR_ATTRIBUTES1:
8479 	*((SQLUINTEGER *) val) = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE |
8480 	    SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK;
8481 	*valLen = sizeof (SQLUINTEGER);
8482 	break;
8483     case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
8484     case SQL_STATIC_CURSOR_ATTRIBUTES2:
8485 	*((SQLUINTEGER *) val) = SQL_CA2_READ_ONLY_CONCURRENCY |
8486 	    SQL_CA2_LOCK_CONCURRENCY;
8487 	*valLen = sizeof (SQLUINTEGER);
8488 	break;
8489     case SQL_KEYSET_CURSOR_ATTRIBUTES1:
8490     case SQL_KEYSET_CURSOR_ATTRIBUTES2:
8491     case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
8492     case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
8493 	*((SQLUINTEGER *) val) = 0;
8494 	*valLen = sizeof (SQLUINTEGER);
8495 	break;
8496     case SQL_ODBC_INTERFACE_CONFORMANCE:
8497 	*((SQLUINTEGER *) val) = SQL_OIC_CORE;
8498 	*valLen = sizeof (SQLUINTEGER);
8499 	break;
8500     default:
8501 	setstatd(d, -1, "unsupported info option %d",
8502 		 (*d->ov3) ? "HYC00" : "S1C00", type);
8503 	return SQL_ERROR;
8504     }
8505     return SQL_SUCCESS;
8506 }
8507 
8508 #if (defined(HAVE_UNIXODBC) && (HAVE_UNIXODBC)) || !defined(WINTERFACE)
8509 /**
8510  * Return information about what this ODBC driver supports.
8511  * @param dbc database connection handle
8512  * @param type type of information to be retrieved
8513  * @param val output buffer
8514  * @param valMax length of output buffer
8515  * @param valLen output length
8516  * @result ODBC error code
8517  */
8518 
8519 SQLRETURN SQL_API
SQLGetInfo(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)8520 SQLGetInfo(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
8521 	   SQLSMALLINT *valLen)
8522 {
8523     SQLRETURN ret;
8524 
8525     HDBC_LOCK(dbc);
8526     ret = drvgetinfo(dbc, type, val, valMax, valLen);
8527     HDBC_UNLOCK(dbc);
8528     return ret;
8529 }
8530 #endif
8531 
8532 #ifdef WINTERFACE
8533 /**
8534  * Return information about what this ODBC driver supports.
8535  * @param dbc database connection handle
8536  * @param type type of information to be retrieved
8537  * @param val output buffer
8538  * @param valMax length of output buffer
8539  * @param valLen output length
8540  * @result ODBC error code
8541  */
8542 
8543 SQLRETURN SQL_API
SQLGetInfoW(SQLHDBC dbc,SQLUSMALLINT type,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen)8544 SQLGetInfoW(SQLHDBC dbc, SQLUSMALLINT type, SQLPOINTER val, SQLSMALLINT valMax,
8545 	    SQLSMALLINT *valLen)
8546 {
8547     SQLRETURN ret;
8548     SQLSMALLINT len = 0;
8549 
8550     HDBC_LOCK(dbc);
8551     ret = drvgetinfo(dbc, type, val, valMax, &len);
8552     HDBC_UNLOCK(dbc);
8553     if (ret == SQL_SUCCESS) {
8554 	SQLWCHAR *v = NULL;
8555 
8556 	switch (type) {
8557 	case SQL_USER_NAME:
8558 	case SQL_DRIVER_ODBC_VER:
8559 	case SQL_DATA_SOURCE_NAME:
8560 	case SQL_DRIVER_NAME:
8561 	case SQL_DRIVER_VER:
8562 	case SQL_ODBC_VER:
8563 	case SQL_SERVER_NAME:
8564 	case SQL_DATABASE_NAME:
8565 	case SQL_SEARCH_PATTERN_ESCAPE:
8566 	case SQL_DBMS_NAME:
8567 	case SQL_DBMS_VER:
8568 	case SQL_NEED_LONG_DATA_LEN:
8569 	case SQL_ROW_UPDATES:
8570 	case SQL_ACCESSIBLE_PROCEDURES:
8571 	case SQL_PROCEDURES:
8572 	case SQL_EXPRESSIONS_IN_ORDERBY:
8573 	case SQL_ODBC_SQL_OPT_IEF:
8574 	case SQL_LIKE_ESCAPE_CLAUSE:
8575 	case SQL_ORDER_BY_COLUMNS_IN_SELECT:
8576 	case SQL_OUTER_JOINS:
8577 	case SQL_COLUMN_ALIAS:
8578 	case SQL_ACCESSIBLE_TABLES:
8579 	case SQL_MULT_RESULT_SETS:
8580 	case SQL_MULTIPLE_ACTIVE_TXN:
8581 	case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
8582 	case SQL_DATA_SOURCE_READ_ONLY:
8583 #ifdef SQL_DESCRIBE_PARAMETER
8584 	case SQL_DESCRIBE_PARAMETER:
8585 #endif
8586 	case SQL_IDENTIFIER_QUOTE_CHAR:
8587 	case SQL_OWNER_TERM:
8588 	case SQL_PROCEDURE_TERM:
8589 	case SQL_QUALIFIER_NAME_SEPARATOR:
8590 	case SQL_QUALIFIER_TERM:
8591 	case SQL_TABLE_TERM:
8592 	case SQL_KEYWORDS:
8593 	case SQL_SPECIAL_CHARACTERS:
8594 #ifdef SQL_CATALOG_NAME
8595 	case SQL_CATALOG_NAME:
8596 #endif
8597 #ifdef SQL_COLLATION_SEQ
8598 	case SQL_COLLATION_SEQ:
8599 #endif
8600 	    if (val) {
8601 		if (len > 0) {
8602 		    v = uc_from_utf((SQLCHAR *) val, len);
8603 		    if (v) {
8604 			int vmax = valMax / sizeof (SQLWCHAR);
8605 
8606 			uc_strncpy(val, v, vmax);
8607 			if (len < vmax) {
8608 			    len = min(vmax, uc_strlen(v));
8609 			    v[len] = 0;
8610 			} else {
8611 			    len = vmax;
8612 			}
8613 			uc_free(v);
8614 			len *= sizeof (SQLWCHAR);
8615 		    } else {
8616 			len = 0;
8617 		    }
8618 		}
8619 		if (len <= 0) {
8620 		    len = 0;
8621 		    if (valMax >= sizeof (SQLWCHAR)) {
8622 			*((SQLWCHAR *)val) = 0;
8623 		    }
8624 		}
8625 	    } else {
8626 		len *= sizeof (SQLWCHAR);
8627 	    }
8628 	    break;
8629 	}
8630 	if (valLen) {
8631 	    *valLen = len;
8632 	}
8633     }
8634     return ret;
8635 }
8636 #endif
8637 
8638 /**
8639  * Return information about supported ODBC API functions.
8640  * @param dbc database connection handle
8641  * @param func function code to be retrieved
8642  * @param flags output indicator
8643  * @result ODBC error code
8644  */
8645 
8646 SQLRETURN SQL_API
SQLGetFunctions(SQLHDBC dbc,SQLUSMALLINT func,SQLUSMALLINT * flags)8647 SQLGetFunctions(SQLHDBC dbc, SQLUSMALLINT func,
8648 		SQLUSMALLINT *flags)
8649 {
8650     int i;
8651     SQLUSMALLINT exists[100];
8652 
8653     if (dbc == SQL_NULL_HDBC) {
8654 	return SQL_INVALID_HANDLE;
8655     }
8656     for (i = 0; i < array_size(exists); i++) {
8657 	exists[i] = SQL_FALSE;
8658     }
8659     exists[SQL_API_SQLALLOCCONNECT] = SQL_TRUE;
8660     exists[SQL_API_SQLFETCH] = SQL_TRUE;
8661     exists[SQL_API_SQLALLOCENV] = SQL_TRUE;
8662     exists[SQL_API_SQLFREECONNECT] = SQL_TRUE;
8663     exists[SQL_API_SQLALLOCSTMT] = SQL_TRUE;
8664     exists[SQL_API_SQLFREEENV] = SQL_TRUE;
8665     exists[SQL_API_SQLBINDCOL] = SQL_TRUE;
8666     exists[SQL_API_SQLFREESTMT] = SQL_TRUE;
8667     exists[SQL_API_SQLCANCEL] = SQL_TRUE;
8668     exists[SQL_API_SQLGETCURSORNAME] = SQL_TRUE;
8669     exists[SQL_API_SQLCOLATTRIBUTES] = SQL_TRUE;
8670     exists[SQL_API_SQLNUMRESULTCOLS] = SQL_TRUE;
8671     exists[SQL_API_SQLCONNECT] = SQL_TRUE;
8672     exists[SQL_API_SQLPREPARE] = SQL_TRUE;
8673     exists[SQL_API_SQLDESCRIBECOL] = SQL_TRUE;
8674     exists[SQL_API_SQLROWCOUNT] = SQL_TRUE;
8675     exists[SQL_API_SQLDISCONNECT] = SQL_TRUE;
8676     exists[SQL_API_SQLSETCURSORNAME] = SQL_TRUE;
8677     exists[SQL_API_SQLERROR] = SQL_TRUE;
8678     exists[SQL_API_SQLSETPARAM] = SQL_TRUE;
8679     exists[SQL_API_SQLEXECDIRECT] = SQL_TRUE;
8680     exists[SQL_API_SQLTRANSACT] = SQL_TRUE;
8681     exists[SQL_API_SQLEXECUTE] = SQL_TRUE;
8682     exists[SQL_API_SQLBINDPARAMETER] = SQL_TRUE;
8683     exists[SQL_API_SQLGETTYPEINFO] = SQL_TRUE;
8684     exists[SQL_API_SQLCOLUMNS] = SQL_TRUE;
8685     exists[SQL_API_SQLPARAMDATA] = SQL_TRUE;
8686     exists[SQL_API_SQLDRIVERCONNECT] = SQL_TRUE;
8687     exists[SQL_API_SQLPUTDATA] = SQL_TRUE;
8688     exists[SQL_API_SQLGETCONNECTOPTION] = SQL_TRUE;
8689     exists[SQL_API_SQLSETCONNECTOPTION] = SQL_TRUE;
8690     exists[SQL_API_SQLGETDATA] = SQL_TRUE;
8691     exists[SQL_API_SQLSETSTMTOPTION] = SQL_TRUE;
8692     exists[SQL_API_SQLGETFUNCTIONS] = SQL_TRUE;
8693     exists[SQL_API_SQLSPECIALCOLUMNS] = SQL_TRUE;
8694     exists[SQL_API_SQLGETINFO] = SQL_TRUE;
8695     exists[SQL_API_SQLSTATISTICS] = SQL_TRUE;
8696     exists[SQL_API_SQLGETSTMTOPTION] = SQL_TRUE;
8697     exists[SQL_API_SQLTABLES] = SQL_TRUE;
8698     exists[SQL_API_SQLBROWSECONNECT] = SQL_FALSE;
8699     exists[SQL_API_SQLNUMPARAMS] = SQL_TRUE;
8700     exists[SQL_API_SQLCOLUMNPRIVILEGES] = SQL_FALSE;
8701     exists[SQL_API_SQLPARAMOPTIONS] = SQL_FALSE;
8702     exists[SQL_API_SQLDATASOURCES] = SQL_TRUE;
8703     exists[SQL_API_SQLPRIMARYKEYS] = SQL_TRUE;
8704     exists[SQL_API_SQLDESCRIBEPARAM] = SQL_TRUE;
8705     exists[SQL_API_SQLPROCEDURECOLUMNS] = SQL_TRUE;
8706     exists[SQL_API_SQLDRIVERS] = SQL_FALSE;
8707     exists[SQL_API_SQLPROCEDURES] = SQL_TRUE;
8708     exists[SQL_API_SQLEXTENDEDFETCH] = SQL_TRUE;
8709     exists[SQL_API_SQLSETPOS] = SQL_TRUE;
8710     exists[SQL_API_SQLFOREIGNKEYS] = SQL_TRUE;
8711     exists[SQL_API_SQLSETSCROLLOPTIONS] = SQL_TRUE;
8712     exists[SQL_API_SQLMORERESULTS] = SQL_TRUE;
8713     exists[SQL_API_SQLTABLEPRIVILEGES] = SQL_TRUE;
8714     exists[SQL_API_SQLNATIVESQL] = SQL_TRUE;
8715     if (func == SQL_API_ALL_FUNCTIONS) {
8716 	memcpy(flags, exists, sizeof (exists));
8717     } else if (func == SQL_API_ODBC3_ALL_FUNCTIONS) {
8718 	int i;
8719 #define SET_EXISTS(x) \
8720 	flags[(x) >> 4] |= (1 << ((x) & 0xF))
8721 #define CLR_EXISTS(x) \
8722 	flags[(x) >> 4] &= ~(1 << ((x) & 0xF))
8723 
8724 	memset(flags, 0,
8725 	       sizeof (SQLUSMALLINT) * SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
8726 	for (i = 0; i < array_size(exists); i++) {
8727 	    if (exists[i]) {
8728 		flags[i >> 4] |= (1 << (i & 0xF));
8729 	    }
8730 	}
8731 	SET_EXISTS(SQL_API_SQLALLOCHANDLE);
8732 	SET_EXISTS(SQL_API_SQLFREEHANDLE);
8733 	SET_EXISTS(SQL_API_SQLGETSTMTATTR);
8734 	SET_EXISTS(SQL_API_SQLSETSTMTATTR);
8735 	SET_EXISTS(SQL_API_SQLGETCONNECTATTR);
8736 	SET_EXISTS(SQL_API_SQLSETCONNECTATTR);
8737 	SET_EXISTS(SQL_API_SQLGETENVATTR);
8738 	SET_EXISTS(SQL_API_SQLSETENVATTR);
8739 	SET_EXISTS(SQL_API_SQLCLOSECURSOR);
8740 	SET_EXISTS(SQL_API_SQLBINDPARAM);
8741 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
8742 	/*
8743 	 * Some unixODBC versions have problems with
8744 	 * SQLError() vs. SQLGetDiagRec() with loss
8745 	 * of error/warning messages.
8746 	 */
8747 	SET_EXISTS(SQL_API_SQLGETDIAGREC);
8748 #endif
8749 	SET_EXISTS(SQL_API_SQLFETCHSCROLL);
8750 	SET_EXISTS(SQL_API_SQLENDTRAN);
8751     } else {
8752 	if (func < array_size(exists)) {
8753 	    *flags = exists[func];
8754 	} else {
8755 	    switch (func) {
8756 	    case SQL_API_SQLALLOCHANDLE:
8757 	    case SQL_API_SQLFREEHANDLE:
8758 	    case SQL_API_SQLGETSTMTATTR:
8759 	    case SQL_API_SQLSETSTMTATTR:
8760 	    case SQL_API_SQLGETCONNECTATTR:
8761 	    case SQL_API_SQLSETCONNECTATTR:
8762 	    case SQL_API_SQLGETENVATTR:
8763 	    case SQL_API_SQLSETENVATTR:
8764 	    case SQL_API_SQLCLOSECURSOR:
8765 	    case SQL_API_SQLBINDPARAM:
8766 #if !defined(HAVE_UNIXODBC) || !(HAVE_UNIXODBC)
8767 	    /*
8768 	     * Some unixODBC versions have problems with
8769 	     * SQLError() vs. SQLGetDiagRec() with loss
8770 	     * of error/warning messages.
8771 	     */
8772 	    case SQL_API_SQLGETDIAGREC:
8773 #endif
8774 	    case SQL_API_SQLFETCHSCROLL:
8775 	    case SQL_API_SQLENDTRAN:
8776 		*flags = SQL_TRUE;
8777 		break;
8778 	    default:
8779 		*flags = SQL_FALSE;
8780 	    }
8781 	}
8782     }
8783     return SQL_SUCCESS;
8784 }
8785 
8786 /**
8787  * Internal allocate HENV.
8788  * @param env pointer to environment handle
8789  * @result ODBC error code
8790  */
8791 
8792 static SQLRETURN
drvallocenv(SQLHENV * env)8793 drvallocenv(SQLHENV *env)
8794 {
8795     ENV *e;
8796 
8797     if (env == NULL) {
8798 	return SQL_INVALID_HANDLE;
8799     }
8800     e = (ENV *) xmalloc(sizeof (ENV));
8801     if (e == NULL) {
8802 	*env = SQL_NULL_HENV;
8803 	return SQL_ERROR;
8804     }
8805     e->magic = ENV_MAGIC;
8806     e->ov3 = 0;
8807     e->pool = 0;
8808 #if defined(_WIN32) || defined(_WIN64)
8809     InitializeCriticalSection(&e->cs);
8810 #endif
8811     e->dbcs = NULL;
8812     *env = (SQLHENV) e;
8813     return SQL_SUCCESS;
8814 }
8815 
8816 /**
8817  * Allocate HENV.
8818  * @param env pointer to environment handle
8819  * @result ODBC error code
8820  */
8821 
8822 SQLRETURN SQL_API
SQLAllocEnv(SQLHENV * env)8823 SQLAllocEnv(SQLHENV *env)
8824 {
8825     return drvallocenv(env);
8826 }
8827 
8828 /**
8829  * Internal free HENV.
8830  * @param env environment handle
8831  * @result ODBC error code
8832  */
8833 
8834 static SQLRETURN
drvfreeenv(SQLHENV env)8835 drvfreeenv(SQLHENV env)
8836 {
8837     ENV *e;
8838 
8839     if (env == SQL_NULL_HENV) {
8840 	return SQL_INVALID_HANDLE;
8841     }
8842     e = (ENV *) env;
8843     if (e->magic != ENV_MAGIC) {
8844 	return SQL_SUCCESS;
8845     }
8846 #if defined(_WIN32) || defined(_WIN64)
8847     EnterCriticalSection(&e->cs);
8848 #endif
8849     if (e->dbcs) {
8850 #if defined(_WIN32) || defined(_WIN64)
8851 	LeaveCriticalSection(&e->cs);
8852 #endif
8853 	return SQL_ERROR;
8854     }
8855     e->magic = DEAD_MAGIC;
8856 #if defined(_WIN32) || defined(_WIN64)
8857     LeaveCriticalSection(&e->cs);
8858     DeleteCriticalSection(&e->cs);
8859 #endif
8860     xfree(e);
8861     return SQL_SUCCESS;
8862 }
8863 
8864 /**
8865  * Free HENV.
8866  * @param env environment handle
8867  * @result ODBC error code
8868  */
8869 
8870 SQLRETURN SQL_API
SQLFreeEnv(SQLHENV env)8871 SQLFreeEnv(SQLHENV env)
8872 {
8873     return drvfreeenv(env);
8874 }
8875 
8876 /**
8877  * Internal allocate HDBC.
8878  * @param env environment handle
8879  * @param dbc pointer to database connection handle
8880  * @result ODBC error code
8881  */
8882 
8883 static SQLRETURN
drvallocconnect(SQLHENV env,SQLHDBC * dbc)8884 drvallocconnect(SQLHENV env, SQLHDBC *dbc)
8885 {
8886     DBC *d;
8887     ENV *e;
8888     const char *verstr;
8889     int maj = 0, min = 0, lev = 0;
8890 
8891     if (dbc == NULL) {
8892 	return SQL_ERROR;
8893     }
8894     d = (DBC *) xmalloc(sizeof (DBC));
8895     if (d == NULL) {
8896 	*dbc = SQL_NULL_HDBC;
8897 	return SQL_ERROR;
8898     }
8899     memset(d, 0, sizeof (DBC));
8900     d->curtype = SQL_CURSOR_STATIC;
8901 #if (HAVE_LIBVERSION)
8902     verstr = sqlite_libversion();
8903 #else
8904     verstr = sqlite_version;
8905 #endif
8906     sscanf(verstr, "%d.%d.%d", &maj, &min, &lev);
8907     d->version = verinfo(maj & 0xFF, min & 0xFF, lev & 0xFF);
8908     if (d->version < verinfo(2, 8, 0)) {
8909 	xfree(d);
8910 	return SQL_ERROR;
8911     }
8912     d->ov3 = &d->ov3val;
8913     e = (ENV *) env;
8914 #if defined(_WIN32) || defined(_WIN64)
8915     if (e->magic == ENV_MAGIC) {
8916 	EnterCriticalSection(&e->cs);
8917     }
8918 #endif
8919     if (e->magic == ENV_MAGIC) {
8920 	DBC *n, *p;
8921 
8922 	d->env = e;
8923 	d->ov3 = &e->ov3;
8924 	p = NULL;
8925 	n = e->dbcs;
8926 	while (n) {
8927 	    p = n;
8928 	    n = n->next;
8929 	}
8930 	if (p) {
8931 	    p->next = d;
8932 	} else {
8933 	    e->dbcs = d;
8934 	}
8935     }
8936 #if defined(_WIN32) || defined(_WIN64)
8937     InitializeCriticalSection(&d->cs);
8938     d->owner = 0;
8939     if (e->magic == ENV_MAGIC) {
8940 	LeaveCriticalSection(&e->cs);
8941     }
8942 #endif
8943     d->autocommit = 1;
8944     d->magic = DBC_MAGIC;
8945     *dbc = (SQLHDBC) d;
8946     drvgetgpps(d);
8947     return SQL_SUCCESS;
8948 }
8949 
8950 /**
8951  * Allocate HDBC.
8952  * @param env environment handle
8953  * @param dbc pointer to database connection handle
8954  * @result ODBC error code
8955  */
8956 
8957 SQLRETURN SQL_API
SQLAllocConnect(SQLHENV env,SQLHDBC * dbc)8958 SQLAllocConnect(SQLHENV env, SQLHDBC *dbc)
8959 {
8960     return drvallocconnect(env, dbc);
8961 }
8962 
8963 /**
8964  * Internal free connection (HDBC).
8965  * @param dbc database connection handle
8966  * @result ODBC error code
8967  */
8968 
8969 static SQLRETURN
drvfreeconnect(SQLHDBC dbc)8970 drvfreeconnect(SQLHDBC dbc)
8971 {
8972     DBC *d;
8973     ENV *e;
8974     SQLRETURN ret = SQL_ERROR;
8975 
8976     if (dbc == SQL_NULL_HDBC) {
8977 	return SQL_INVALID_HANDLE;
8978     }
8979     d = (DBC *) dbc;
8980     if (d->magic != DBC_MAGIC) {
8981 	return SQL_INVALID_HANDLE;
8982     }
8983     e = d->env;
8984     if (e && e->magic == ENV_MAGIC) {
8985 #if defined(_WIN32) || defined(_WIN64)
8986 	EnterCriticalSection(&e->cs);
8987 #endif
8988     } else {
8989 	e = NULL;
8990     }
8991     HDBC_LOCK(dbc);
8992     if (d->sqlite) {
8993 	setstatd(d, -1, "not disconnected", (*d->ov3) ? "HY000" : "S1000");
8994 	HDBC_UNLOCK(dbc);
8995 	goto done;
8996     }
8997     while (d->stmt) {
8998 	freestmt((HSTMT) d->stmt);
8999     }
9000     if (e && e->magic == ENV_MAGIC) {
9001 	DBC *n, *p;
9002 
9003 	p = NULL;
9004 	n = e->dbcs;
9005 	while (n) {
9006 	    if (n == d) {
9007 		break;
9008 	    }
9009 	    p = n;
9010 	    n = n->next;
9011 	}
9012 	if (n) {
9013 	    if (p) {
9014 		p->next = d->next;
9015 	    } else {
9016 		e->dbcs = d->next;
9017 	    }
9018 	}
9019     }
9020     drvrelgpps(d);
9021     d->magic = DEAD_MAGIC;
9022 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9023     if (d->trace) {
9024 	fclose(d->trace);
9025     }
9026 #endif
9027 #if defined(_WIN32) || defined(_WIN64)
9028     d->owner = 0;
9029     LeaveCriticalSection(&d->cs);
9030     DeleteCriticalSection(&d->cs);
9031 #endif
9032     xfree(d);
9033     ret = SQL_SUCCESS;
9034 done:
9035 #if defined(_WIN32) || defined(_WIN64)
9036     if (e) {
9037 	LeaveCriticalSection(&e->cs);
9038     }
9039 #endif
9040     return ret;
9041 }
9042 
9043 /**
9044  * Free connection (HDBC).
9045  * @param dbc database connection handle
9046  * @result ODBC error code
9047  */
9048 
9049 SQLRETURN SQL_API
SQLFreeConnect(SQLHDBC dbc)9050 SQLFreeConnect(SQLHDBC dbc)
9051 {
9052     return drvfreeconnect(dbc);
9053 }
9054 
9055 /**
9056  * Internal get connect attribute of HDBC.
9057  * @param dbc database connection handle
9058  * @param attr option to be retrieved
9059  * @param val output buffer
9060  * @param bufmax size of output buffer
9061  * @param buflen output length
9062  * @result ODBC error code
9063  */
9064 
9065 static SQLRETURN
drvgetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)9066 drvgetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
9067 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
9068 {
9069     DBC *d;
9070     SQLINTEGER dummy;
9071 
9072     if (dbc == SQL_NULL_HDBC) {
9073 	return SQL_INVALID_HANDLE;
9074     }
9075     d = (DBC *) dbc;
9076     if (!val) {
9077 	val = (SQLPOINTER) &dummy;
9078     }
9079     if (!buflen) {
9080 	buflen = &dummy;
9081     }
9082     switch (attr) {
9083     case SQL_ATTR_CONNECTION_DEAD:
9084 	*((SQLINTEGER *) val) = d->sqlite ? SQL_CD_FALSE : SQL_CD_TRUE;
9085 	*buflen = sizeof (SQLINTEGER);
9086 	break;
9087     case SQL_ATTR_ACCESS_MODE:
9088 	*((SQLINTEGER *) val) = SQL_MODE_READ_WRITE;
9089 	*buflen = sizeof (SQLINTEGER);
9090 	break;
9091     case SQL_ATTR_AUTOCOMMIT:
9092 	*((SQLINTEGER *) val) =
9093 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
9094 	*buflen = sizeof (SQLINTEGER);
9095 	break;
9096     case SQL_ATTR_LOGIN_TIMEOUT:
9097 	*((SQLINTEGER *) val) = 100;
9098 	*buflen = sizeof (SQLINTEGER);
9099 	break;
9100     case SQL_ATTR_ODBC_CURSORS:
9101 	*((SQLINTEGER *) val) = SQL_CUR_USE_DRIVER;
9102 	*buflen = sizeof (SQLINTEGER);
9103 	break;
9104     case SQL_ATTR_PACKET_SIZE:
9105 	*((SQLINTEGER *) val) = 16384;
9106 	*buflen = sizeof (SQLINTEGER);
9107 	break;
9108     case SQL_ATTR_TXN_ISOLATION:
9109 	*((SQLINTEGER *) val) = SQL_TXN_SERIALIZABLE;
9110 	*buflen = sizeof (SQLINTEGER);
9111 	break;
9112     case SQL_ATTR_TRACEFILE:
9113     case SQL_ATTR_TRANSLATE_LIB:
9114 	*((SQLCHAR *) val) = 0;
9115 	*buflen = 0;
9116 	break;
9117     case SQL_ATTR_CURRENT_CATALOG:
9118 #if defined(_WIN32) || defined(_WIN64)
9119 	if (d->xcelqrx) {
9120 	    if ((bufmax > 4) && (val != (SQLPOINTER) &dummy)) {
9121 		strcpy((char *) val, "main");
9122 		*buflen = 4;
9123 		break;
9124 	    }
9125 	}
9126 #endif
9127 	*((SQLCHAR *) val) = 0;
9128 	*buflen = 0;
9129 	break;
9130     case SQL_ATTR_TRACE:
9131     case SQL_ATTR_QUIET_MODE:
9132     case SQL_ATTR_TRANSLATE_OPTION:
9133     case SQL_ATTR_KEYSET_SIZE:
9134     case SQL_ATTR_QUERY_TIMEOUT:
9135 	*((SQLINTEGER *) val) = 0;
9136 	*buflen = sizeof (SQLINTEGER);
9137 	break;
9138     case SQL_ATTR_PARAM_BIND_TYPE:
9139 	*((SQLUINTEGER *) val) = SQL_PARAM_BIND_BY_COLUMN;
9140 	*buflen = sizeof (SQLUINTEGER);
9141 	break;
9142     case SQL_ATTR_ROW_BIND_TYPE:
9143 	*((SQLUINTEGER *) val) = SQL_BIND_BY_COLUMN;
9144 	*buflen = sizeof (SQLUINTEGER);
9145 	break;
9146     case SQL_ATTR_USE_BOOKMARKS:
9147 	*((SQLINTEGER *) val) = SQL_UB_OFF;
9148 	*buflen = sizeof (SQLINTEGER);
9149 	break;
9150     case SQL_ATTR_ASYNC_ENABLE:
9151 	*((SQLINTEGER *) val) = SQL_ASYNC_ENABLE_OFF;
9152 	*buflen = sizeof (SQLINTEGER);
9153 	break;
9154     case SQL_ATTR_NOSCAN:
9155 	*((SQLINTEGER *) val) = SQL_NOSCAN_OFF;
9156 	*buflen = sizeof (SQLINTEGER);
9157 	break;
9158     case SQL_ATTR_CONCURRENCY:
9159 	*((SQLINTEGER *) val) = SQL_CONCUR_LOCK;
9160 	*buflen = sizeof (SQLINTEGER);
9161 	break;
9162 #ifdef SQL_ATTR_CURSOR_SENSITIVITY
9163     case SQL_ATTR_CURSOR_SENSITIVITY:
9164 	*((SQLINTEGER *) val) = SQL_UNSPECIFIED;
9165 	*buflen = sizeof (SQLINTEGER);
9166 	break;
9167 #endif
9168     case SQL_ATTR_SIMULATE_CURSOR:
9169 	*((SQLINTEGER *) val) = SQL_SC_NON_UNIQUE;
9170 	*buflen = sizeof (SQLINTEGER);
9171 	break;
9172     case SQL_ATTR_MAX_ROWS:
9173     case SQL_ATTR_MAX_LENGTH:
9174 	*((SQLINTEGER *) val) = 1000000000;
9175 	*buflen = sizeof (SQLINTEGER);
9176 	break;
9177     case SQL_ATTR_CURSOR_TYPE:
9178 	*((SQLINTEGER *) val) = d->curtype;
9179 	*buflen = sizeof (SQLINTEGER);
9180 	break;
9181     case SQL_ATTR_RETRIEVE_DATA:
9182 	*((SQLINTEGER *) val) = SQL_RD_ON;
9183 	*buflen = sizeof (SQLINTEGER);
9184 	break;
9185     default:
9186 	setstatd(d, -1, "unsupported connect attribute %d",
9187 		 (*d->ov3) ? "HYC00" : "S1C00", (int) attr);
9188 	return SQL_ERROR;
9189     }
9190     return SQL_SUCCESS;
9191 }
9192 
9193 #ifndef WINTERFACE
9194 /**
9195  * Get connect attribute of HDBC.
9196  * @param dbc database connection handle
9197  * @param attr option to be retrieved
9198  * @param val output buffer
9199  * @param bufmax size of output buffer
9200  * @param buflen output length
9201  * @result ODBC error code
9202  */
9203 
9204 SQLRETURN SQL_API
SQLGetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)9205 SQLGetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
9206 		  SQLINTEGER bufmax, SQLINTEGER *buflen)
9207 {
9208     SQLRETURN ret;
9209 
9210     HDBC_LOCK(dbc);
9211     ret = drvgetconnectattr(dbc, attr, val, bufmax, buflen);
9212     HDBC_UNLOCK(dbc);
9213     return ret;
9214 }
9215 #endif
9216 
9217 #ifdef WINTERFACE
9218 /**
9219  * Get connect attribute of HDBC (UNICODE version).
9220  * @param dbc database connection handle
9221  * @param attr option to be retrieved
9222  * @param val output buffer
9223  * @param bufmax size of output buffer
9224  * @param buflen output length
9225  * @result ODBC error code
9226  */
9227 
9228 SQLRETURN SQL_API
SQLGetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER bufmax,SQLINTEGER * buflen)9229 SQLGetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
9230 		   SQLINTEGER bufmax, SQLINTEGER *buflen)
9231 {
9232     SQLRETURN ret;
9233     SQLINTEGER len = 0;
9234 
9235     HDBC_LOCK(dbc);
9236     ret = drvgetconnectattr(dbc, attr, val, bufmax, &len);
9237     if (ret == SQL_SUCCESS) {
9238 	SQLWCHAR *v = NULL;
9239 
9240 	switch (attr) {
9241 	case SQL_ATTR_TRACEFILE:
9242 	case SQL_ATTR_CURRENT_CATALOG:
9243 	case SQL_ATTR_TRANSLATE_LIB:
9244 	    if (val) {
9245 		if (len > 0) {
9246 		    v = uc_from_utf((SQLCHAR *) val, len);
9247 		    if (v) {
9248 			int vmax = bufmax / sizeof (SQLWCHAR);
9249 
9250 			uc_strncpy(val, v, vmax);
9251 			if (len < vmax) {
9252 			    len = min(vmax, uc_strlen(v));
9253 			    v[len] = 0;
9254 			} else {
9255 			    len = vmax;
9256 			}
9257 			uc_free(v);
9258 			len *= sizeof (SQLWCHAR);
9259 		    } else {
9260 			len = 0;
9261 		    }
9262 		}
9263 		if (len <= 0) {
9264 		    len = 0;
9265 		    if (bufmax >= sizeof (SQLWCHAR)) {
9266 			*((SQLWCHAR *)val) = 0;
9267 		    }
9268 		}
9269 	    } else {
9270 		len *= sizeof (SQLWCHAR);
9271 	    }
9272 	    break;
9273 	}
9274 	if (buflen) {
9275 	    *buflen = len;
9276 	}
9277     }
9278     HDBC_UNLOCK(dbc);
9279     return ret;
9280 }
9281 #endif
9282 
9283 /**
9284  * Internal set connect attribute of HDBC.
9285  * @param dbc database connection handle
9286  * @param attr option to be set
9287  * @param val option value
9288  * @param len size of option
9289  * @result ODBC error code
9290  */
9291 
9292 static SQLRETURN
drvsetconnectattr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)9293 drvsetconnectattr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
9294 		  SQLINTEGER len)
9295 {
9296     DBC *d;
9297 
9298     if (dbc == SQL_NULL_HDBC) {
9299 	return SQL_INVALID_HANDLE;
9300     }
9301     d = (DBC *) dbc;
9302     switch (attr) {
9303     case SQL_AUTOCOMMIT:
9304 	d->autocommit = val == (SQLPOINTER) SQL_AUTOCOMMIT_ON;
9305 	if (d->autocommit && d->intrans) {
9306 	    return endtran(d, SQL_COMMIT, 1);
9307 	} else if (!d->autocommit) {
9308 	    vm_end(d->vm_stmt);
9309 	}
9310 	break;
9311     default:
9312 	setstatd(d, -1, "option value changed", "01S02");
9313 	return SQL_SUCCESS_WITH_INFO;
9314     }
9315     return SQL_SUCCESS;
9316 }
9317 
9318 #ifndef WINTERFACE
9319 /**
9320  * Set connect attribute of HDBC.
9321  * @param dbc database connection handle
9322  * @param attr option to be set
9323  * @param val option value
9324  * @param len size of option
9325  * @result ODBC error code
9326  */
9327 
9328 SQLRETURN SQL_API
SQLSetConnectAttr(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)9329 SQLSetConnectAttr(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
9330 		  SQLINTEGER len)
9331 {
9332     SQLRETURN ret;
9333 
9334     HDBC_LOCK(dbc);
9335     ret = drvsetconnectattr(dbc, attr, val, len);
9336     HDBC_UNLOCK(dbc);
9337     return ret;
9338 }
9339 #endif
9340 
9341 #ifdef WINTERFACE
9342 /**
9343  * Set connect attribute of HDBC (UNICODE version).
9344  * @param dbc database connection handle
9345  * @param attr option to be set
9346  * @param val option value
9347  * @param len size of option
9348  * @result ODBC error code
9349  */
9350 
9351 SQLRETURN SQL_API
SQLSetConnectAttrW(SQLHDBC dbc,SQLINTEGER attr,SQLPOINTER val,SQLINTEGER len)9352 SQLSetConnectAttrW(SQLHDBC dbc, SQLINTEGER attr, SQLPOINTER val,
9353 		   SQLINTEGER len)
9354 {
9355     SQLRETURN ret;
9356 
9357     HDBC_LOCK(dbc);
9358     ret = drvsetconnectattr(dbc, attr, val, len);
9359     HDBC_UNLOCK(dbc);
9360     return ret;
9361 }
9362 #endif
9363 
9364 /**
9365  * Internal get connect option of HDBC.
9366  * @param dbc database connection handle
9367  * @param opt option to be retrieved
9368  * @param param output buffer
9369  * @result ODBC error code
9370  */
9371 
9372 static SQLRETURN
drvgetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)9373 drvgetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
9374 {
9375     DBC *d;
9376     SQLINTEGER dummy;
9377 
9378     if (dbc == SQL_NULL_HDBC) {
9379 	return SQL_INVALID_HANDLE;
9380     }
9381     d = (DBC *) dbc;
9382     if (!param) {
9383 	param = (SQLPOINTER) &dummy;
9384     }
9385     switch (opt) {
9386     case SQL_ACCESS_MODE:
9387 	*((SQLINTEGER *) param) = SQL_MODE_READ_WRITE;
9388 	break;
9389     case SQL_AUTOCOMMIT:
9390 	*((SQLINTEGER *) param) =
9391 	    d->autocommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
9392 	break;
9393     case SQL_LOGIN_TIMEOUT:
9394 	*((SQLINTEGER *) param) = 100;
9395 	break;
9396     case SQL_ODBC_CURSORS:
9397 	*((SQLINTEGER *) param) = SQL_CUR_USE_DRIVER;
9398 	break;
9399     case SQL_PACKET_SIZE:
9400 	*((SQLINTEGER *) param) = 16384;
9401 	break;
9402     case SQL_TXN_ISOLATION:
9403 	*((SQLINTEGER *) param) = SQL_TXN_SERIALIZABLE;
9404 	break;
9405     case SQL_OPT_TRACEFILE:
9406     case SQL_CURRENT_QUALIFIER:
9407     case SQL_TRANSLATE_DLL:
9408 	*((SQLCHAR *) param) = 0;
9409 	break;
9410     case SQL_OPT_TRACE:
9411     case SQL_QUIET_MODE:
9412     case SQL_KEYSET_SIZE:
9413     case SQL_QUERY_TIMEOUT:
9414     case SQL_BIND_TYPE:
9415     case SQL_TRANSLATE_OPTION:
9416 	*((SQLINTEGER *) param) = 0;
9417 	break;
9418     case SQL_USE_BOOKMARKS:
9419 	*((SQLINTEGER *) param) = SQL_UB_OFF;
9420 	break;
9421     case SQL_ASYNC_ENABLE:
9422 	*((SQLINTEGER *) param) = SQL_ASYNC_ENABLE_OFF;
9423 	break;
9424     case SQL_NOSCAN:
9425 	*((SQLINTEGER *) param) = SQL_NOSCAN_OFF;
9426 	break;
9427     case SQL_CONCURRENCY:
9428 	*((SQLINTEGER *) param) = SQL_CONCUR_LOCK;
9429 	break;
9430     case SQL_SIMULATE_CURSOR:
9431 	*((SQLINTEGER *) param) = SQL_SC_NON_UNIQUE;
9432 	break;
9433     case SQL_ROWSET_SIZE:
9434     case SQL_MAX_ROWS:
9435     case SQL_MAX_LENGTH:
9436 	*((SQLINTEGER *) param) = 1000000000;
9437 	break;
9438     case SQL_CURSOR_TYPE:
9439 	*((SQLINTEGER *) param) = d->curtype;
9440 	break;
9441     case SQL_RETRIEVE_DATA:
9442 	*((SQLINTEGER *) param) = SQL_RD_ON;
9443 	break;
9444     default:
9445 	setstatd(d, -1, "unsupported connect option %d",
9446 		 (*d->ov3) ? "HYC00" : "S1C00", opt);
9447 	return SQL_ERROR;
9448     }
9449     return SQL_SUCCESS;
9450 }
9451 
9452 #ifndef WINTERFACE
9453 /**
9454  * Get connect option of HDBC.
9455  * @param dbc database connection handle
9456  * @param opt option to be retrieved
9457  * @param param output buffer
9458  * @result ODBC error code
9459  */
9460 
9461 SQLRETURN SQL_API
SQLGetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)9462 SQLGetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
9463 {
9464     SQLRETURN ret;
9465 
9466     HDBC_LOCK(dbc);
9467     ret = drvgetconnectoption(dbc, opt, param);
9468     HDBC_UNLOCK(dbc);
9469     return ret;
9470 }
9471 #endif
9472 
9473 #ifdef WINTERFACE
9474 /**
9475  * Get connect option of HDBC (UNICODE version).
9476  * @param dbc database connection handle
9477  * @param opt option to be retrieved
9478  * @param param output buffer
9479  * @result ODBC error code
9480  */
9481 
9482 SQLRETURN SQL_API
SQLGetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLPOINTER param)9483 SQLGetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLPOINTER param)
9484 {
9485     SQLRETURN ret;
9486 
9487     HDBC_LOCK(dbc);
9488     ret = drvgetconnectoption(dbc, opt, param);
9489     if (SQL_SUCCEEDED(ret)) {
9490 	switch (opt) {
9491 	case SQL_OPT_TRACEFILE:
9492 	case SQL_CURRENT_QUALIFIER:
9493 	case SQL_TRANSLATE_DLL:
9494 	    if (param) {
9495 		*(SQLWCHAR *) param = 0;
9496 	    }
9497 	    break;
9498 	}
9499     }
9500     HDBC_UNLOCK(dbc);
9501     return ret;
9502 }
9503 #endif
9504 
9505 /**
9506  * Internal set option on HDBC.
9507  * @param dbc database connection handle
9508  * @param opt option to be set
9509  * @param param option value
9510  * @result ODBC error code
9511  */
9512 
9513 static SQLRETURN
drvsetconnectoption(SQLHDBC dbc,SQLUSMALLINT opt,SQLUINTEGER param)9514 drvsetconnectoption(SQLHDBC dbc, SQLUSMALLINT opt, SQLUINTEGER param)
9515 {
9516     DBC *d;
9517 
9518     if (dbc == SQL_NULL_HDBC) {
9519 	return SQL_INVALID_HANDLE;
9520     }
9521     d = (DBC *) dbc;
9522     switch (opt) {
9523     case SQL_AUTOCOMMIT:
9524 	d->autocommit = param == SQL_AUTOCOMMIT_ON;
9525 	if (d->autocommit && d->intrans) {
9526 	    return endtran(d, SQL_COMMIT, 1);
9527 	} else if (!d->autocommit) {
9528 	    vm_end(d->vm_stmt);
9529 	}
9530 	break;
9531     default:
9532 	setstatd(d, -1, "option value changed", "01S02");
9533 	return SQL_SUCCESS_WITH_INFO;
9534     }
9535     return SQL_SUCCESS;
9536 }
9537 
9538 #ifndef WINTERFACE
9539 /**
9540  * Set option on HDBC.
9541  * @param dbc database connection handle
9542  * @param opt option to be set
9543  * @param param option value
9544  * @result ODBC error code
9545  */
9546 
9547 SQLRETURN SQL_API
SQLSetConnectOption(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)9548 SQLSetConnectOption(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
9549 {
9550     SQLRETURN ret;
9551 
9552     HDBC_LOCK(dbc);
9553     ret = drvsetconnectoption(dbc, opt, param);
9554     HDBC_UNLOCK(dbc);
9555     return ret;
9556 }
9557 #endif
9558 
9559 #ifdef WINTERFACE
9560 /**
9561  * Set option on HDBC (UNICODE version).
9562  * @param dbc database connection handle
9563  * @param opt option to be set
9564  * @param param option value
9565  * @result ODBC error code
9566  */
9567 
9568 SQLRETURN SQL_API
SQLSetConnectOptionW(SQLHDBC dbc,SQLUSMALLINT opt,SQLULEN param)9569 SQLSetConnectOptionW(SQLHDBC dbc, SQLUSMALLINT opt, SQLULEN param)
9570 {
9571     SQLRETURN ret;
9572 
9573     HDBC_LOCK(dbc);
9574     ret = drvsetconnectoption(dbc, opt, param);
9575     HDBC_UNLOCK(dbc);
9576     return ret;
9577 }
9578 #endif
9579 
9580 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64) && !defined(__OS2__))
9581 
9582 /**
9583  * Handling of SQLConnect() connection attributes
9584  * for standalone operation without driver manager.
9585  * @param dsn DSN/driver connection string
9586  * @param attr attribute string to be retrieved
9587  * @param out output buffer
9588  * @param outLen length of output buffer
9589  * @result true or false
9590  */
9591 
9592 static int
getdsnattr(char * dsn,char * attr,char * out,int outLen)9593 getdsnattr(char *dsn, char *attr, char *out, int outLen)
9594 {
9595     char *str = dsn, *start;
9596     int len = strlen(attr);
9597 
9598     while (*str) {
9599 	while (*str && *str == ';') {
9600 	    ++str;
9601 	}
9602 	start = str;
9603 	if ((str = strchr(str, '=')) == NULL) {
9604 	    return 0;
9605 	}
9606 	if (str - start == len && strncasecmp(start, attr, len) == 0) {
9607 	    start = ++str;
9608 	    while (*str && *str != ';') {
9609 		++str;
9610 	    }
9611 	    len = min(outLen - 1, str - start);
9612 	    strncpy(out, start, len);
9613 	    out[len] = '\0';
9614 	    return 1;
9615 	}
9616 	while (*str && *str != ';') {
9617 	    ++str;
9618 	}
9619     }
9620     return 0;
9621 }
9622 #endif
9623 
9624 /**
9625  * Internal connect to SQLite database.
9626  * @param dbc database connection handle
9627  * @param dsn DSN string
9628  * @param dsnLen length of DSN string or SQL_NTS
9629  * @result ODBC error code
9630  */
9631 
9632 static SQLRETURN
drvconnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen)9633 drvconnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen)
9634 {
9635     DBC *d;
9636     int len;
9637     char buf[SQL_MAX_MESSAGE_LENGTH * 6], dbname[SQL_MAX_MESSAGE_LENGTH];
9638     char busy[SQL_MAX_MESSAGE_LENGTH / 4];
9639     char sflag[32], ntflag[32], nwflag[32], lnflag[32];
9640 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9641     char tracef[SQL_MAX_MESSAGE_LENGTH];
9642 #endif
9643 
9644     if (dbc == SQL_NULL_HDBC) {
9645 	return SQL_INVALID_HANDLE;
9646     }
9647     d = (DBC *) dbc;
9648     if (d->magic != DBC_MAGIC) {
9649 	return SQL_INVALID_HANDLE;
9650     }
9651     if (d->sqlite != NULL) {
9652 	setstatd(d, -1, "connection already established", "08002");
9653 	return SQL_ERROR;
9654     }
9655     buf[0] = '\0';
9656     if (dsnLen == SQL_NTS) {
9657 	len = sizeof (buf) - 1;
9658     } else {
9659 	len = min(sizeof (buf) - 1, dsnLen);
9660     }
9661     if (dsn != NULL) {
9662 	strncpy(buf, (char *) dsn, len);
9663     }
9664     buf[len] = '\0';
9665     if (buf[0] == '\0') {
9666 	setstatd(d, -1, "invalid DSN", (*d->ov3) ? "HY090" : "S1090");
9667 	return SQL_ERROR;
9668     }
9669     busy[0] = '\0';
9670     dbname[0] = '\0';
9671 #ifdef WITHOUT_DRIVERMGR
9672     getdsnattr(buf, "database", dbname, sizeof (dbname));
9673     if (dbname[0] == '\0') {
9674 	strncpy(dbname, buf, sizeof (dbname));
9675 	dbname[sizeof (dbname) - 1] = '\0';
9676     }
9677     getdsnattr(buf, "timeout", busy, sizeof (busy));
9678     sflag[0] = '\0';
9679     ntflag[0] = '\0';
9680     nwflag[0] = '\0';
9681     lnflag[0] = '\0';
9682     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
9683     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
9684     getdsnattr(buf, "nowchar", nwflag, sizeof (nwflag));
9685     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
9686 #else
9687     SQLGetPrivateProfileString(buf, "timeout", "100000",
9688 			       busy, sizeof (busy), ODBC_INI);
9689     SQLGetPrivateProfileString(buf, "database", "",
9690 			       dbname, sizeof (dbname), ODBC_INI);
9691     SQLGetPrivateProfileString(buf, "stepapi", "",
9692 			       sflag, sizeof (sflag), ODBC_INI);
9693     SQLGetPrivateProfileString(buf, "notxn", "",
9694 			       ntflag, sizeof (ntflag), ODBC_INI);
9695     SQLGetPrivateProfileString(buf, "nowchar", "",
9696 			       nwflag, sizeof (nwflag), ODBC_INI);
9697     SQLGetPrivateProfileString(buf, "longnames", "",
9698 			       lnflag, sizeof (lnflag), ODBC_INI);
9699 #endif
9700 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9701     tracef[0] = '\0';
9702 #ifdef WITHOUT_DRIVERMGR
9703     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
9704 #else
9705     SQLGetPrivateProfileString(buf, "tracefile", "",
9706 			       tracef, sizeof (tracef), ODBC_INI);
9707 #endif
9708     if (tracef[0] != '\0') {
9709 	d->trace = fopen(tracef, "a");
9710     }
9711 #endif
9712     d->nowchar = getbool(nwflag);
9713     d->longnames = getbool(lnflag);
9714     return dbopen(d, dbname, (char *) dsn, sflag, ntflag, busy);
9715 }
9716 
9717 #ifndef WINTERFACE
9718 /**
9719  * Connect to SQLite database.
9720  * @param dbc database connection handle
9721  * @param dsn DSN string
9722  * @param dsnLen length of DSN string or SQL_NTS
9723  * @param uid user id string or NULL
9724  * @param uidLen length of user id string or SQL_NTS
9725  * @param pass password string or NULL
9726  * @param passLen length of password string or SQL_NTS
9727  * @result ODBC error code
9728  */
9729 
9730 SQLRETURN SQL_API
SQLConnect(SQLHDBC dbc,SQLCHAR * dsn,SQLSMALLINT dsnLen,SQLCHAR * uid,SQLSMALLINT uidLen,SQLCHAR * pass,SQLSMALLINT passLen)9731 SQLConnect(SQLHDBC dbc, SQLCHAR *dsn, SQLSMALLINT dsnLen,
9732 	   SQLCHAR *uid, SQLSMALLINT uidLen,
9733 	   SQLCHAR *pass, SQLSMALLINT passLen)
9734 {
9735     SQLRETURN ret;
9736 
9737     HDBC_LOCK(dbc);
9738     ret = drvconnect(dbc, dsn, dsnLen);
9739     HDBC_UNLOCK(dbc);
9740     return ret;
9741 }
9742 #endif
9743 
9744 #ifdef WINTERFACE
9745 /**
9746  * Connect to SQLite database.
9747  * @param dbc database connection handle
9748  * @param dsn DSN string
9749  * @param dsnLen length of DSN string or SQL_NTS
9750  * @param uid user id string or NULL
9751  * @param uidLen length of user id string or SQL_NTS
9752  * @param pass password string or NULL
9753  * @param passLen length of password string or SQL_NTS
9754  * @result ODBC error code
9755  */
9756 
9757 SQLRETURN SQL_API
SQLConnectW(SQLHDBC dbc,SQLWCHAR * dsn,SQLSMALLINT dsnLen,SQLWCHAR * uid,SQLSMALLINT uidLen,SQLWCHAR * pass,SQLSMALLINT passLen)9758 SQLConnectW(SQLHDBC dbc, SQLWCHAR *dsn, SQLSMALLINT dsnLen,
9759 	    SQLWCHAR *uid, SQLSMALLINT uidLen,
9760 	    SQLWCHAR *pass, SQLSMALLINT passLen)
9761 {
9762     char *dsna = NULL;
9763     SQLRETURN ret;
9764 
9765     HDBC_LOCK(dbc);
9766     if (dsn) {
9767 	dsna = uc_to_utf_c(dsn, dsnLen);
9768 	if (!dsna) {
9769 	    DBC *d = (DBC *) dbc;
9770 
9771 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
9772 	    return SQL_ERROR;
9773 	}
9774     }
9775     ret = drvconnect(dbc, (SQLCHAR *) dsna, SQL_NTS);
9776     HDBC_UNLOCK(dbc);
9777     uc_free(dsna);
9778     return ret;
9779 }
9780 #endif
9781 
9782 /**
9783  * Internal disconnect given HDBC.
9784  * @param dbc database connection handle
9785  * @result ODBC error code
9786  */
9787 
9788 static SQLRETURN
drvdisconnect(SQLHDBC dbc)9789 drvdisconnect(SQLHDBC dbc)
9790 {
9791     DBC *d;
9792 
9793     if (dbc == SQL_NULL_HDBC) {
9794 	return SQL_INVALID_HANDLE;
9795     }
9796     d = (DBC *) dbc;
9797     if (d->magic != DBC_MAGIC) {
9798 	return SQL_INVALID_HANDLE;
9799     }
9800     if (d->intrans) {
9801 	setstatd(d, -1, "incomplete transaction", "25000");
9802 	return SQL_ERROR;
9803     }
9804     if (d->vm_stmt) {
9805 	vm_end(d->vm_stmt);
9806     }
9807     if (d->sqlite) {
9808 	sqlite_close(d->sqlite);
9809 	d->sqlite = NULL;
9810     }
9811     freep(&d->dbname);
9812     freep(&d->dsn);
9813     return SQL_SUCCESS;
9814 }
9815 
9816 /**
9817  * Disconnect given HDBC.
9818  * @param dbc database connection handle
9819  * @result ODBC error code
9820  */
9821 
9822 SQLRETURN SQL_API
SQLDisconnect(SQLHDBC dbc)9823 SQLDisconnect(SQLHDBC dbc)
9824 {
9825     SQLRETURN ret;
9826 
9827     HDBC_LOCK(dbc);
9828     ret = drvdisconnect(dbc);
9829     HDBC_UNLOCK(dbc);
9830     return ret;
9831 }
9832 
9833 #if defined(WITHOUT_DRIVERMGR) || (!defined(_WIN32) && !defined(_WIN64) && !defined(__OS2__))
9834 
9835 /**
9836  * Internal standalone (w/o driver manager) database connect.
9837  * @param dbc database connection handle
9838  * @param hwnd dummy window handle or NULL
9839  * @param connIn driver connect input string
9840  * @param connInLen length of driver connect input string or SQL_NTS
9841  * @param connOut driver connect output string
9842  * @param connOutMax length of driver connect output string
9843  * @param connOutLen output length of driver connect output string
9844  * @param drvcompl completion type
9845  * @result ODBC error code
9846  */
9847 
9848 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)9849 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
9850 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
9851 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
9852 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
9853 {
9854     DBC *d;
9855     int len;
9856     char buf[SQL_MAX_MESSAGE_LENGTH * 6], dbname[SQL_MAX_MESSAGE_LENGTH];
9857     char dsn[SQL_MAX_MESSAGE_LENGTH], busy[SQL_MAX_MESSAGE_LENGTH / 4];
9858     char sflag[32], ntflag[32], lnflag[32];
9859 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9860     char tracef[SQL_MAX_MESSAGE_LENGTH];
9861 #endif
9862 
9863     if (dbc == SQL_NULL_HDBC) {
9864 	return SQL_INVALID_HANDLE;
9865     }
9866     if (drvcompl != SQL_DRIVER_COMPLETE &&
9867 	drvcompl != SQL_DRIVER_COMPLETE_REQUIRED &&
9868 	drvcompl != SQL_DRIVER_PROMPT &&
9869 	drvcompl != SQL_DRIVER_NOPROMPT) {
9870 	return SQL_NO_DATA;
9871     }
9872     d = (DBC *) dbc;
9873     if (d->sqlite) {
9874 	setstatd(d, -1, "connection already established", "08002");
9875 	return SQL_ERROR;
9876     }
9877     buf[0] = '\0';
9878     if (connInLen == SQL_NTS) {
9879 	len = sizeof (buf) - 1;
9880     } else {
9881 	len = min(connInLen, sizeof (buf) - 1);
9882     }
9883     if (connIn != NULL) {
9884 	strncpy(buf, (char *) connIn, len);
9885     }
9886     buf[len] = '\0';
9887     if (!buf[0]) {
9888 	setstatd(d, -1, "invalid connect attributes",
9889 		 (*d->ov3) ? "HY090" : "S1090");
9890 	return SQL_ERROR;
9891     }
9892     dsn[0] = '\0';
9893     getdsnattr(buf, "DSN", dsn, sizeof (dsn));
9894 
9895     /* special case: connIn is sole DSN value without keywords */
9896     if (!dsn[0] && !strchr(buf, ';') && !strchr(buf, '=')) {
9897 	strncpy(dsn, buf, sizeof (dsn) - 1);
9898 	dsn[sizeof (dsn) - 1] = '\0';
9899     }
9900 
9901     busy[0] = '\0';
9902     getdsnattr(buf, "timeout", busy, sizeof (busy));
9903 #ifndef WITHOUT_DRIVERMGR
9904     if (dsn[0] && !busy[0]) {
9905 	SQLGetPrivateProfileString(dsn, "timeout", "100000",
9906 				   busy, sizeof (busy), ODBC_INI);
9907     }
9908 #endif
9909     dbname[0] = '\0';
9910     getdsnattr(buf, "database", dbname, sizeof (dbname));
9911 #ifndef WITHOUT_DRIVERMGR
9912     if (dsn[0] && !dbname[0]) {
9913 	SQLGetPrivateProfileString(dsn, "database", "",
9914 				   dbname, sizeof (dbname), ODBC_INI);
9915     }
9916 #endif
9917     sflag[0] = '\0';
9918     getdsnattr(buf, "stepapi", sflag, sizeof (sflag));
9919 #ifndef WITHOUT_DRIVERMGR
9920     if (dsn[0] && !sflag[0]) {
9921 	SQLGetPrivateProfileString(dsn, "stepapi", "",
9922 				   sflag, sizeof (sflag), ODBC_INI);
9923     }
9924 #endif
9925     ntflag[0] = '\0';
9926     getdsnattr(buf, "notxn", ntflag, sizeof (ntflag));
9927 #ifndef WITHOUT_DRIVERMGR
9928     if (dsn[0] && !ntflag[0]) {
9929 	SQLGetPrivateProfileString(dsn, "notxn", "",
9930 				   ntflag, sizeof (ntflag), ODBC_INI);
9931     }
9932 #endif
9933     lnflag[0] = '\0';
9934     getdsnattr(buf, "longnames", lnflag, sizeof (lnflag));
9935 #ifndef WITHOUT_DRIVERMGR
9936     if (dsn[0] && !lnflag[0]) {
9937 	SQLGetPrivateProfileString(dsn, "longnames", "",
9938 				   lnflag, sizeof (lnflag), ODBC_INI);
9939     }
9940 #endif
9941     if (!dbname[0] && !dsn[0]) {
9942 	strcpy(dsn, "SQLite");
9943 	strncpy(dbname, buf, sizeof (dbname));
9944 	dbname[sizeof (dbname) - 1] = '\0';
9945     }
9946 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9947     tracef[0] = '\0';
9948     getdsnattr(buf, "tracefile", tracef, sizeof (tracef));
9949 #ifndef WITHOUT_DRIVERMGR
9950     if (dsn[0] && !tracef[0]) {
9951 	SQLGetPrivateProfileString(dsn, "tracefile", "",
9952 				   tracef, sizeof (tracef), ODBC_INI);
9953     }
9954 #endif
9955 #endif
9956     if (connOut || connOutLen) {
9957 	int count;
9958 
9959 	buf[0] = '\0';
9960 	count = snprintf(buf, sizeof (buf),
9961 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9962 			 "DSN=%s;Database=%s;StepAPI=%s;NoTXN=%s;"
9963 			 "Timeout=%s;LongNames=%s;Tracefile=%s",
9964 			 dsn, dbname, sflag, ntflag, busy, lnflag, tracef
9965 #else
9966 			 "DSN=%s;Database=%s;StepAPI=%s;NoTXN=%s;"
9967 			 "Timeout=%s;LongNames=%s",
9968 			 dsn, dbname, sflag, ntflag, busy, lnflag
9969 #endif
9970 			);
9971 	if (count < 0) {
9972 	    buf[sizeof (buf) - 1] = '\0';
9973 	}
9974 	len = min(connOutMax - 1, strlen(buf));
9975 	if (connOut) {
9976 	    strncpy((char *) connOut, buf, len);
9977 	    connOut[len] = '\0';
9978 	}
9979 	if (connOutLen) {
9980 	    *connOutLen = len;
9981 	}
9982     }
9983 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
9984     if (tracef[0] != '\0') {
9985 	d->trace = fopen(tracef, "a");
9986     }
9987 #endif
9988     d->longnames = getbool(lnflag);
9989     return dbopen(d, dbname, dsn, sflag, ntflag, busy);
9990 }
9991 #endif
9992 
9993 /**
9994  * Internal free function for HSTMT.
9995  * @param stmt statement handle
9996  * @result ODBC error code
9997  */
9998 
9999 static SQLRETURN
freestmt(SQLHSTMT stmt)10000 freestmt(SQLHSTMT stmt)
10001 {
10002     STMT *s;
10003     DBC *d;
10004 
10005     if (stmt == SQL_NULL_HSTMT) {
10006 	return SQL_INVALID_HANDLE;
10007     }
10008     s = (STMT *) stmt;
10009     freeresult(s, 1);
10010     freep(&s->query);
10011     d = (DBC *) s->dbc;
10012     if (d && d->magic == DBC_MAGIC) {
10013 	STMT *p, *n;
10014 
10015 	p = NULL;
10016 	n = d->stmt;
10017 	while (n) {
10018 	    if (n == s) {
10019 		break;
10020 	    }
10021 	    p = n;
10022 	    n = n->next;
10023 	}
10024 	if (n) {
10025 	    if (p) {
10026 		p->next = s->next;
10027 	    } else {
10028 		d->stmt = s->next;
10029 	    }
10030 	}
10031     }
10032     freeparams(s);
10033     freep(&s->bindparms);
10034     if (s->row_status0 != &s->row_status1) {
10035 	freep(&s->row_status0);
10036 	s->rowset_size = 1;
10037 	s->row_status0 = &s->row_status1;
10038     }
10039     xfree(s);
10040     return SQL_SUCCESS;
10041 }
10042 
10043 /**
10044  * Allocate HSTMT given HDBC (driver internal version).
10045  * @param dbc database connection handle
10046  * @param stmt pointer to statement handle
10047  * @result ODBC error code
10048  */
10049 
10050 static SQLRETURN
drvallocstmt(SQLHDBC dbc,SQLHSTMT * stmt)10051 drvallocstmt(SQLHDBC dbc, SQLHSTMT *stmt)
10052 {
10053     DBC *d;
10054     STMT *s, *sl, *pl;
10055 
10056     if (dbc == SQL_NULL_HDBC) {
10057 	return SQL_INVALID_HANDLE;
10058     }
10059     d = (DBC *) dbc;
10060     if (d->magic != DBC_MAGIC || stmt == NULL) {
10061 	return SQL_INVALID_HANDLE;
10062     }
10063     s = (STMT *) xmalloc(sizeof (STMT));
10064     if (s == NULL) {
10065 	*stmt = SQL_NULL_HSTMT;
10066 	return SQL_ERROR;
10067     }
10068     *stmt = (SQLHSTMT) s;
10069     memset(s, 0, sizeof (STMT));
10070     s->dbc = dbc;
10071     s->ov3 = d->ov3;
10072     s->nowchar[0] = d->nowchar;
10073     s->nowchar[1] = 0;
10074     s->longnames = d->longnames;
10075     s->curtype = d->curtype;
10076     s->row_status0 = &s->row_status1;
10077     s->rowset_size = 1;
10078     s->retr_data = SQL_RD_ON;
10079     s->bind_type = SQL_BIND_BY_COLUMN;
10080     s->bind_offs = NULL;
10081     s->paramset_size = 1;
10082     s->parm_bind_type = SQL_PARAM_BIND_BY_COLUMN;
10083 #ifdef _WIN64
10084     sprintf((char *) s->cursorname, "CUR_%I64X", (SQLUBIGINT) *stmt);
10085 #else
10086     sprintf((char *) s->cursorname, "CUR_%016lX", (long) *stmt);
10087 #endif
10088     sl = d->stmt;
10089     pl = NULL;
10090     while (sl) {
10091 	pl = sl;
10092 	sl = sl->next;
10093     }
10094     if (pl) {
10095 	pl->next = s;
10096     } else {
10097 	d->stmt = s;
10098     }
10099     return SQL_SUCCESS;
10100 }
10101 
10102 /**
10103  * Allocate HSTMT given HDBC.
10104  * @param dbc database connection handle
10105  * @param stmt pointer to statement handle
10106  * @result ODBC error code
10107  */
10108 
10109 SQLRETURN SQL_API
SQLAllocStmt(SQLHDBC dbc,SQLHSTMT * stmt)10110 SQLAllocStmt(SQLHDBC dbc, SQLHSTMT *stmt)
10111 {
10112     SQLRETURN ret;
10113 
10114     HDBC_LOCK(dbc);
10115     ret = drvallocstmt(dbc, stmt);
10116     HDBC_UNLOCK(dbc);
10117     return ret;
10118 }
10119 
10120 /**
10121  * Internal function to perform certain kinds of free/close on STMT.
10122  * @param stmt statement handle
10123  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
10124  * @result ODBC error code
10125  */
10126 
10127 static SQLRETURN
drvfreestmt(SQLHSTMT stmt,SQLUSMALLINT opt)10128 drvfreestmt(SQLHSTMT stmt, SQLUSMALLINT opt)
10129 {
10130     STMT *s;
10131     SQLRETURN ret = SQL_SUCCESS;
10132     SQLHDBC dbc;
10133 
10134     if (stmt == SQL_NULL_HSTMT) {
10135 	return SQL_INVALID_HANDLE;
10136     }
10137     HSTMT_LOCK(stmt);
10138     s = (STMT *) stmt;
10139     dbc = s->dbc;
10140     switch (opt) {
10141     case SQL_RESET_PARAMS:
10142 	freeparams(s);
10143 	break;
10144     case SQL_UNBIND:
10145 	unbindcols(s);
10146 	break;
10147     case SQL_CLOSE:
10148 	vm_end_if(s);
10149 	freeresult(s, 0);
10150 	break;
10151     case SQL_DROP:
10152 	vm_end_if(s);
10153 	ret = freestmt(stmt);
10154 	break;
10155     default:
10156 	setstat(s, -1, "unsupported option", (*s->ov3) ? "HYC00" : "S1C00");
10157 	ret = SQL_ERROR;
10158 	break;
10159     }
10160     HDBC_UNLOCK(dbc);
10161     return ret;
10162 }
10163 
10164 /**
10165  * Free HSTMT.
10166  * @param stmt statement handle
10167  * @param opt SQL_RESET_PARAMS, SQL_UNBIND, SQL_CLOSE, or SQL_DROP
10168  * @result ODBC error code
10169  */
10170 
10171 SQLRETURN SQL_API
SQLFreeStmt(SQLHSTMT stmt,SQLUSMALLINT opt)10172 SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT opt)
10173 {
10174     return drvfreestmt(stmt, opt);
10175 }
10176 
10177 /**
10178  * Cancel HSTMT closing cursor.
10179  * @param stmt statement handle
10180  * @result ODBC error code
10181  */
10182 
10183 SQLRETURN SQL_API
SQLCancel(SQLHSTMT stmt)10184 SQLCancel(SQLHSTMT stmt)
10185 {
10186     if (stmt != SQL_NULL_HSTMT) {
10187 	DBC *d = (DBC *) ((STMT *) stmt)->dbc;
10188 #if defined(_WIN32) || defined(_WIN64)
10189 	/* interrupt when other thread owns critical section */
10190 	if (d->magic == DBC_MAGIC && d->owner != GetCurrentThreadId() &&
10191 	    d->owner != 0) {
10192 	    d->busyint = 1;
10193 	    sqlite_interrupt(d->sqlite);
10194 	    return SQL_SUCCESS;
10195 	}
10196 #else
10197 	if (d->magic == DBC_MAGIC) {
10198 	    d->busyint = 1;
10199 	    sqlite_interrupt(d->sqlite);
10200 	}
10201 #endif
10202     }
10203     return drvfreestmt(stmt, SQL_CLOSE);
10204 }
10205 
10206 /**
10207  * Internal function to get cursor name of STMT.
10208  * @param stmt statement handle
10209  * @param cursor output buffer
10210  * @param buflen length of output buffer
10211  * @param lenp output length
10212  * @result ODBC error code
10213  */
10214 
10215 static SQLRETURN
drvgetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)10216 drvgetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
10217 		 SQLSMALLINT *lenp)
10218 {
10219     STMT *s;
10220 
10221     if (stmt == SQL_NULL_HSTMT) {
10222 	return SQL_INVALID_HANDLE;
10223     }
10224     s = (STMT *) stmt;
10225     if (lenp && !cursor) {
10226 	*lenp = strlen((char *) s->cursorname);
10227 	return SQL_SUCCESS;
10228     }
10229     if (cursor) {
10230 	if (buflen > 0) {
10231 	    strncpy((char *) cursor, (char *) s->cursorname, buflen - 1);
10232 	    cursor[buflen - 1] = '\0';
10233 	}
10234 	if (lenp) {
10235 	    *lenp = min(strlen((char *) s->cursorname), buflen - 1);
10236 	}
10237     }
10238     return SQL_SUCCESS;
10239 }
10240 
10241 #ifndef WINTERFACE
10242 /**
10243  * Get cursor name of STMT.
10244  * @param stmt statement handle
10245  * @param cursor output buffer
10246  * @param buflen length of output buffer
10247  * @param lenp output length
10248  * @result ODBC error code
10249  */
10250 
10251 SQLRETURN SQL_API
SQLGetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)10252 SQLGetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT buflen,
10253 		 SQLSMALLINT *lenp)
10254 {
10255     SQLRETURN ret;
10256 
10257     HSTMT_LOCK(stmt);
10258     ret = drvgetcursorname(stmt, cursor, buflen, lenp);
10259     HSTMT_UNLOCK(stmt);
10260     return ret;
10261 }
10262 #endif
10263 
10264 #ifdef WINTERFACE
10265 /**
10266  * Get cursor name of STMT (UNICODE version).
10267  * @param stmt statement handle
10268  * @param cursor output buffer
10269  * @param buflen length of output buffer
10270  * @param lenp output length
10271  * @result ODBC error code
10272  */
10273 
10274 SQLRETURN SQL_API
SQLGetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT buflen,SQLSMALLINT * lenp)10275 SQLGetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT buflen,
10276 		  SQLSMALLINT *lenp)
10277 {
10278     SQLRETURN ret;
10279     SQLSMALLINT len = 0;
10280 
10281     HSTMT_LOCK(stmt);
10282     ret = drvgetcursorname(stmt, (SQLCHAR *) cursor, buflen, &len);
10283     if (ret == SQL_SUCCESS) {
10284 	SQLWCHAR *c = NULL;
10285 
10286 	if (cursor) {
10287 	    c = uc_from_utf((SQLCHAR *) cursor, len);
10288 	    if (!c) {
10289 		ret = nomem((STMT *) stmt);
10290 		goto done;
10291 	    }
10292 	    c[len] = 0;
10293 	    len = uc_strlen(c);
10294 	    if (buflen > 0) {
10295 		uc_strncpy(cursor, c, buflen - 1);
10296 		cursor[buflen - 1] = 0;
10297 	    }
10298 	    uc_free(c);
10299 	}
10300 	if (lenp) {
10301 	    *lenp = min(len, buflen - 1);
10302 	}
10303     }
10304 done:
10305     HSTMT_UNLOCK(stmt);
10306     return ret;
10307 }
10308 #endif
10309 
10310 /**
10311  * Internal function to set cursor name on STMT.
10312  * @param stmt statement handle
10313  * @param cursor new cursor name
10314  * @param len length of cursor name or SQL_NTS
10315  * @result ODBC error code
10316  */
10317 
10318 static SQLRETURN
drvsetcursorname(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)10319 drvsetcursorname(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
10320 {
10321     STMT *s;
10322 
10323     if (stmt == SQL_NULL_HSTMT) {
10324 	return SQL_INVALID_HANDLE;
10325     }
10326     s = (STMT *) stmt;
10327     if (!cursor ||
10328 	!((cursor[0] >= 'A' && cursor[0] <= 'Z') ||
10329 	  (cursor[0] >= 'a' && cursor[0] <= 'z'))) {
10330 	setstat(s, -1, "invalid cursor name", (*s->ov3) ? "HYC00" : "S1C00");
10331 	return SQL_ERROR;
10332     }
10333     if (len == SQL_NTS) {
10334 	len = sizeof (s->cursorname) - 1;
10335     } else {
10336 	len = min(sizeof (s->cursorname) - 1, len);
10337     }
10338     strncpy((char *) s->cursorname, (char *) cursor, len);
10339     s->cursorname[len] = '\0';
10340     return SQL_SUCCESS;
10341 }
10342 
10343 #ifndef WINTERFACE
10344 /**
10345  * Set cursor name on STMT.
10346  * @param stmt statement handle
10347  * @param cursor new cursor name
10348  * @param len length of cursor name or SQL_NTS
10349  * @result ODBC error code
10350  */
10351 
10352 SQLRETURN SQL_API
SQLSetCursorName(SQLHSTMT stmt,SQLCHAR * cursor,SQLSMALLINT len)10353 SQLSetCursorName(SQLHSTMT stmt, SQLCHAR *cursor, SQLSMALLINT len)
10354 {
10355     SQLRETURN ret;
10356 
10357     HSTMT_LOCK(stmt);
10358     ret = drvsetcursorname(stmt, cursor, len);
10359     HSTMT_UNLOCK(stmt);
10360     return ret;
10361 }
10362 #endif
10363 
10364 #ifdef WINTERFACE
10365 /**
10366  * Set cursor name on STMT (UNICODE version).
10367  * @param stmt statement handle
10368  * @param cursor new cursor name
10369  * @param len length of cursor name or SQL_NTS
10370  * @result ODBC error code
10371  */
10372 
10373 SQLRETURN SQL_API
SQLSetCursorNameW(SQLHSTMT stmt,SQLWCHAR * cursor,SQLSMALLINT len)10374 SQLSetCursorNameW(SQLHSTMT stmt, SQLWCHAR *cursor, SQLSMALLINT len)
10375 {
10376     char *c = NULL;
10377     SQLRETURN ret;
10378 
10379     HSTMT_LOCK(stmt);
10380     if (cursor) {
10381 	c = uc_to_utf_c(cursor, len);
10382 	if (!c) {
10383 	    ret = nomem((STMT *) stmt);
10384 	    goto done;
10385 	}
10386     }
10387     ret = drvsetcursorname(stmt, (SQLCHAR *) c, SQL_NTS);
10388 done:
10389     HSTMT_UNLOCK(stmt);
10390     uc_free(c);
10391     return ret;
10392 }
10393 #endif
10394 
10395 /**
10396  * Close open cursor.
10397  * @param stmt statement handle
10398  * @return ODBC error code
10399  */
10400 
10401 SQLRETURN SQL_API
SQLCloseCursor(SQLHSTMT stmt)10402 SQLCloseCursor(SQLHSTMT stmt)
10403 {
10404     return drvfreestmt(stmt, SQL_CLOSE);
10405 }
10406 
10407 /**
10408  * Allocate a HENV, HDBC, or HSTMT handle.
10409  * @param type handle type
10410  * @param input input handle (HENV, HDBC)
10411  * @param output pointer to output handle (HENV, HDBC, HSTMT)
10412  * @result ODBC error code
10413  */
10414 
10415 SQLRETURN SQL_API
SQLAllocHandle(SQLSMALLINT type,SQLHANDLE input,SQLHANDLE * output)10416 SQLAllocHandle(SQLSMALLINT type, SQLHANDLE input, SQLHANDLE *output)
10417 {
10418     SQLRETURN ret;
10419 
10420     switch (type) {
10421     case SQL_HANDLE_ENV:
10422 	ret = drvallocenv((SQLHENV *) output);
10423 	if (ret == SQL_SUCCESS) {
10424 	    ENV *e = (ENV *) *output;
10425 
10426 	    if (e && e->magic == ENV_MAGIC) {
10427 		e->ov3 = 1;
10428 	    }
10429 	}
10430 	return ret;
10431     case SQL_HANDLE_DBC:
10432 	return drvallocconnect((SQLHENV) input, (SQLHDBC *) output);
10433     case SQL_HANDLE_STMT:
10434 	HDBC_LOCK((SQLHDBC) input);
10435 	ret = drvallocstmt((SQLHDBC) input, (SQLHSTMT *) output);
10436 	HDBC_UNLOCK((SQLHDBC) input);
10437 	return ret;
10438     }
10439     return SQL_ERROR;
10440 }
10441 
10442 /**
10443  * Free a HENV, HDBC, or HSTMT handle.
10444  * @param type handle type
10445  * @param h handle (HENV, HDBC, or HSTMT)
10446  * @result ODBC error code
10447  */
10448 
10449 SQLRETURN SQL_API
SQLFreeHandle(SQLSMALLINT type,SQLHANDLE h)10450 SQLFreeHandle(SQLSMALLINT type, SQLHANDLE h)
10451 {
10452     switch (type) {
10453     case SQL_HANDLE_ENV:
10454 	return drvfreeenv((SQLHENV) h);
10455     case SQL_HANDLE_DBC:
10456 	return drvfreeconnect((SQLHDBC) h);
10457     case SQL_HANDLE_STMT:
10458 	return drvfreestmt((SQLHSTMT) h, SQL_DROP);
10459     }
10460     return SQL_ERROR;
10461 }
10462 
10463 /**
10464  * Free dynamically allocated column descriptions of STMT.
10465  * @param s statement pointer
10466  */
10467 
10468 static void
freedyncols(STMT * s)10469 freedyncols(STMT *s)
10470 {
10471     if (s->dyncols) {
10472 	int i;
10473 
10474 	for (i = 0; i < s->dcols; i++) {
10475 	    freep(&s->dyncols[i].typename);
10476 	}
10477 	if (s->cols == s->dyncols) {
10478 	    s->cols = NULL;
10479 	    s->ncols = 0;
10480 	}
10481 	freep(&s->dyncols);
10482     }
10483     s->dcols = 0;
10484 }
10485 
10486 /**
10487  * Free statement's result.
10488  * @param s statement pointer
10489  * @param clrcols flag to clear column information
10490  *
10491  * The result rows are free'd using the rowfree function pointer.
10492  * If clrcols is greater than zero, then column bindings and dynamic column
10493  * descriptions are free'd.
10494  * If clrcols is less than zero, then dynamic column descriptions are free'd.
10495  */
10496 
10497 static void
freeresult(STMT * s,int clrcols)10498 freeresult(STMT *s, int clrcols)
10499 {
10500 #if (HAVE_ENCDEC)
10501     freep(&s->bincache);
10502     freep(&s->hexcache);
10503     s->bincell = NULL;
10504 #endif
10505     if (s->rows) {
10506 	if (s->rowfree) {
10507 	    s->rowfree(s->rows);
10508 	    s->rowfree = NULL;
10509 	}
10510 	s->rows = NULL;
10511     }
10512     s->nrows = -1;
10513     if (clrcols > 0) {
10514 	freep(&s->bindcols);
10515 	s->nbindcols = 0;
10516     }
10517     if (clrcols) {
10518 	freedyncols(s);
10519 	s->cols = NULL;
10520 	s->ncols = 0;
10521 	s->nowchar[1] = 0;
10522     }
10523 }
10524 
10525 /**
10526  * Reset bound columns to unbound state.
10527  * @param s statement pointer
10528  */
10529 
10530 static void
unbindcols(STMT * s)10531 unbindcols(STMT *s)
10532 {
10533     int i;
10534 
10535     for (i = 0; s->bindcols && i < s->nbindcols; i++) {
10536 	s->bindcols[i].type = SQL_UNKNOWN_TYPE;
10537 	s->bindcols[i].max = 0;
10538 	s->bindcols[i].lenp = NULL;
10539 	s->bindcols[i].valp = NULL;
10540 	s->bindcols[i].index = i;
10541 	s->bindcols[i].offs = 0;
10542     }
10543 }
10544 
10545 /**
10546  * Reallocate space for bound columns.
10547  * @param s statement pointer
10548  * @param ncols number of columns
10549  * @result ODBC error code
10550  */
10551 
10552 static SQLRETURN
mkbindcols(STMT * s,int ncols)10553 mkbindcols(STMT *s, int ncols)
10554 {
10555     if (s->bindcols) {
10556 	if (s->nbindcols < ncols) {
10557 	    int i;
10558 	    BINDCOL *bindcols =
10559 		xrealloc(s->bindcols, ncols * sizeof (BINDCOL));
10560 
10561 	    if (!bindcols) {
10562 		return nomem(s);
10563 	    }
10564 	    for (i = s->nbindcols; i < ncols; i++) {
10565 		bindcols[i].type = SQL_UNKNOWN_TYPE;
10566 		bindcols[i].max = 0;
10567 		bindcols[i].lenp = NULL;
10568 		bindcols[i].valp = NULL;
10569 		bindcols[i].index = i;
10570 		bindcols[i].offs = 0;
10571 	    }
10572 	    s->bindcols = bindcols;
10573 	    s->nbindcols = ncols;
10574 	}
10575     } else if (ncols > 0) {
10576 	s->bindcols = (BINDCOL *) xmalloc(ncols * sizeof (BINDCOL));
10577 	if (!s->bindcols) {
10578 	    return nomem(s);
10579 	}
10580 	s->nbindcols = ncols;
10581 	unbindcols(s);
10582     }
10583     return SQL_SUCCESS;
10584 }
10585 
10586 /**
10587  * Internal function to retrieve row data, used by SQLFetch() and
10588  * friends and SQLGetData().
10589  * @param s statement pointer
10590  * @param col column number, 0 based
10591  * @param otype output data type
10592  * @param val output buffer
10593  * @param len length of output buffer
10594  * @param lenp output length
10595  * @param partial flag for partial data retrieval
10596  * @result ODBC error code
10597  */
10598 
10599 static SQLRETURN
getrowdata(STMT * s,SQLUSMALLINT col,SQLSMALLINT otype,SQLPOINTER val,SQLLEN len,SQLLEN * lenp,int partial)10600 getrowdata(STMT *s, SQLUSMALLINT col, SQLSMALLINT otype,
10601 	   SQLPOINTER val, SQLLEN len, SQLLEN *lenp, int partial)
10602 {
10603     char **data, valdummy[16];
10604     SQLLEN dummy;
10605     SQLINTEGER *ilenp = NULL;
10606     int valnull = 0;
10607     int type = otype;
10608     SQLRETURN sret = SQL_NO_DATA;
10609 
10610     if (!lenp) {
10611 	lenp = &dummy;
10612     }
10613     /* workaround for JDK 1.7.0 on x86_64 */
10614     if (((SQLINTEGER *) lenp) + 1 == (SQLINTEGER *) val) {
10615 	ilenp = (SQLINTEGER *) lenp;
10616 	lenp = &dummy;
10617     }
10618     if (col >= s->ncols) {
10619 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
10620 	return SQL_ERROR;
10621     }
10622     if (s->retr_data != SQL_RD_ON) {
10623 	return SQL_SUCCESS;
10624     }
10625     if (!s->rows) {
10626 	*lenp = SQL_NULL_DATA;
10627 	goto done;
10628     }
10629     if (s->rowp < 0 || s->rowp >= s->nrows) {
10630 	*lenp = SQL_NULL_DATA;
10631 	goto done;
10632     }
10633     type = mapdeftype(type, s->cols[col].type, s->cols[col].nosign ? 1 : 0,
10634 		      s->nowchar[0]);
10635 
10636 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
10637     /* MS Access hack part 3 (map SQL_C_DEFAULT to SQL_C_CHAR) */
10638     if (type == SQL_C_WCHAR && otype == SQL_C_DEFAULT) {
10639 	type = SQL_C_CHAR;
10640     }
10641 #endif
10642 
10643 #if (HAVE_ENCDEC)
10644     if (type == SQL_C_CHAR) {
10645 	switch (s->cols[col].type) {
10646 	case SQL_BINARY:
10647 	case SQL_VARBINARY:
10648 	case SQL_LONGVARBINARY:
10649 	    type = SQL_C_BINARY;
10650 	    break;
10651 	}
10652 #ifdef WCHARSUPPORT
10653     } else if (type == SQL_C_WCHAR) {
10654 	switch (s->cols[col].type) {
10655 	case SQL_BINARY:
10656 	case SQL_VARBINARY:
10657 	case SQL_LONGVARBINARY:
10658 	    type = SQL_C_BINARY;
10659 	    break;
10660 	}
10661 #endif
10662     }
10663 #endif
10664     data = s->rows + s->ncols + (s->rowp * s->ncols) + col;
10665     if (!val) {
10666 	valnull = 1;
10667 	val = (SQLPOINTER) valdummy;
10668     }
10669     if (*data == NULL) {
10670 	*lenp = SQL_NULL_DATA;
10671 	switch (type) {
10672 	case SQL_C_UTINYINT:
10673 	case SQL_C_TINYINT:
10674 	case SQL_C_STINYINT:
10675 #ifdef SQL_BIT
10676 	case SQL_C_BIT:
10677 #endif
10678 	    *((char *) val) = 0;
10679 	    break;
10680 	case SQL_C_USHORT:
10681 	case SQL_C_SHORT:
10682 	case SQL_C_SSHORT:
10683 	    *((short *) val) = 0;
10684 	    break;
10685 	case SQL_C_ULONG:
10686 	case SQL_C_LONG:
10687 	case SQL_C_SLONG:
10688 	    *((SQLINTEGER *) val) = 0;
10689 	    break;
10690 	case SQL_C_FLOAT:
10691 	    *((float *) val) = 0;
10692 	    break;
10693 	case SQL_C_DOUBLE:
10694 	    *((double *) val) = 0;
10695 	    break;
10696 	case SQL_C_BINARY:
10697 	case SQL_C_CHAR:
10698 #ifdef WCHARSUPPORT
10699 	case SQL_C_WCHAR:
10700 	    if (type == SQL_C_WCHAR) {
10701 		*((SQLWCHAR *) val) = '\0';
10702 	    } else {
10703 		*((char *) val) = '\0';
10704 	    }
10705 #else
10706 	    *((char *) val) = '\0';
10707 #endif
10708 	    break;
10709 #ifdef SQL_C_TYPE_DATE
10710 	case SQL_C_TYPE_DATE:
10711 #endif
10712 	case SQL_C_DATE:
10713 	    memset((DATE_STRUCT *) val, 0, sizeof (DATE_STRUCT));
10714 	    break;
10715 #ifdef SQL_C_TYPE_TIME
10716 	case SQL_C_TYPE_TIME:
10717 #endif
10718 	case SQL_C_TIME:
10719 	    memset((TIME_STRUCT *) val, 0, sizeof (TIME_STRUCT));
10720 	    break;
10721 #ifdef SQL_C_TYPE_TIMESTAMP
10722 	case SQL_C_TYPE_TIMESTAMP:
10723 #endif
10724 	case SQL_C_TIMESTAMP:
10725 	    memset((TIMESTAMP_STRUCT *) val, 0, sizeof (TIMESTAMP_STRUCT));
10726 	    break;
10727 	default:
10728 	    return SQL_ERROR;
10729 	}
10730     } else {
10731 	char *endp = NULL;
10732 
10733 	switch (type) {
10734 	case SQL_C_UTINYINT:
10735 	case SQL_C_TINYINT:
10736 	case SQL_C_STINYINT:
10737 	    *((char *) val) = strtol(*data, &endp, 0);
10738 	    if (endp && endp == *data) {
10739 		*lenp = SQL_NULL_DATA;
10740 	    } else {
10741 		*lenp = sizeof (char);
10742 	    }
10743 	    break;
10744 #ifdef SQL_BIT
10745 	case SQL_C_BIT:
10746 	    *((char *) val) = getbool(*data);
10747 	    *lenp = sizeof (char);
10748 	    break;
10749 #endif
10750 	case SQL_C_USHORT:
10751 	case SQL_C_SHORT:
10752 	case SQL_C_SSHORT:
10753 	    *((short *) val) = strtol(*data, &endp, 0);
10754 	    if (endp && endp == *data) {
10755 		*lenp = SQL_NULL_DATA;
10756 	    } else {
10757 		*lenp = sizeof (short);
10758 	    }
10759 	    break;
10760 	case SQL_C_ULONG:
10761 	case SQL_C_LONG:
10762 	case SQL_C_SLONG:
10763 	    *((SQLINTEGER *) val) = strtol(*data, &endp, 0);
10764 	    if (endp && endp == *data) {
10765 		*lenp = SQL_NULL_DATA;
10766 	    } else {
10767 		*lenp = sizeof (SQLINTEGER);
10768 	    }
10769 	    break;
10770 	case SQL_C_FLOAT:
10771 	    *((float *) val) = ln_strtod(*data, &endp);
10772 	    if (endp && endp == *data) {
10773 		*lenp = SQL_NULL_DATA;
10774 	    } else {
10775 		*lenp = sizeof (float);
10776 	    }
10777 	    break;
10778 	case SQL_C_DOUBLE:
10779 	    *((double *) val) = ln_strtod(*data, &endp);
10780 	    if (endp && endp == *data) {
10781 		*lenp = SQL_NULL_DATA;
10782 	    } else {
10783 		*lenp = sizeof (double);
10784 	    }
10785 	    break;
10786 	case SQL_C_BINARY:
10787 #if (HAVE_ENCDEC)
10788 	{
10789 	    int dlen, offs = 0;
10790 	    char *bin;
10791 
10792 	    if (*data == s->bincell && s->bincache) {
10793 		bin = s->bincache;
10794 		dlen = s->binlen;
10795 	    } else {
10796 		freep(&s->bincache);
10797 		freep(&s->hexcache);
10798 		s->bincell = NULL;
10799 		dlen = strlen(*data);
10800 		bin = xmalloc(dlen + 1);
10801 		if (!bin) {
10802 		    return nomem(s);
10803 		}
10804 		dlen = sqlite_decode_binary((unsigned char *) *data,
10805 					    (unsigned char *) bin);
10806 		if (dlen < 0) {
10807 		    freep(&bin);
10808 		    setstat(s, -1, "error decoding binary data",
10809 			    (*s->ov3) ? "HY000" : "S1000");
10810 		    return SQL_ERROR;
10811 		}
10812 		s->bincache = bin;
10813 		s->binlen = dlen;
10814 		s->bincell = *data;
10815 	    }
10816 	    if (partial && len && s->bindcols) {
10817 		if (s->bindcols[col].offs >= dlen) {
10818 		    *lenp = 0;
10819 		    if (!dlen && s->bindcols[col].offs == dlen) {
10820 			s->bindcols[col].offs = 1;
10821 			sret = SQL_SUCCESS;
10822 			goto done;
10823 		    }
10824 		    s->bindcols[col].offs = 0;
10825 		    sret = SQL_NO_DATA;
10826 		    goto done;
10827 		}
10828 		offs = s->bindcols[col].offs;
10829 		dlen -= offs;
10830 	    }
10831 	    if (val && !valnull && len) {
10832 		memcpy(val, bin + offs, min(len, dlen));
10833 	    }
10834 	    if (valnull || len < 1) {
10835 		*lenp = dlen;
10836 	    } else {
10837 		*lenp = min(len, dlen);
10838 		if (*lenp == len && *lenp != dlen) {
10839 		    *lenp = SQL_NO_TOTAL;
10840 		}
10841 	    }
10842 	    if (partial && len && s->bindcols) {
10843 		if (*lenp == SQL_NO_TOTAL) {
10844 		    *lenp = dlen;
10845 		    s->bindcols[col].offs += len;
10846 		    setstat(s, -1, "data right truncated", "01004");
10847 		    if (s->bindcols[col].lenp) {
10848 			*s->bindcols[col].lenp = dlen;
10849 		    }
10850 		    sret = SQL_SUCCESS_WITH_INFO;
10851 		    goto done;
10852 		}
10853 		s->bindcols[col].offs += *lenp;
10854 	    }
10855 	    if (*lenp == SQL_NO_TOTAL) {
10856 		*lenp = dlen;
10857 		setstat(s, -1, "data right truncated", "01004");
10858 		sret = SQL_SUCCESS_WITH_INFO;
10859 		goto done;
10860 	    }
10861 	    break;
10862 	}
10863 #endif
10864 #ifdef WCHARSUPPORT
10865 	case SQL_C_WCHAR:
10866 #endif
10867 	case SQL_C_CHAR: {
10868 	    int doz, zlen = len - 1;
10869 	    int dlen = strlen(*data);
10870 	    int offs = 0;
10871 #ifdef WCHARSUPPORT
10872 	    SQLWCHAR *ucdata = NULL;
10873 #endif
10874 
10875 #if (defined(_WIN32) || defined(_WIN64)) && defined(WINTERFACE)
10876 	    /* MS Access hack part 2 (reserved error -7748) */
10877 	    if (!valnull &&
10878 		(s->cols == statSpec2P || s->cols == statSpec3P) &&
10879 		type == SQL_C_WCHAR) {
10880 		if (len > 0 && len <= sizeof (SQLWCHAR)) {
10881 		    ((char *) val)[0] = data[0][0];
10882 		    memset((char *) val + 1, 0, len - 1);
10883 		    *lenp = 1;
10884 		    sret = SQL_SUCCESS;
10885 		    goto done;
10886 		}
10887 	    }
10888 #endif
10889 
10890 #ifdef WCHARSUPPORT
10891 	    switch (type) {
10892 	    case SQL_C_CHAR:
10893 		doz = 1;
10894 		break;
10895 	    case SQL_C_WCHAR:
10896 		doz = sizeof (SQLWCHAR);
10897 		break;
10898 	    default:
10899 		doz = 0;
10900 		break;
10901 	    }
10902 	    if (type == SQL_C_WCHAR) {
10903 		ucdata = uc_from_utf((SQLCHAR *) *data, dlen);
10904 		if (!ucdata) {
10905 		    return nomem(s);
10906 		}
10907 		dlen = uc_strlen(ucdata) * sizeof (SQLWCHAR);
10908 	    }
10909 #else
10910 	    doz = type == SQL_C_CHAR ? 1 : 0;
10911 #endif
10912 	    if (partial && len && s->bindcols) {
10913 		if (s->bindcols[col].offs >= dlen) {
10914 #ifdef WCHARSUPPORT
10915 		    uc_free(ucdata);
10916 #endif
10917 		    *lenp = 0;
10918 		    if (doz && val) {
10919 #ifdef WCHARSUPPORT
10920 			if (type == SQL_C_WCHAR) {
10921 			    ((SQLWCHAR *) val)[0] = 0;
10922 			} else {
10923 			    ((char *) val)[0] = '\0';
10924 			}
10925 #else
10926 			((char *) val)[0] = '\0';
10927 #endif
10928 		    }
10929 		    if (!dlen && s->bindcols[col].offs == dlen) {
10930 			s->bindcols[col].offs = 1;
10931 			sret = SQL_SUCCESS;
10932 			goto done;
10933 		    }
10934 		    s->bindcols[col].offs = 0;
10935 		    sret = SQL_NO_DATA;
10936 		    goto done;
10937 		}
10938 		offs = s->bindcols[col].offs;
10939 		dlen -= offs;
10940 	    }
10941 	    if (val && !valnull && len) {
10942 #ifdef WCHARSUPPORT
10943 		if (type == SQL_C_WCHAR) {
10944 		    uc_strncpy(val, ucdata + offs / sizeof (SQLWCHAR),
10945 			       (len - doz) / sizeof (SQLWCHAR));
10946 		} else {
10947 		    strncpy(val, *data + offs, len - doz);
10948 		}
10949 #else
10950 		strncpy(val, *data + offs, len - doz);
10951 #endif
10952 	    }
10953 	    if (valnull || len < 1) {
10954 		*lenp = dlen;
10955 	    } else {
10956 		*lenp = min(len - doz, dlen);
10957 		if (*lenp == len - doz && *lenp != dlen) {
10958 		    *lenp = SQL_NO_TOTAL;
10959 		} else if (*lenp < zlen) {
10960 		    zlen = *lenp;
10961 		}
10962 	    }
10963 	    if (len && !valnull && doz) {
10964 #ifdef WCHARSUPPORT
10965 		if (type == SQL_C_WCHAR) {
10966 		    ((SQLWCHAR *) val)[zlen / sizeof (SQLWCHAR)] = 0;
10967 		} else {
10968 		    ((char *) val)[zlen] = '\0';
10969 		}
10970 #else
10971 		((char *) val)[zlen] = '\0';
10972 #endif
10973 	    }
10974 #ifdef WCHARSUPPORT
10975 	    uc_free(ucdata);
10976 #endif
10977 	    if (partial && len && s->bindcols) {
10978 		if (*lenp == SQL_NO_TOTAL) {
10979 		    *lenp = dlen;
10980 		    s->bindcols[col].offs += len - doz;
10981 		    setstat(s, -1, "data right truncated", "01004");
10982 		    if (s->bindcols[col].lenp) {
10983 			*s->bindcols[col].lenp = dlen;
10984 		    }
10985 		    sret = SQL_SUCCESS_WITH_INFO;
10986 		    goto done;
10987 		}
10988 		s->bindcols[col].offs += *lenp;
10989 	    }
10990 	    if (*lenp == SQL_NO_TOTAL) {
10991 		*lenp = dlen;
10992 		setstat(s, -1, "data right truncated", "01004");
10993 		sret = SQL_SUCCESS_WITH_INFO;
10994 		goto done;
10995 	    }
10996 	    break;
10997 	}
10998 #ifdef SQL_C_TYPE_DATE
10999 	case SQL_C_TYPE_DATE:
11000 #endif
11001 	case SQL_C_DATE:
11002 	    if (str2date(*data, (DATE_STRUCT *) val) < 0) {
11003 		*lenp = SQL_NULL_DATA;
11004 	    } else {
11005 		*lenp = sizeof (DATE_STRUCT);
11006 	    }
11007 	    break;
11008 #ifdef SQL_C_TYPE_TIME
11009 	case SQL_C_TYPE_TIME:
11010 #endif
11011 	case SQL_C_TIME:
11012 	    if (str2time(*data, (TIME_STRUCT *) val) < 0) {
11013 		*lenp = SQL_NULL_DATA;
11014 	    } else {
11015 		*lenp = sizeof (TIME_STRUCT);
11016 	    }
11017 	    break;
11018 #ifdef SQL_C_TYPE_TIMESTAMP
11019 	case SQL_C_TYPE_TIMESTAMP:
11020 #endif
11021 	case SQL_C_TIMESTAMP:
11022 	    if (str2timestamp(*data, (TIMESTAMP_STRUCT *) val) < 0) {
11023 		*lenp = SQL_NULL_DATA;
11024 	    } else {
11025 		*lenp = sizeof (TIMESTAMP_STRUCT);
11026 	    }
11027 	    switch (s->cols[col].prec) {
11028 	    case 0:
11029 		((TIMESTAMP_STRUCT *) val)->fraction = 0;
11030 		break;
11031 	    case 1:
11032 		((TIMESTAMP_STRUCT *) val)->fraction /= 100000000;
11033 		((TIMESTAMP_STRUCT *) val)->fraction *= 100000000;
11034 		break;
11035 	    case 2:
11036 		((TIMESTAMP_STRUCT *) val)->fraction /= 10000000;
11037 		((TIMESTAMP_STRUCT *) val)->fraction *= 10000000;
11038 		break;
11039 	    }
11040 	    break;
11041 	default:
11042 	    return SQL_ERROR;
11043 	}
11044     }
11045     sret = SQL_SUCCESS;
11046 done:
11047     if (ilenp) {
11048 	*ilenp = *lenp;
11049     }
11050     return sret;
11051 }
11052 
11053 /**
11054  * Internal bind C variable to column of result set.
11055  * @param stmt statement handle
11056  * @param col column number, starting at 1
11057  * @param type output type
11058  * @param val output buffer
11059  * @param max length of output buffer
11060  * @param lenp output length pointer
11061  * @result ODBC error code
11062  */
11063 
11064 static SQLRETURN
drvbindcol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)11065 drvbindcol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
11066 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
11067 {
11068     STMT *s;
11069     int sz = 0;
11070 
11071     if (stmt == SQL_NULL_HSTMT) {
11072 	return SQL_INVALID_HANDLE;
11073     }
11074     s = (STMT *) stmt;
11075     if (col < 1) {
11076 	if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
11077 	    s->bkmrkcol.type = val ? type : SQL_UNKNOWN_TYPE;
11078 	    s->bkmrkcol.max = val ? sizeof (SQLINTEGER) : 0;
11079 	    s->bkmrkcol.lenp = val ? lenp : 0;
11080 	    s->bkmrkcol.valp = val;
11081 	    s->bkmrkcol.offs = 0;
11082 	    if (val && lenp) {
11083 		*lenp = 0;
11084 	    }
11085 	    return SQL_SUCCESS;
11086 	}
11087 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
11088 	return SQL_ERROR;
11089     }
11090     if (mkbindcols(s, col) != SQL_SUCCESS) {
11091 	return SQL_ERROR;
11092     }
11093     --col;
11094     if (type == SQL_C_DEFAULT) {
11095 	type = mapdeftype(type, s->cols[col].type, 0,
11096 			  s->nowchar[0] || s->nowchar[1]);
11097     }
11098     switch (type) {
11099     case SQL_C_LONG:
11100     case SQL_C_ULONG:
11101     case SQL_C_SLONG:
11102 	sz = sizeof (SQLINTEGER);
11103 	break;
11104     case SQL_C_TINYINT:
11105     case SQL_C_UTINYINT:
11106     case SQL_C_STINYINT:
11107 	sz = sizeof (SQLCHAR);
11108 	break;
11109     case SQL_C_SHORT:
11110     case SQL_C_USHORT:
11111     case SQL_C_SSHORT:
11112 	sz = sizeof (short);
11113 	break;
11114     case SQL_C_FLOAT:
11115 	sz = sizeof (SQLFLOAT);
11116 	break;
11117     case SQL_C_DOUBLE:
11118 	sz = sizeof (SQLDOUBLE);
11119 	break;
11120     case SQL_C_TIMESTAMP:
11121 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
11122 	break;
11123     case SQL_C_TIME:
11124 	sz = sizeof (SQL_TIME_STRUCT);
11125 	break;
11126     case SQL_C_DATE:
11127 	sz = sizeof (SQL_DATE_STRUCT);
11128 	break;
11129     case SQL_C_CHAR:
11130 	break;
11131 #ifdef WCHARSUPPORT
11132     case SQL_C_WCHAR:
11133 	break;
11134 #endif
11135 #ifdef SQL_C_TYPE_DATE
11136     case SQL_C_TYPE_DATE:
11137 	sz = sizeof (SQL_DATE_STRUCT);
11138 	break;
11139 #endif
11140 #ifdef SQL_C_TYPE_TIME
11141     case SQL_C_TYPE_TIME:
11142 	sz = sizeof (SQL_TIME_STRUCT);
11143 	break;
11144 #endif
11145 #ifdef SQL_C_TYPE_TIMESTAMP
11146     case SQL_C_TYPE_TIMESTAMP:
11147 	sz = sizeof (SQL_TIMESTAMP_STRUCT);
11148 	break;
11149 #endif
11150 #ifdef SQL_BIT
11151     case SQL_C_BIT:
11152 	sz = sizeof (SQLCHAR);
11153 	break;
11154 #endif
11155 #if (HAVE_ENCDEC)
11156     case SQL_C_BINARY:
11157 	break;
11158 #endif
11159     default:
11160 	if (val == NULL) {
11161 	    /* fall through, unbinding column */
11162 	    break;
11163 	}
11164 	setstat(s, -1, "invalid type %d", "HY003", type);
11165 	return SQL_ERROR;
11166     }
11167     if (val == NULL) {
11168 	/* unbind column */
11169 	s->bindcols[col].type = SQL_UNKNOWN_TYPE;
11170 	s->bindcols[col].max = 0;
11171 	s->bindcols[col].lenp = NULL;
11172 	s->bindcols[col].valp = NULL;
11173 	s->bindcols[col].offs = 0;
11174     } else {
11175 	if (sz == 0 && max < 0) {
11176 	    setstat(s, -1, "invalid length", "HY090");
11177 	    return SQL_ERROR;
11178 	}
11179 	s->bindcols[col].type = type;
11180 	s->bindcols[col].max = (sz == 0) ? max : sz;
11181 	s->bindcols[col].lenp = lenp;
11182 	s->bindcols[col].valp = val;
11183 	s->bindcols[col].offs = 0;
11184 	if (lenp) {
11185 	    *lenp = 0;
11186 	}
11187     }
11188     return SQL_SUCCESS;
11189 }
11190 
11191 /**
11192  * Bind C variable to column of result set.
11193  * @param stmt statement handle
11194  * @param col column number, starting at 1
11195  * @param type output type
11196  * @param val output buffer
11197  * @param max length of output buffer
11198  * @param lenp output length pointer
11199  * @result ODBC error code
11200  */
11201 
11202 SQLRETURN SQL_API
SQLBindCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN max,SQLLEN * lenp)11203 SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
11204 	   SQLPOINTER val, SQLLEN max, SQLLEN *lenp)
11205 {
11206     SQLRETURN ret;
11207 
11208     HSTMT_LOCK(stmt);
11209     ret = drvbindcol(stmt, col, type, val, max, lenp);
11210     HSTMT_UNLOCK(stmt);
11211     return ret;
11212 }
11213 
11214 /**
11215  * Columns for result set of SQLTables().
11216  */
11217 
11218 static COL tableSpec2[] = {
11219     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
11220     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
11221     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
11222     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
11223     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
11224 };
11225 
11226 static COL tableSpec3[] = {
11227     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
11228     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
11229     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
11230     { "SYSTEM", "COLUMN", "TABLE_TYPE", SCOL_VARCHAR, 50 },
11231     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 }
11232 };
11233 
11234 /**
11235  * Retrieve information on tables and/or views.
11236  * @param stmt statement handle
11237  * @param cat catalog name/pattern or NULL
11238  * @param catLen length of catalog name/pattern or SQL_NTS
11239  * @param schema schema name/pattern or NULL
11240  * @param schemaLen length of schema name/pattern or SQL_NTS
11241  * @param table table name/pattern or NULL
11242  * @param tableLen length of table name/pattern or SQL_NTS
11243  * @param type types of tables string or NULL
11244  * @param typeLen length of types of tables string or SQL_NTS
11245  * @result ODBC error code
11246  */
11247 
11248 static SQLRETURN
drvtables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)11249 drvtables(SQLHSTMT stmt,
11250 	  SQLCHAR *cat, SQLSMALLINT catLen,
11251 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
11252 	  SQLCHAR *table, SQLSMALLINT tableLen,
11253 	  SQLCHAR *type, SQLSMALLINT typeLen)
11254 {
11255     SQLRETURN ret;
11256     STMT *s;
11257     DBC *d;
11258     int ncols, asize, rc, size, npatt;
11259     char *errp = NULL, tname[512];
11260     char *where = "(type = 'table' or type = 'view')";
11261 
11262     ret = mkresultset(stmt, tableSpec2, array_size(tableSpec2),
11263 		      tableSpec3, array_size(tableSpec3), &asize);
11264     if (ret != SQL_SUCCESS) {
11265 	return ret;
11266     }
11267     s = (STMT *) stmt;
11268     d = (DBC *) s->dbc;
11269     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] == '%') {
11270 	int size = 3 * asize;
11271 
11272 	s->rows = xmalloc(size * sizeof (char *));
11273 	if (!s->rows) {
11274 	    s->nrows = 0;
11275 	    return nomem(s);
11276 	}
11277 	memset(s->rows, 0, sizeof (char *) * size);
11278 	s->ncols = asize;
11279 	s->rows[s->ncols + 0] = "";
11280 	s->rows[s->ncols + 1] = "";
11281 	s->rows[s->ncols + 2] = "";
11282 	s->rows[s->ncols + 3] = "TABLE";
11283 	s->rows[s->ncols + 5] = "";
11284 	s->rows[s->ncols + 6] = "";
11285 	s->rows[s->ncols + 7] = "";
11286 	s->rows[s->ncols + 8] = "VIEW";
11287 #ifdef MEMORY_DEBUG
11288 	s->rowfree = xfree__;
11289 #else
11290 	s->rowfree = free;
11291 #endif
11292 	s->nrows = 2;
11293 	s->rowp = -1;
11294 	return SQL_SUCCESS;
11295     }
11296     if (cat && (catLen > 0 || catLen == SQL_NTS) && cat[0] == '%') {
11297 	table = NULL;
11298 	goto doit;
11299     }
11300     if (schema && (schemaLen > 0 || schemaLen == SQL_NTS) &&
11301 	schema[0] == '%') {
11302 	if ((!cat || catLen == 0 || !cat[0]) &&
11303 	    (!table || tableLen == 0 || !table[0])) {
11304 	    table = NULL;
11305 	    goto doit;
11306 	}
11307     }
11308     if (type && (typeLen > 0 || typeLen == SQL_NTS) && type[0] != '\0') {
11309 	char tmp[256], *t;
11310 	int with_view = 0, with_table = 0;
11311 
11312 	if (typeLen == SQL_NTS) {
11313 	    strncpy(tmp, (char *) type, sizeof (tmp));
11314 	    tmp[sizeof (tmp) - 1] = '\0';
11315 	} else {
11316 	    int len = min(sizeof (tmp) - 1, typeLen);
11317 
11318 	    strncpy(tmp, (char *) type, len);
11319 	    tmp[len] = '\0';
11320 	}
11321 	t = tmp;
11322 	while (*t) {
11323 	    *t = TOLOWER(*t);
11324 	    t++;
11325 	}
11326 	t = tmp;
11327 	unescpat(t);
11328 	while (t) {
11329 	    if (t[0] == '\'') {
11330 		++t;
11331 	    }
11332 	    if (strncmp(t, "table", 5) == 0) {
11333 		with_table++;
11334 	    } else if (strncmp(t, "view", 4) == 0) {
11335 		with_view++;
11336 	    }
11337 	    t = strchr(t, ',');
11338 	    if (t) {
11339 		++t;
11340 	    }
11341 	}
11342 	if (with_view && with_table) {
11343 	    /* where is already preset */
11344 	} else if (with_view && !with_table) {
11345 	    where = "type = 'view'";
11346 	} else if (!with_view && with_table) {
11347 	    where = "type = 'table'";
11348 	} else {
11349 	    return SQL_SUCCESS;
11350 	}
11351     }
11352 doit:
11353     if (!table) {
11354 	size = 1;
11355 	tname[0] = '%';
11356     } else {
11357 	if (tableLen == SQL_NTS) {
11358 	    size = sizeof (tname) - 1;
11359 	} else {
11360 	    size = min(sizeof (tname) - 1, tableLen);
11361 	}
11362 	strncpy(tname, (char *) table, size);
11363     }
11364     tname[size] = '\0';
11365     npatt = unescpat(tname);
11366     ret = starttran(s);
11367     if (ret != SQL_SUCCESS) {
11368 	return ret;
11369     }
11370 #if defined(_WIN32) || defined(_WIN64)
11371     if (npatt) {
11372 	rc = sqlite_get_table_printf(d->sqlite,
11373 				     "select %s as 'TABLE_QUALIFIER', "
11374 				     "%s as 'TABLE_OWNER', "
11375 				     "tbl_name as 'TABLE_NAME', "
11376 				     "upper(type) as 'TABLE_TYPE', "
11377 				     "NULL as 'REMARKS' "
11378 				     "from sqlite_master where %s "
11379 				     "and tbl_name like '%q'",
11380 				     &s->rows, &s->nrows, &ncols, &errp,
11381 				     d->xcelqrx ? "'main'" : "NULL",
11382 				     d->xcelqrx ? "''" : "NULL",
11383 				     where, tname);
11384     } else {
11385 	rc = sqlite_get_table_printf(d->sqlite,
11386 				     "select %s as 'TABLE_QUALIFIER', "
11387 				     "%s as 'TABLE_OWNER', "
11388 				     "tbl_name as 'TABLE_NAME', "
11389 				     "upper(type) as 'TABLE_TYPE', "
11390 				     "NULL as 'REMARKS' "
11391 				     "from sqlite_master where %s "
11392 				     "and lower(tbl_name) = lower('%q')",
11393 				     &s->rows, &s->nrows, &ncols, &errp,
11394 				     d->xcelqrx ? "'main'" : "NULL",
11395 				     d->xcelqrx ? "''" : "NULL",
11396 				     where, tname);
11397     }
11398 #else
11399     if (npatt) {
11400 	rc = sqlite_get_table_printf(d->sqlite,
11401 				     "select NULL as 'TABLE_QUALIFIER', "
11402 				     "NULL as 'TABLE_OWNER', "
11403 				     "tbl_name as 'TABLE_NAME', "
11404 				     "upper(type) as 'TABLE_TYPE', "
11405 				     "NULL as 'REMARKS' "
11406 				     "from sqlite_master where %s "
11407 				     "and tbl_name like '%q'",
11408 				     &s->rows, &s->nrows, &ncols, &errp,
11409 				     where, tname);
11410     } else {
11411 	rc = sqlite_get_table_printf(d->sqlite,
11412 				     "select NULL as 'TABLE_QUALIFIER', "
11413 				     "NULL as 'TABLE_OWNER', "
11414 				     "tbl_name as 'TABLE_NAME', "
11415 				     "upper(type) as 'TABLE_TYPE', "
11416 				     "NULL as 'REMARKS' "
11417 				     "from sqlite_master where %s "
11418 				     "and lower(tbl_name) = lower('%q')",
11419 				     &s->rows, &s->nrows, &ncols, &errp,
11420 				     where, tname);
11421     }
11422 #endif
11423     if (rc == SQLITE_OK) {
11424 	if (ncols != s->ncols) {
11425 	    freeresult(s, 0);
11426 	    s->nrows = 0;
11427 	} else {
11428 	    s->rowfree = sqlite_free_table;
11429 	}
11430     } else {
11431 	s->nrows = 0;
11432 	s->rows = NULL;
11433 	s->rowfree = NULL;
11434     }
11435     if (errp) {
11436 	sqlite_freemem(errp);
11437 	errp = NULL;
11438     }
11439     s->rowp = -1;
11440     return SQL_SUCCESS;
11441 }
11442 
11443 #ifndef WINTERFACE
11444 /**
11445  * Retrieve information on tables and/or views.
11446  * @param stmt statement handle
11447  * @param cat catalog name/pattern or NULL
11448  * @param catLen length of catalog name/pattern or SQL_NTS
11449  * @param schema schema name/pattern or NULL
11450  * @param schemaLen length of schema name/pattern or SQL_NTS
11451  * @param table table name/pattern or NULL
11452  * @param tableLen length of table name/pattern or SQL_NTS
11453  * @param type types of tables string or NULL
11454  * @param typeLen length of types of tables string or SQL_NTS
11455  * @result ODBC error code
11456  */
11457 
11458 SQLRETURN SQL_API
SQLTables(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * type,SQLSMALLINT typeLen)11459 SQLTables(SQLHSTMT stmt,
11460 	  SQLCHAR *cat, SQLSMALLINT catLen,
11461 	  SQLCHAR *schema, SQLSMALLINT schemaLen,
11462 	  SQLCHAR *table, SQLSMALLINT tableLen,
11463 	  SQLCHAR *type, SQLSMALLINT typeLen)
11464 {
11465     SQLRETURN ret;
11466 
11467     HSTMT_LOCK(stmt);
11468     ret = drvtables(stmt, cat, catLen, schema, schemaLen,
11469 		    table, tableLen, type, typeLen);
11470     HSTMT_UNLOCK(stmt);
11471     return ret;
11472 }
11473 #endif
11474 
11475 #ifdef WINTERFACE
11476 /**
11477  * Retrieve information on tables and/or views.
11478  * @param stmt statement handle
11479  * @param cat catalog name/pattern or NULL
11480  * @param catLen length of catalog name/pattern or SQL_NTS
11481  * @param schema schema name/pattern or NULL
11482  * @param schemaLen length of schema name/pattern or SQL_NTS
11483  * @param table table name/pattern or NULL
11484  * @param tableLen length of table name/pattern or SQL_NTS
11485  * @param type types of tables string or NULL
11486  * @param typeLen length of types of tables string or SQL_NTS
11487  * @result ODBC error code
11488  */
11489 
11490 SQLRETURN SQL_API
SQLTablesW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * type,SQLSMALLINT typeLen)11491 SQLTablesW(SQLHSTMT stmt,
11492 	   SQLWCHAR *cat, SQLSMALLINT catLen,
11493 	   SQLWCHAR *schema, SQLSMALLINT schemaLen,
11494 	   SQLWCHAR *table, SQLSMALLINT tableLen,
11495 	   SQLWCHAR *type, SQLSMALLINT typeLen)
11496 {
11497     char *c = NULL, *s = NULL, *t = NULL, *y = NULL;
11498     SQLRETURN ret;
11499 
11500     HSTMT_LOCK(stmt);
11501     if (cat) {
11502 	c = uc_to_utf_c(cat, catLen);
11503 	if (!c) {
11504 	    ret = nomem((STMT *) stmt);
11505 	    goto done;
11506 	}
11507     }
11508     if (schema) {
11509 	s = uc_to_utf_c(schema, schemaLen);
11510 	if (!s) {
11511 	    ret = nomem((STMT *) stmt);
11512 	    goto done;
11513 	}
11514     }
11515     if (table) {
11516 	t = uc_to_utf_c(table, tableLen);
11517 	if (!t) {
11518 	    ret = nomem((STMT *) stmt);
11519 	    goto done;
11520 	}
11521     }
11522     if (type) {
11523 	y = uc_to_utf_c(type, typeLen);
11524 	if (!y) {
11525 	    ret = nomem((STMT *) stmt);
11526 	    goto done;
11527 	}
11528     }
11529     ret = drvtables(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
11530 		    (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) y, SQL_NTS);
11531 done:
11532     HSTMT_UNLOCK(stmt);
11533     uc_free(y);
11534     uc_free(t);
11535     uc_free(s);
11536     uc_free(c);
11537     return ret;
11538 }
11539 #endif
11540 
11541 /**
11542  * Columns for result set of SQLColumns().
11543  */
11544 
11545 static COL colSpec2[] = {
11546     { "SYSTEM", "COLUMN", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
11547     { "SYSTEM", "COLUMN", "TABLE_OWNER", SCOL_VARCHAR, 50 },
11548     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
11549     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
11550     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
11551     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
11552     { "SYSTEM", "COLUMN", "PRECISION", SQL_INTEGER, 50 },
11553     { "SYSTEM", "COLUMN", "LENGTH", SQL_INTEGER, 50 },
11554     { "SYSTEM", "COLUMN", "SCALE", SQL_SMALLINT, 50 },
11555     { "SYSTEM", "COLUMN", "RADIX", SQL_SMALLINT, 50 },
11556     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
11557     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
11558     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
11559     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
11560     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
11561     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
11562     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
11563     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
11564 };
11565 
11566 static COL colSpec3[] = {
11567     { "SYSTEM", "COLUMN", "TABLE_CAT", SCOL_VARCHAR, 50 },
11568     { "SYSTEM", "COLUMN", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
11569     { "SYSTEM", "COLUMN", "TABLE_NAME", SCOL_VARCHAR, 255 },
11570     { "SYSTEM", "COLUMN", "COLUMN_NAME", SCOL_VARCHAR, 255 },
11571     { "SYSTEM", "COLUMN", "DATA_TYPE", SQL_SMALLINT, 50 },
11572     { "SYSTEM", "COLUMN", "TYPE_NAME", SCOL_VARCHAR, 50 },
11573     { "SYSTEM", "COLUMN", "COLUMN_SIZE", SQL_INTEGER, 50 },
11574     { "SYSTEM", "COLUMN", "BUFFER_LENGTH", SQL_INTEGER, 50 },
11575     { "SYSTEM", "COLUMN", "DECIMAL_DIGITS", SQL_SMALLINT, 50 },
11576     { "SYSTEM", "COLUMN", "NUM_PREC_RADIX", SQL_SMALLINT, 50 },
11577     { "SYSTEM", "COLUMN", "NULLABLE", SQL_SMALLINT, 50 },
11578     { "SYSTEM", "COLUMN", "REMARKS", SCOL_VARCHAR, 50 },
11579     { "SYSTEM", "COLUMN", "COLUMN_DEF", SCOL_VARCHAR, 50 },
11580     { "SYSTEM", "COLUMN", "SQL_DATA_TYPE", SQL_SMALLINT, 50 },
11581     { "SYSTEM", "COLUMN", "SQL_DATETIME_SUB", SQL_SMALLINT, 50 },
11582     { "SYSTEM", "COLUMN", "CHAR_OCTET_LENGTH", SQL_SMALLINT, 50 },
11583     { "SYSTEM", "COLUMN", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
11584     { "SYSTEM", "COLUMN", "IS_NULLABLE", SCOL_VARCHAR, 50 }
11585 };
11586 
11587 /**
11588  * Internal retrieve column information on table.
11589  * @param stmt statement handle
11590  * @param cat catalog name/pattern or NULL
11591  * @param catLen length of catalog name/pattern or SQL_NTS
11592  * @param schema schema name/pattern or NULL
11593  * @param schemaLen length of schema name/pattern or SQL_NTS
11594  * @param table table name/pattern or NULL
11595  * @param tableLen length of table name/pattern or SQL_NTS
11596  * @param col column name/pattern or NULL
11597  * @param colLen length of column name/pattern or SQL_NTS
11598  * @result ODBC error code
11599  */
11600 
11601 static SQLRETURN
drvcolumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)11602 drvcolumns(SQLHSTMT stmt,
11603 	   SQLCHAR *cat, SQLSMALLINT catLen,
11604 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
11605 	   SQLCHAR *table, SQLSMALLINT tableLen,
11606 	   SQLCHAR *col, SQLSMALLINT colLen)
11607 {
11608     SQLRETURN sret;
11609     STMT *s;
11610     DBC *d;
11611     int ret, nrows, ncols, asize, i, k, roffs, namec;
11612     int tnrows, tncols, npatt;
11613     PTRDIFF_T size;
11614     char *errp = NULL, tname[512], cname[512], **rowp, **trows;
11615 
11616     sret = mkresultset(stmt, colSpec2, array_size(colSpec2),
11617 		       colSpec3, array_size(colSpec3), &asize);
11618     if (sret != SQL_SUCCESS) {
11619 	return sret;
11620     }
11621     s = (STMT *) stmt;
11622     d = (DBC *) s->dbc;
11623     if (!table) {
11624 	size = 1;
11625 	tname[0] = '%';
11626     } else {
11627 	if (tableLen == SQL_NTS) {
11628 	    size = sizeof (tname) - 1;
11629 	} else {
11630 	    size = min(sizeof (tname) - 1, tableLen);
11631 	}
11632 	strncpy(tname, (char *) table, size);
11633     }
11634     tname[size] = '\0';
11635     npatt = unescpat(tname);
11636     size = 0;
11637     if (col) {
11638 	if (colLen == SQL_NTS) {
11639 	    size = sizeof (cname) - 1;
11640 	} else {
11641 	    size = min(sizeof (cname) - 1, colLen);
11642 	}
11643 	strncpy(cname, (char *) col, size);
11644     }
11645     cname[size] = '\0';
11646     if (!strcmp(cname, "%")) {
11647 	cname[0] = '\0';
11648     }
11649     sret = starttran(s);
11650     if (sret != SQL_SUCCESS) {
11651 	return sret;
11652     }
11653     if (npatt) {
11654 	ret = sqlite_get_table_printf(d->sqlite,
11655 				      "select tbl_name from sqlite_master "
11656 				      "where (type = 'table' or type = 'view')"
11657 				      " and tbl_name like '%q'",
11658 				      &trows, &tnrows, &tncols, &errp, tname);
11659     } else {
11660 	ret = sqlite_get_table_printf(d->sqlite,
11661 				      "select tbl_name from sqlite_master "
11662 				      "where (type = 'table' or type = 'view')"
11663 				      " and lower(tbl_name) = lower('%q')",
11664 				      &trows, &tnrows, &tncols, &errp, tname);
11665     }
11666     if (ret != SQLITE_OK) {
11667 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
11668 		errp ? errp : "unknown error", ret);
11669 	if (errp) {
11670 	    sqlite_freemem(errp);
11671 	    errp = NULL;
11672 	}
11673 	return SQL_ERROR;
11674     }
11675     /* pass 1; compute number of rows of result set */
11676     if (tncols * tnrows <= 0) {
11677 	sqlite_free_table(trows);
11678 	return SQL_SUCCESS;
11679     }
11680     size = 0;
11681     for (i = 1; i <= tnrows; i++) {
11682 	ret = sqlite_get_table_printf(d->sqlite, "PRAGMA table_info('%q')",
11683 				      &rowp, &nrows, &ncols, &errp, trows[i]);
11684 	if (ret != SQLITE_OK) {
11685 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
11686 		    errp ? errp : "unknown error", ret);
11687 	    if (errp) {
11688 		sqlite_freemem(errp);
11689 		errp = NULL;
11690 	    }
11691 	    return SQL_ERROR;
11692 	}
11693 	if (errp) {
11694 	    sqlite_freemem(errp);
11695 	    errp = NULL;
11696 	}
11697 	if (ncols * nrows > 0) {
11698 	    namec = -1;
11699 	    for (k = 0; k < ncols; k++) {
11700 		if (strcmp(rowp[k], "name") == 0) {
11701 		    namec = k;
11702 		    break;
11703 		}
11704 	    }
11705 	    if (cname[0]) {
11706 		for (k = 1; k <= nrows; k++) {
11707 		    if (namematch(rowp[k * ncols + namec], cname, 1)) {
11708 			size++;
11709 		    }
11710 		}
11711 	    } else {
11712 		size += nrows;
11713 	    }
11714 	}
11715 	sqlite_free_table(rowp);
11716     }
11717     /* pass 2: fill result set */
11718     if (size <= 0) {
11719 	sqlite_free_table(trows);
11720 	return SQL_SUCCESS;
11721     }
11722     s->nrows = size;
11723     size = (size + 1) * asize;
11724     s->rows = xmalloc((size + 1) * sizeof (char *));
11725     if (!s->rows) {
11726 	s->nrows = 0;
11727 	sqlite_free_table(trows);
11728 	return nomem(s);
11729     }
11730     s->rows[0] = (char *) size;
11731     s->rows += 1;
11732     memset(s->rows, 0, sizeof (char *) * size);
11733     s->rowfree = freerows;
11734     roffs = 1;
11735     for (i = 1; i <= tnrows; i++) {
11736 	ret = sqlite_get_table_printf(d->sqlite, "PRAGMA table_info('%q')",
11737 				      &rowp, &nrows, &ncols, &errp, trows[i]);
11738 	if (ret != SQLITE_OK) {
11739 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
11740 		    errp ? errp : "unknown error", ret);
11741 	    if (errp) {
11742 		sqlite_freemem(errp);
11743 		errp = NULL;
11744 	    }
11745 	    sqlite_free_table(trows);
11746 	    return SQL_ERROR;
11747 	}
11748 	if (errp) {
11749 	    sqlite_freemem(errp);
11750 	    errp = NULL;
11751 	}
11752 	if (ncols * nrows > 0) {
11753 	    int m, mr, nr = nrows;
11754 
11755 	    namec = -1;
11756 	    for (k = 0; k < ncols; k++) {
11757 		if (strcmp(rowp[k], "name") == 0) {
11758 		    namec = k;
11759 		    break;
11760 		}
11761 	    }
11762 	    if (cname[0]) {
11763 		nr = 0;
11764 		for (k = 1; k <= nrows; k++) {
11765 		    if (namematch(rowp[k * ncols + namec], cname, 1)) {
11766 			nr++;
11767 		    }
11768 		}
11769 	    }
11770 	    for (k = 0; k < nr; k++) {
11771 		m = asize * (roffs + k);
11772 #if defined(_WIN32) || defined(_WIN64)
11773 		s->rows[m + 0] = xstrdup(d->xcelqrx ? "main" : "");
11774 		s->rows[m + 1] = xstrdup("");
11775 #else
11776 		s->rows[m + 0] = xstrdup("");
11777 		s->rows[m + 1] = xstrdup("");
11778 #endif
11779 		s->rows[m + 2] = xstrdup(trows[i]);
11780 		s->rows[m + 8] = xstrdup("10");
11781 		s->rows[m + 9] = xstrdup("0");
11782 		s->rows[m + 15] = xstrdup("16384");
11783 	    }
11784 	    for (k = 0; nr && k < ncols; k++) {
11785 		if (strcmp(rowp[k], "cid") == 0) {
11786 		    for (mr = 0, m = 1; m <= nrows; m++) {
11787 			char buf[256];
11788 			int ir, coln = i;
11789 
11790 			if (cname[0] &&
11791 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
11792 			    continue;
11793 			}
11794 			ir = asize * (roffs + mr);
11795 			sscanf(rowp[m * ncols + k], "%d", &coln);
11796 			sprintf(buf, "%d", coln + 1);
11797 			s->rows[ir + 16] = xstrdup(buf);
11798 			++mr;
11799 		    }
11800 		} else if (k == namec) {
11801 		    for (mr = 0, m = 1; m <= nrows; m++) {
11802 			int ir;
11803 
11804 			if (cname[0] &&
11805 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
11806 			    continue;
11807 			}
11808 			ir = asize * (roffs + mr);
11809 			s->rows[ir + 3] = xstrdup(rowp[m * ncols + k]);
11810 			++mr;
11811 		    }
11812 		} else if (strcmp(rowp[k], "notnull") == 0) {
11813 		    for (mr = 0, m = 1; m <= nrows; m++) {
11814 			int ir;
11815 
11816 			if (cname[0] &&
11817 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
11818 			    continue;
11819 			}
11820 			ir = asize * (roffs + mr);
11821 			if (*rowp[m * ncols + k] != '0') {
11822 			    s->rows[ir + 10] = xstrdup(stringify(SQL_FALSE));
11823 			} else {
11824 			    s->rows[ir + 10] = xstrdup(stringify(SQL_TRUE));
11825 			}
11826 			s->rows[ir + 17] =
11827 			    xstrdup((*rowp[m * ncols + k] != '0') ?
11828 				    "NO" : "YES");
11829 			++mr;
11830 		    }
11831 		} else if (strcmp(rowp[k], "dflt_value") == 0) {
11832 		    for (mr = 0, m = 1; m <= nrows; m++) {
11833 			char *dflt = rowp[m * ncols + k];
11834 			int ir;
11835 
11836 			if (cname[0] &&
11837 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
11838 			    continue;
11839 			}
11840 			ir = asize * (roffs + mr);
11841 			s->rows[ir + 12] = xstrdup(dflt ? dflt : "NULL");
11842 			++mr;
11843 		    }
11844 		} else if (strcmp(rowp[k], "type") == 0) {
11845 		    for (mr = 0, m = 1; m <= nrows; m++) {
11846 			char *typename = rowp[m * ncols + k];
11847 			int sqltype, mm, dd, ir;
11848 			char buf[256];
11849 
11850 			if (cname[0] &&
11851 			    !namematch(rowp[m * ncols + namec], cname, 1)) {
11852 			    continue;
11853 			}
11854 			ir = asize * (roffs + mr);
11855 			s->rows[ir + 5] = xstrdup(typename);
11856 			sqltype = mapsqltype(typename, NULL, *s->ov3,
11857 					     s->nowchar[0]);
11858 			getmd(typename, sqltype, &mm, &dd);
11859 #ifdef SQL_LONGVARCHAR
11860 			if (sqltype == SQL_VARCHAR && mm > 255) {
11861 			    sqltype = SQL_LONGVARCHAR;
11862 			}
11863 #endif
11864 #ifdef WINTERFACE
11865 #ifdef SQL_WLONGVARCHAR
11866 			if (sqltype == SQL_WVARCHAR && mm > 255) {
11867 			    sqltype = SQL_WLONGVARCHAR;
11868 			}
11869 #endif
11870 #endif
11871 #if (HAVE_ENCDEC)
11872 			if (sqltype == SQL_VARBINARY && mm > 255) {
11873 			    sqltype = SQL_LONGVARBINARY;
11874 			}
11875 #endif
11876 			sprintf(buf, "%d", sqltype);
11877 			s->rows[ir + 4] = xstrdup(buf);
11878 			s->rows[ir + 13] = xstrdup(buf);
11879 			sprintf(buf, "%d", mm);
11880 			s->rows[ir + 7] = xstrdup(buf);
11881 			sprintf(buf, "%d", dd);
11882 			s->rows[ir + 6] = xstrdup(buf);
11883 			++mr;
11884 		    }
11885 		}
11886 	    }
11887 	    roffs += nr;
11888 	}
11889 	sqlite_free_table(rowp);
11890     }
11891     sqlite_free_table(trows);
11892     return SQL_SUCCESS;
11893 }
11894 
11895 #ifndef WINTERFACE
11896 /**
11897  * Retrieve column information on table.
11898  * @param stmt statement handle
11899  * @param cat catalog name/pattern or NULL
11900  * @param catLen length of catalog name/pattern or SQL_NTS
11901  * @param schema schema name/pattern or NULL
11902  * @param schemaLen length of schema name/pattern or SQL_NTS
11903  * @param table table name/pattern or NULL
11904  * @param tableLen length of table name/pattern or SQL_NTS
11905  * @param col column name/pattern or NULL
11906  * @param colLen length of column name/pattern or SQL_NTS
11907  * @result ODBC error code
11908  */
11909 
11910 SQLRETURN SQL_API
SQLColumns(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLCHAR * col,SQLSMALLINT colLen)11911 SQLColumns(SQLHSTMT stmt,
11912 	   SQLCHAR *cat, SQLSMALLINT catLen,
11913 	   SQLCHAR *schema, SQLSMALLINT schemaLen,
11914 	   SQLCHAR *table, SQLSMALLINT tableLen,
11915 	   SQLCHAR *col, SQLSMALLINT colLen)
11916 {
11917     SQLRETURN ret;
11918 
11919     HSTMT_LOCK(stmt);
11920     ret = drvcolumns(stmt, cat, catLen, schema, schemaLen,
11921 		     table, tableLen, col, colLen);
11922     HSTMT_UNLOCK(stmt);
11923     return ret;
11924 }
11925 #endif
11926 
11927 #ifdef WINTERFACE
11928 /**
11929  * Retrieve column information on table (UNICODE version).
11930  * @param stmt statement handle
11931  * @param cat catalog name/pattern or NULL
11932  * @param catLen length of catalog name/pattern or SQL_NTS
11933  * @param schema schema name/pattern or NULL
11934  * @param schemaLen length of schema name/pattern or SQL_NTS
11935  * @param table table name/pattern or NULL
11936  * @param tableLen length of table name/pattern or SQL_NTS
11937  * @param col column name/pattern or NULL
11938  * @param colLen length of column name/pattern or SQL_NTS
11939  * @result ODBC error code
11940  */
11941 
11942 SQLRETURN SQL_API
SQLColumnsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLWCHAR * col,SQLSMALLINT colLen)11943 SQLColumnsW(SQLHSTMT stmt,
11944 	    SQLWCHAR *cat, SQLSMALLINT catLen,
11945 	    SQLWCHAR *schema, SQLSMALLINT schemaLen,
11946 	    SQLWCHAR *table, SQLSMALLINT tableLen,
11947 	    SQLWCHAR *col, SQLSMALLINT colLen)
11948 {
11949     char *c = NULL, *s = NULL, *t = NULL, *k = NULL;
11950     SQLRETURN ret;
11951 
11952     HSTMT_LOCK(stmt);
11953     if (cat) {
11954 	c = uc_to_utf_c(cat, catLen);
11955 	if (!c) {
11956 	    ret = nomem((STMT *) stmt);
11957 	    goto done;
11958 	}
11959     }
11960     if (schema) {
11961 	s = uc_to_utf_c(schema, schemaLen);
11962 	if (!s) {
11963 	    ret = nomem((STMT *) stmt);
11964 	    goto done;
11965 	}
11966     }
11967     if (table) {
11968 	t = uc_to_utf_c(table, tableLen);
11969 	if (!t) {
11970 	    ret = nomem((STMT *) stmt);
11971 	    goto done;
11972 	}
11973     }
11974     if (col) {
11975 	k = uc_to_utf_c(col, colLen);
11976 	if (!k) {
11977 	    ret = nomem((STMT *) stmt);
11978 	    goto done;
11979 	}
11980     }
11981     ret = drvcolumns(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
11982 		     (SQLCHAR *) t, SQL_NTS, (SQLCHAR *) k, SQL_NTS);
11983 done:
11984     HSTMT_UNLOCK(stmt);
11985     uc_free(k);
11986     uc_free(t);
11987     uc_free(s);
11988     uc_free(c);
11989     return ret;
11990 
11991 }
11992 #endif
11993 
11994 /**
11995  * Columns for result set of SQLGetTypeInfo().
11996  */
11997 
11998 static COL typeSpec2[] = {
11999     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
12000     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
12001     { "SYSTEM", "TYPE", "PRECISION", SQL_INTEGER, 9 },
12002     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
12003     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
12004     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
12005     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
12006     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
12007     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
12008     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
12009     { "SYSTEM", "TYPE", "MONEY", SQL_SMALLINT, 2 },
12010     { "SYSTEM", "TYPE", "AUTO_INCREMENT", SQL_SMALLINT, 2 },
12011     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
12012     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
12013     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 }
12014 };
12015 
12016 static COL typeSpec3[] = {
12017     { "SYSTEM", "TYPE", "TYPE_NAME", SCOL_VARCHAR, 50 },
12018     { "SYSTEM", "TYPE", "DATA_TYPE", SQL_SMALLINT, 2 },
12019     { "SYSTEM", "TYPE", "COLUMN_SIZE", SQL_INTEGER, 9 },
12020     { "SYSTEM", "TYPE", "LITERAL_PREFIX", SCOL_VARCHAR, 50 },
12021     { "SYSTEM", "TYPE", "LITERAL_SUFFIX", SCOL_VARCHAR, 50 },
12022     { "SYSTEM", "TYPE", "CREATE_PARAMS", SCOL_VARCHAR, 50 },
12023     { "SYSTEM", "TYPE", "NULLABLE", SQL_SMALLINT, 2 },
12024     { "SYSTEM", "TYPE", "CASE_SENSITIVE", SQL_SMALLINT, 2 },
12025     { "SYSTEM", "TYPE", "SEARCHABLE", SQL_SMALLINT, 2 },
12026     { "SYSTEM", "TYPE", "UNSIGNED_ATTRIBUTE", SQL_SMALLINT, 2 },
12027     { "SYSTEM", "TYPE", "FIXED_PREC_SCALE", SQL_SMALLINT, 2 },
12028     { "SYSTEM", "TYPE", "AUTO_UNIQUE_VALUE", SQL_SMALLINT, 2 },
12029     { "SYSTEM", "TYPE", "LOCAL_TYPE_NAME", SCOL_VARCHAR, 50 },
12030     { "SYSTEM", "TYPE", "MINIMUM_SCALE", SQL_SMALLINT, 2 },
12031     { "SYSTEM", "TYPE", "MAXIMUM_SCALE", SQL_SMALLINT, 2 },
12032     { "SYSTEM", "TYPE", "SQL_DATA_TYPE", SQL_SMALLINT, 2 },
12033     { "SYSTEM", "TYPE", "SQL_DATETIME_SUB", SQL_SMALLINT, 2 },
12034     { "SYSTEM", "TYPE", "NUM_PREC_RADIX", SQL_INTEGER, 4 },
12035     { "SYSTEM", "TYPE", "INTERVAL_PRECISION", SQL_SMALLINT, 2 }
12036 };
12037 
12038 /**
12039  * Internal function to build up data type information as row in result set.
12040  * @param s statement pointer
12041  * @param row row number
12042  * @param asize number of items in a row
12043  * @param typename name of type
12044  * @param type integer SQL type
12045  * @param tind type index
12046  */
12047 
12048 static void
mktypeinfo(STMT * s,int row,int asize,char * typename,int type,int tind)12049 mktypeinfo(STMT *s, int row, int asize, char *typename, int type, int tind)
12050 {
12051     int offs = row * asize;
12052     char *tcode, *crpar = NULL, *quote = NULL, *sign = stringify(SQL_FALSE);
12053     static char tcodes[32 * 32];
12054 
12055     if (tind <= 0) {
12056 	tind = row;
12057     }
12058     tcode = tcodes + tind * 32;
12059     sprintf(tcode, "%d", type);
12060     s->rows[offs + 0] = typename;
12061     s->rows[offs + 1] = tcode;
12062     if (asize >= 17) {
12063 	s->rows[offs + 15] = tcode;
12064 	s->rows[offs + 16] = "0";
12065     }
12066     switch (type) {
12067     default:
12068 #ifdef SQL_LONGVARCHAR
12069     case SQL_LONGVARCHAR:
12070 #ifdef WINTERFACE
12071     case SQL_WLONGVARCHAR:
12072 #endif
12073 	crpar = "length";
12074 	quote = "'";
12075 	sign = NULL;
12076 	s->rows[offs + 2] = "65536";
12077 	break;
12078 #endif
12079     case SQL_CHAR:
12080     case SQL_VARCHAR:
12081 #ifdef WINTERFACE
12082     case SQL_WCHAR:
12083     case SQL_WVARCHAR:
12084 #endif
12085 	s->rows[offs + 2] = "255";
12086 	crpar = "length";
12087 	quote = "'";
12088 	sign = NULL;
12089 	break;
12090     case SQL_TINYINT:
12091 	s->rows[offs + 2] = "3";
12092 	break;
12093     case SQL_SMALLINT:
12094 	s->rows[offs + 2] = "5";
12095 	break;
12096     case SQL_INTEGER:
12097 	s->rows[offs + 2] = "9";
12098 	break;
12099     case SQL_FLOAT:
12100 	s->rows[offs + 2] = "7";
12101 	break;
12102     case SQL_DOUBLE:
12103 	s->rows[offs + 2] = "15";
12104 	break;
12105 #ifdef SQL_TYPE_DATE
12106     case SQL_TYPE_DATE:
12107 #endif
12108     case SQL_DATE:
12109 	s->rows[offs + 2] = "10";
12110 	quote = "'";
12111 	sign = NULL;
12112 	break;
12113 #ifdef SQL_TYPE_TIME
12114     case SQL_TYPE_TIME:
12115 #endif
12116     case SQL_TIME:
12117 	s->rows[offs + 2] = "8";
12118 	quote = "'";
12119 	sign = NULL;
12120 	break;
12121 #ifdef SQL_TYPE_TIMESTAMP
12122     case SQL_TYPE_TIMESTAMP:
12123 #endif
12124     case SQL_TIMESTAMP:
12125 	s->rows[offs + 2] = "32";
12126 	quote = "'";
12127 	sign = NULL;
12128 	break;
12129 #if (HAVE_ENCDEC)
12130     case SQL_VARBINARY:
12131 	sign = NULL;
12132 	s->rows[offs + 2] = "255";
12133 	break;
12134     case SQL_LONGVARBINARY:
12135 	sign = NULL;
12136 	s->rows[offs + 2] = "65536";
12137 	break;
12138 #endif
12139 #ifdef SQL_BIT
12140     case SQL_BIT:
12141 	sign = NULL;
12142 	s->rows[offs + 2] = "1";
12143 	break;
12144 #endif
12145     }
12146     s->rows[offs + 3] = s->rows[offs + 4] = quote;
12147     s->rows[offs + 5] = crpar;
12148     s->rows[offs + 6] = stringify(SQL_NULLABLE);
12149     s->rows[offs + 7] = stringify(SQL_FALSE);
12150     s->rows[offs + 8] = stringify(SQL_SEARCHABLE);
12151     s->rows[offs + 9] = sign;
12152     s->rows[offs + 10] = stringify(SQL_FALSE);
12153     s->rows[offs + 11] = stringify(SQL_FALSE);
12154     s->rows[offs + 12] = typename;
12155     switch (type) {
12156     case SQL_DATE:
12157     case SQL_TIME:
12158 	s->rows[offs + 13] = "0";
12159 	s->rows[offs + 14] = "0";
12160 	break;
12161 #ifdef SQL_TYPE_TIMESTAMP
12162     case SQL_TYPE_TIMESTAMP:
12163 #endif
12164     case SQL_TIMESTAMP:
12165 	s->rows[offs + 13] = "0";
12166 	s->rows[offs + 14] = "3";
12167 	break;
12168     default:
12169 	s->rows[offs + 13] = NULL;
12170 	s->rows[offs + 14] = NULL;
12171 	break;
12172     }
12173 }
12174 
12175 /**
12176  * Helper function to sort type information.
12177  * Callback for qsort().
12178  * @param a first item to compare
12179  * @param b second item to compare
12180  * @result ==0, <0, >0 according to data type number
12181  */
12182 
12183 static int
typeinfosort(const void * a,const void * b)12184 typeinfosort(const void *a, const void *b)
12185 {
12186     char **pa = (char **) a;
12187     char **pb = (char **) b;
12188     int na, nb;
12189 
12190     na = strtol(pa[1], NULL, 0);
12191     nb = strtol(pb[1], NULL, 0);
12192     return na - nb;
12193 }
12194 
12195 /**
12196  * Internal return data type information.
12197  * @param stmt statement handle
12198  * @param sqltype which type to retrieve
12199  * @result ODBC error code
12200  */
12201 
12202 static SQLRETURN
drvgettypeinfo(SQLHSTMT stmt,SQLSMALLINT sqltype)12203 drvgettypeinfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
12204 {
12205     SQLRETURN ret;
12206     STMT *s;
12207     int asize;
12208 
12209     ret = mkresultset(stmt, typeSpec2, array_size(typeSpec2),
12210 		      typeSpec3, array_size(typeSpec3), &asize);
12211     if (ret != SQL_SUCCESS) {
12212 	return ret;
12213     }
12214     s = (STMT *) stmt;
12215 #ifdef WINTERFACE
12216 #ifdef SQL_LONGVARCHAR
12217 #ifdef SQL_WLONGVARCHAR
12218     if (s->nowchar[0]) {
12219 	s->nrows = (sqltype == SQL_ALL_TYPES) ? 13 : 1;
12220     } else {
12221 	s->nrows = (sqltype == SQL_ALL_TYPES) ? 17 : 1;
12222     }
12223 #else
12224     if (s->nowchar[0]) {
12225 	s->nrows = (sqltype == SQL_ALL_TYPES) ? 12 : 1;
12226     } else {
12227 	s->nrows = (sqltype == SQL_ALL_TYPES) ? 16 : 1;
12228     }
12229 #endif
12230 #else
12231     s->nrows = (sqltype == SQL_ALL_TYPES) ? 15 : 1;
12232 #endif
12233 #else
12234 #ifdef SQL_LONGVARCHAR
12235     s->nrows = (sqltype == SQL_ALL_TYPES) ? 13 : 1;
12236 #else
12237     s->nrows = (sqltype == SQL_ALL_TYPES) ? 12 : 1;
12238 #endif
12239 #endif
12240 #if (HAVE_ENCDEC)
12241     if (sqltype == SQL_ALL_TYPES) {
12242 	s->nrows += 2;
12243     }
12244 #endif
12245 #ifdef SQL_BIT
12246     if (sqltype == SQL_ALL_TYPES) {
12247 	s->nrows += 1;
12248     }
12249 #endif
12250     s->rows = (char **) xmalloc(sizeof (char *) * (s->nrows + 1) * asize);
12251     if (!s->rows) {
12252 	s->nrows = 0;
12253 	return nomem(s);
12254     }
12255 #ifdef MEMORY_DEBUG
12256     s->rowfree = xfree__;
12257 #else
12258     s->rowfree = free;
12259 #endif
12260     memset(s->rows, 0, sizeof (char *) * (s->nrows + 1) * asize);
12261     if (sqltype == SQL_ALL_TYPES) {
12262 	int cc = 1;
12263 
12264 	mktypeinfo(s, cc++, asize, "varchar", SQL_VARCHAR, 0);
12265 	mktypeinfo(s, cc++, asize, "tinyint", SQL_TINYINT, 0);
12266 	mktypeinfo(s, cc++, asize, "smallint", SQL_SMALLINT, 0);
12267 	mktypeinfo(s, cc++, asize, "integer", SQL_INTEGER, 0);
12268 	mktypeinfo(s, cc++, asize, "float", SQL_FLOAT, 0);
12269 	mktypeinfo(s, cc++, asize, "double", SQL_DOUBLE, 0);
12270 #ifdef SQL_TYPE_DATE
12271 	mktypeinfo(s, cc++, asize, "date",
12272 		   (*s->ov3) ? SQL_TYPE_DATE : SQL_DATE, 0);
12273 #else
12274 	mktypeinfo(s, cc++, asize, "date", SQL_DATE, 0);
12275 #endif
12276 #ifdef SQL_TYPE_TIME
12277 	mktypeinfo(s, cc++, asize, "time",
12278 		   (*s->ov3) ? SQL_TYPE_TIME : SQL_TIME, 0);
12279 #else
12280 	mktypeinfo(s, cc++, asize, "time", SQL_TIME, 0);
12281 #endif
12282 #ifdef SQL_TYPE_TIMESTAMP
12283 	mktypeinfo(s, cc++, asize, "timestamp",
12284 		   (*s->ov3) ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP, 0);
12285 #else
12286 	mktypeinfo(s, cc++, asize, "timestamp", SQL_TIMESTAMP, 0);
12287 #endif
12288 	mktypeinfo(s, cc++, asize, "char", SQL_CHAR, 0);
12289 	mktypeinfo(s, cc++, asize, "numeric", SQL_DOUBLE, 0);
12290 #ifdef SQL_LONGVARCHAR
12291 	mktypeinfo(s, cc++, asize, "text", SQL_LONGVARCHAR, 0);
12292 	mktypeinfo(s, cc++, asize, "longvarchar", SQL_LONGVARCHAR, 0);
12293 #else
12294 	mktypeinfo(s, cc++, asize, "text", SQL_VARCHAR, 0);
12295 #endif
12296 #ifdef WINTERFACE
12297 	if (!s->nowchar[0]) {
12298 	    mktypeinfo(s, cc++, asize, "wvarchar", SQL_WVARCHAR, 0);
12299 #ifdef SQL_LONGVARCHAR
12300 	    mktypeinfo(s, cc++, asize, "wchar", SQL_WCHAR, 0);
12301 	    mktypeinfo(s, cc++, asize, "wtext", SQL_WLONGVARCHAR, 0);
12302 #ifdef SQL_WLONGVARCHAR
12303 	    mktypeinfo(s, cc++, asize, "longwvarchar", SQL_WLONGVARCHAR, 0);
12304 #endif
12305 #else
12306 	    mktypeinfo(s, cc++, asize, "wvarchar", SQL_WVARCHAR, 0);
12307 	    mktypeinfo(s, cc++, asize, "wchar", SQL_WCHAR, 0);
12308 	    mktypeinfo(s, cc++, asize, "wtext", SQL_WVARCHAR, 0);
12309 #endif
12310 	}
12311 #endif
12312 #if (HAVE_ENCDEC)
12313 	mktypeinfo(s, cc++, asize, "varbinary", SQL_VARBINARY, 0);
12314 	mktypeinfo(s, cc++, asize, "longvarbinary", SQL_LONGVARBINARY, 0);
12315 #endif
12316 #ifdef SQL_BIT
12317 	mktypeinfo(s, cc++, asize, "bit", SQL_BIT, 0);
12318 #endif
12319 	qsort(s->rows + asize, s->nrows, sizeof (char *) * asize,
12320 	      typeinfosort);
12321     } else {
12322 	switch (sqltype) {
12323 	case SQL_CHAR:
12324 	    mktypeinfo(s, 1, asize, "char", SQL_CHAR, 10);
12325 	    break;
12326 	case SQL_VARCHAR:
12327 	    mktypeinfo(s, 1, asize, "varchar", SQL_VARCHAR, 1);
12328 	    break;
12329 	case SQL_TINYINT:
12330 	    mktypeinfo(s, 1, asize, "tinyint", SQL_TINYINT, 2);
12331 	    break;
12332 	case SQL_SMALLINT:
12333 	    mktypeinfo(s, 1, asize, "smallint", SQL_SMALLINT, 3);
12334 	    break;
12335 	case SQL_INTEGER:
12336 	    mktypeinfo(s, 1, asize, "integer", SQL_INTEGER, 4);
12337 	    break;
12338 	case SQL_FLOAT:
12339 	    mktypeinfo(s, 1, asize, "float", SQL_FLOAT, 5);
12340 	    break;
12341 	case SQL_DOUBLE:
12342 	    mktypeinfo(s, 1, asize, "double", SQL_DOUBLE, 6);
12343 	    break;
12344 #ifdef SQL_TYPE_DATE
12345 	case SQL_TYPE_DATE:
12346 	    mktypeinfo(s, 1, asize, "date", SQL_TYPE_DATE, 25);
12347 	    break;
12348 #endif
12349 	case SQL_DATE:
12350 	    mktypeinfo(s, 1, asize, "date", SQL_DATE, 7);
12351 	    break;
12352 #ifdef SQL_TYPE_TIME
12353 	case SQL_TYPE_TIME:
12354 	    mktypeinfo(s, 1, asize, "time", SQL_TYPE_TIME, 26);
12355 	    break;
12356 #endif
12357 	case SQL_TIME:
12358 	    mktypeinfo(s, 1, asize, "time", SQL_TIME, 8);
12359 	    break;
12360 #ifdef SQL_TYPE_TIMESTAMP
12361 	case SQL_TYPE_TIMESTAMP:
12362 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TYPE_TIMESTAMP, 27);
12363 	    break;
12364 #endif
12365 	case SQL_TIMESTAMP:
12366 	    mktypeinfo(s, 1, asize, "timestamp", SQL_TIMESTAMP, 9);
12367 	    break;
12368 #ifdef SQL_LONGVARCHAR
12369 	case SQL_LONGVARCHAR:
12370 	    mktypeinfo(s, 1, asize, "longvarchar", SQL_LONGVARCHAR, 12);
12371 	    break;
12372 #endif
12373 #ifdef WINTERFACE
12374 #ifdef SQL_WCHAR
12375 	case SQL_WCHAR:
12376 	    mktypeinfo(s, 1, asize, "wchar", SQL_WCHAR, 18);
12377 	    break;
12378 #endif
12379 #ifdef SQL_WVARCHAR
12380 	case SQL_WVARCHAR:
12381 	    mktypeinfo(s, 1, asize, "wvarchar", SQL_WVARCHAR, 19);
12382 	    break;
12383 #endif
12384 #ifdef SQL_WLONGVARCHAR
12385 	case SQL_WLONGVARCHAR:
12386 	    mktypeinfo(s, 1, asize, "longwvarchar", SQL_WLONGVARCHAR, 20);
12387 	    break;
12388 #endif
12389 #endif
12390 #if (HAVE_ENCDEC)
12391 	case SQL_VARBINARY:
12392 	    mktypeinfo(s, 1, asize, "varbinary", SQL_VARBINARY, 30);
12393 	    break;
12394 	case SQL_LONGVARBINARY:
12395 	    mktypeinfo(s, 1, asize, "longvarbinary", SQL_LONGVARBINARY, 31);
12396 	    break;
12397 #endif
12398 #ifdef SQL_BIT
12399 	case SQL_BIT:
12400 	    mktypeinfo(s, 1, asize, "bit", SQL_BIT, 29);
12401 	    break;
12402 #endif
12403 	default:
12404 	    s->nrows = 0;
12405 	}
12406     }
12407     return SQL_SUCCESS;
12408 }
12409 
12410 #ifndef WINTERFACE
12411 /**
12412  * Return data type information.
12413  * @param stmt statement handle
12414  * @param sqltype which type to retrieve
12415  * @result ODBC error code
12416  */
12417 
12418 SQLRETURN SQL_API
SQLGetTypeInfo(SQLHSTMT stmt,SQLSMALLINT sqltype)12419 SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT sqltype)
12420 {
12421     SQLRETURN ret;
12422 
12423     HSTMT_LOCK(stmt);
12424     ret = drvgettypeinfo(stmt, sqltype);
12425     HSTMT_UNLOCK(stmt);
12426     return ret;
12427 }
12428 #endif
12429 
12430 #ifdef WINTERFACE
12431 /**
12432  * Return data type information (UNICODE version).
12433  * @param stmt statement handle
12434  * @param sqltype which type to retrieve
12435  * @result ODBC error code
12436  */
12437 
12438 SQLRETURN SQL_API
SQLGetTypeInfoW(SQLHSTMT stmt,SQLSMALLINT sqltype)12439 SQLGetTypeInfoW(SQLHSTMT stmt, SQLSMALLINT sqltype)
12440 {
12441     SQLRETURN ret;
12442 
12443     HSTMT_LOCK(stmt);
12444     ret = drvgettypeinfo(stmt, sqltype);
12445     HSTMT_UNLOCK(stmt);
12446     return ret;
12447 }
12448 #endif
12449 
12450 /**
12451  * Columns for result set of SQLStatistics().
12452  */
12453 
12454 static COL statSpec2[] = {
12455     { "SYSTEM", "STATISTICS", "TABLE_QUALIFIER", SCOL_VARCHAR, 50 },
12456     { "SYSTEM", "STATISTICS", "TABLE_OWNER", SCOL_VARCHAR, 50 },
12457     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
12458     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
12459     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
12460     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
12461     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
12462     { "SYSTEM", "STATISTICS", "SEQ_IN_INDEX", SQL_SMALLINT, 50 },
12463     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
12464     { "SYSTEM", "STATISTICS", "COLLATION", SCOL_CHAR, 1 },
12465     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
12466     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
12467     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
12468 };
12469 
12470 static COL statSpec3[] = {
12471     { "SYSTEM", "STATISTICS", "TABLE_CAT", SCOL_VARCHAR, 50 },
12472     { "SYSTEM", "STATISTICS", "TABLE_SCHEM", SCOL_VARCHAR, 50 },
12473     { "SYSTEM", "STATISTICS", "TABLE_NAME", SCOL_VARCHAR, 255 },
12474     { "SYSTEM", "STATISTICS", "NON_UNIQUE", SQL_SMALLINT, 50 },
12475     { "SYSTEM", "STATISTICS", "INDEX_QUALIFIER", SCOL_VARCHAR, 255 },
12476     { "SYSTEM", "STATISTICS", "INDEX_NAME", SCOL_VARCHAR, 255 },
12477     { "SYSTEM", "STATISTICS", "TYPE", SQL_SMALLINT, 50 },
12478     { "SYSTEM", "STATISTICS", "ORDINAL_POSITION", SQL_SMALLINT, 50 },
12479     { "SYSTEM", "STATISTICS", "COLUMN_NAME", SCOL_VARCHAR, 255 },
12480     { "SYSTEM", "STATISTICS", "ASC_OR_DESC", SCOL_CHAR, 1 },
12481     { "SYSTEM", "STATISTICS", "CARDINALITY", SQL_INTEGER, 50 },
12482     { "SYSTEM", "STATISTICS", "PAGES", SQL_INTEGER, 50 },
12483     { "SYSTEM", "STATISTICS", "FILTER_CONDITION", SCOL_VARCHAR, 255 }
12484 };
12485 
12486 /**
12487  * Internal return statistic information on table indices.
12488  * @param stmt statement handle
12489  * @param cat catalog name/pattern or NULL
12490  * @param catLen length of catalog name/pattern or SQL_NTS
12491  * @param schema schema name/pattern or NULL
12492  * @param schemaLen length of schema name/pattern or SQL_NTS
12493  * @param table table name/pattern or NULL
12494  * @param tableLen length of table name/pattern or SQL_NTS
12495  * @param itype type of index information
12496  * @param resv reserved
12497  * @result ODBC error code
12498  */
12499 
12500 static SQLRETURN
drvstatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)12501 drvstatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
12502 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
12503 	      SQLCHAR *table, SQLSMALLINT tableLen,
12504 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
12505 {
12506     SQLRETURN sret;
12507     STMT *s;
12508     DBC *d;
12509     int i, asize, ret, nrows, ncols, offs, namec, uniquec, addipk = 0;
12510     PTRDIFF_T size;
12511     char **rowp, *errp = NULL, tname[512];
12512 
12513     sret = mkresultset(stmt, statSpec2, array_size(statSpec2),
12514 		       statSpec3, array_size(statSpec3), &asize);
12515     if (sret != SQL_SUCCESS) {
12516 	return sret;
12517     }
12518     s = (STMT *) stmt;
12519     d = (DBC *) s->dbc;
12520     if (!table || table[0] == '\0' || table[0] == '%') {
12521 	setstat(s, -1, "need table name", (*s->ov3) ? "HY000" : "S1000");
12522 	return SQL_ERROR;
12523     }
12524     if (tableLen == SQL_NTS) {
12525 	size = sizeof (tname) - 1;
12526     } else {
12527 	size = min(sizeof (tname) - 1, tableLen);
12528     }
12529     strncpy(tname, (char *) table, size);
12530     tname[size] = '\0';
12531     unescpat(tname);
12532     sret = starttran(s);
12533     if (sret != SQL_SUCCESS) {
12534 	return sret;
12535     }
12536     /*
12537      * Try integer primary key (autoincrement) first
12538      */
12539     if (itype == SQL_INDEX_UNIQUE || itype == SQL_INDEX_ALL) {
12540 	int colid, typec, npk = 0, npkint = 0;
12541 
12542 	rowp = 0;
12543 	ret = sqlite_get_table_printf(d->sqlite,
12544 				      "PRAGMA table_info('%q')", &rowp,
12545 				      &nrows, &ncols, NULL, tname);
12546 	if (ret != SQLITE_OK) {
12547 	    goto noipk;
12548 	}
12549 	namec = findcol(rowp, ncols, "name");
12550 	uniquec = findcol(rowp, ncols, "pk");
12551 	typec = findcol(rowp, ncols, "type");
12552 	colid = findcol(rowp, ncols, "cid");
12553 	if (namec < 0 || uniquec < 0 || typec < 0 || colid < 0) {
12554 	    goto noipk;
12555 	}
12556 	for (i = 1; i <= nrows; i++) {
12557 	    if (*rowp[i * ncols + uniquec] != '0') {
12558 		npk++;
12559 		if (strlen(rowp[i * ncols + typec]) == 7 &&
12560 		    strncasecmp(rowp[i * ncols + typec], "integer", 7)
12561 		    == 0) {
12562 		    npkint++;
12563 		}
12564 	    }
12565 	}
12566 	if (npkint == 1 && npk == npkint) {
12567 	    addipk = 1;
12568 	}
12569 noipk:
12570 	sqlite_free_table(rowp);
12571     }
12572     ret = sqlite_get_table_printf(d->sqlite,
12573 				  "PRAGMA index_list('%q')", &rowp,
12574 				  &nrows, &ncols, &errp, tname);
12575     if (ret != SQLITE_OK) {
12576 	setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
12577 		errp ? errp : "unknown error", ret);
12578 	if (errp) {
12579 	    sqlite_freemem(errp);
12580 	    errp = NULL;
12581 	}
12582 	return SQL_ERROR;
12583     }
12584     if (errp) {
12585 	sqlite_freemem(errp);
12586 	errp = NULL;
12587     }
12588     size = 0;
12589     namec = findcol(rowp, ncols, "name");
12590     uniquec = findcol(rowp, ncols, "unique");
12591     if (namec < 0 || uniquec < 0) {
12592 	goto nodata;
12593     }
12594     for (i = 1; i <= nrows; i++) {
12595 	int nnrows, nncols;
12596 	char **rowpp;
12597 	int isuniq;
12598 
12599 	isuniq = *rowp[i * ncols + uniquec] != '0';
12600 	if (isuniq || itype == SQL_INDEX_ALL) {
12601 	    ret = sqlite_get_table_printf(d->sqlite,
12602 					  "PRAGMA index_info('%q')", &rowpp,
12603 					  &nnrows, &nncols, NULL,
12604 					  rowp[i * ncols + namec]);
12605 	    if (ret == SQLITE_OK) {
12606 		size += nnrows;
12607 		sqlite_free_table(rowpp);
12608 	    }
12609 	}
12610     }
12611 nodata:
12612     if (addipk) {
12613 	size++;
12614     }
12615     if (size == 0) {
12616 	sqlite_free_table(rowp);
12617 	return SQL_SUCCESS;
12618     }
12619     s->nrows = size;
12620     size = (size + 1) * asize;
12621     s->rows = xmalloc((size + 1) * sizeof (char *));
12622     if (!s->rows) {
12623 	s->nrows = 0;
12624 	return nomem(s);
12625     }
12626     s->rows[0] = (char *) size;
12627     s->rows += 1;
12628     memset(s->rows, 0, sizeof (char *) * size);
12629     s->rowfree = freerows;
12630     offs = 0;
12631     if (addipk) {
12632 	char **rowpp;
12633 	int ncols2, nrows2;
12634 
12635 	rowpp = 0;
12636 	ret = sqlite_get_table_printf(d->sqlite,
12637 				      "PRAGMA table_info('%q')", &rowpp,
12638 				      &nrows2, &ncols2, NULL, tname);
12639 	if (ret == SQLITE_OK) {
12640 	    int namecc, uniquecc, colid, typec, roffs;
12641 
12642 	    namecc = findcol(rowpp, ncols2, "name");
12643 	    uniquecc = findcol(rowpp, ncols2, "pk");
12644 	    typec = findcol(rowpp, ncols2, "type");
12645 	    colid = findcol(rowpp, ncols2, "cid");
12646 	    if (namecc < 0 || uniquecc < 0 || typec < 0 || colid < 0) {
12647 		addipk = 0;
12648 		s->nrows--;
12649 		goto nodata2;
12650 	    }
12651 	    for (i = 1; i <= nrows2; i++) {
12652 		if (*rowpp[i * ncols2 + uniquecc] != '0' &&
12653 		    strlen(rowpp[i * ncols2 + typec]) == 7 &&
12654 		    strncasecmp(rowpp[i * ncols2 + typec], "integer", 7)
12655 		    == 0) {
12656 		    break;
12657 		}
12658 	    }
12659 	    if (i > nrows) {
12660 		addipk = 0;
12661 		s->nrows--;
12662 		goto nodata2;
12663 	    }
12664 	    roffs = s->ncols;
12665 #if defined(_WIN32) || defined(_WIN64)
12666 	    s->rows[roffs + 0] = xstrdup(d->xcelqrx ? "main" : "");
12667 	    s->rows[roffs + 1] = xstrdup("");
12668 #else
12669 	    s->rows[roffs + 0] = xstrdup("");
12670 	    s->rows[roffs + 1] = xstrdup("");
12671 #endif
12672 	    s->rows[roffs + 2] = xstrdup(tname);
12673 	    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
12674 	    s->rows[roffs + 5] = xstrdup("(autoindex 0)");
12675 	    s->rows[roffs + 6] = xstrdup(stringify(SQL_INDEX_OTHER));
12676 	    s->rows[roffs + 7] = xstrdup("1");
12677 	    s->rows[roffs + 8] = xstrdup(rowpp[i * ncols2 + namecc]);
12678 	    s->rows[roffs + 9] = xstrdup("A");
12679 	}
12680 nodata2:
12681 	sqlite_free_table(rowpp);
12682     }
12683     for (i = 1; i <= nrows; i++) {
12684 	int nnrows, nncols;
12685 	char **rowpp;
12686 
12687 	if (*rowp[i * ncols + uniquec] != '0' || itype == SQL_INDEX_ALL) {
12688 	    int k;
12689 
12690 	    ret = sqlite_get_table_printf(d->sqlite,
12691 					  "PRAGMA index_info('%q')", &rowpp,
12692 					  &nnrows, &nncols, NULL,
12693 					  rowp[i * ncols + namec]);
12694 	    if (ret != SQLITE_OK) {
12695 		continue;
12696 	    }
12697 	    for (k = 0; nnrows && k < nncols; k++) {
12698 		if (strcmp(rowpp[k], "name") == 0) {
12699 		    int m;
12700 
12701 		    for (m = 1; m <= nnrows; m++) {
12702 			int roffs = (offs + addipk + m) * s->ncols;
12703 			int isuniq;
12704 
12705 			isuniq = *rowp[i * ncols + uniquec] != '0';
12706 			s->rows[roffs + 0] = xstrdup("");
12707 			s->rows[roffs + 1] = xstrdup("");
12708 			s->rows[roffs + 2] = xstrdup(tname);
12709 			if (isuniq) {
12710 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_FALSE));
12711 			} else {
12712 			    s->rows[roffs + 3] = xstrdup(stringify(SQL_TRUE));
12713 			}
12714 			s->rows[roffs + 5] = xstrdup(rowp[i * ncols + namec]);
12715 			s->rows[roffs + 6] =
12716 			    xstrdup(stringify(SQL_INDEX_OTHER));
12717 			s->rows[roffs + 8] = xstrdup(rowpp[m * nncols + k]);
12718 			s->rows[roffs + 9] = xstrdup("A");
12719 		    }
12720 		} else if (strcmp(rowpp[k], "seqno") == 0) {
12721 		    int m;
12722 
12723 		    for (m = 1; m <= nnrows; m++) {
12724 			int roffs = (offs + addipk + m) * s->ncols;
12725 			int pos = m - 1;
12726 			char buf[32];
12727 
12728 			sscanf(rowpp[m * nncols + k], "%d", &pos);
12729 			sprintf(buf, "%d", pos + 1);
12730 			s->rows[roffs + 7] = xstrdup(buf);
12731 		    }
12732 		}
12733 	    }
12734 	    offs += nnrows;
12735 	    sqlite_free_table(rowpp);
12736 	}
12737     }
12738     sqlite_free_table(rowp);
12739     return SQL_SUCCESS;
12740 }
12741 
12742 #ifndef WINTERFACE
12743 /**
12744  * Return statistic information on table indices.
12745  * @param stmt statement handle
12746  * @param cat catalog name/pattern or NULL
12747  * @param catLen length of catalog name/pattern or SQL_NTS
12748  * @param schema schema name/pattern or NULL
12749  * @param schemaLen length of schema name/pattern or SQL_NTS
12750  * @param table table name/pattern or NULL
12751  * @param tableLen length of table name/pattern or SQL_NTS
12752  * @param itype type of index information
12753  * @param resv reserved
12754  * @result ODBC error code
12755  */
12756 
12757 SQLRETURN SQL_API
SQLStatistics(SQLHSTMT stmt,SQLCHAR * cat,SQLSMALLINT catLen,SQLCHAR * schema,SQLSMALLINT schemaLen,SQLCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)12758 SQLStatistics(SQLHSTMT stmt, SQLCHAR *cat, SQLSMALLINT catLen,
12759 	      SQLCHAR *schema, SQLSMALLINT schemaLen,
12760 	      SQLCHAR *table, SQLSMALLINT tableLen,
12761 	      SQLUSMALLINT itype, SQLUSMALLINT resv)
12762 {
12763     SQLRETURN ret;
12764 
12765     HSTMT_LOCK(stmt);
12766     ret = drvstatistics(stmt, cat, catLen, schema, schemaLen,
12767 			table, tableLen, itype, resv);
12768     HSTMT_UNLOCK(stmt);
12769     return ret;
12770 }
12771 #endif
12772 
12773 #ifdef WINTERFACE
12774 /**
12775  * Return statistic information on table indices (UNICODE version).
12776  * @param stmt statement handle
12777  * @param cat catalog name/pattern or NULL
12778  * @param catLen length of catalog name/pattern or SQL_NTS
12779  * @param schema schema name/pattern or NULL
12780  * @param schemaLen length of schema name/pattern or SQL_NTS
12781  * @param table table name/pattern or NULL
12782  * @param tableLen length of table name/pattern or SQL_NTS
12783  * @param itype type of index information
12784  * @param resv reserved
12785  * @result ODBC error code
12786  */
12787 
12788 SQLRETURN SQL_API
SQLStatisticsW(SQLHSTMT stmt,SQLWCHAR * cat,SQLSMALLINT catLen,SQLWCHAR * schema,SQLSMALLINT schemaLen,SQLWCHAR * table,SQLSMALLINT tableLen,SQLUSMALLINT itype,SQLUSMALLINT resv)12789 SQLStatisticsW(SQLHSTMT stmt, SQLWCHAR *cat, SQLSMALLINT catLen,
12790 	       SQLWCHAR *schema, SQLSMALLINT schemaLen,
12791 	       SQLWCHAR *table, SQLSMALLINT tableLen,
12792 	       SQLUSMALLINT itype, SQLUSMALLINT resv)
12793 {
12794     char *c = NULL, *s = NULL, *t = NULL;
12795     SQLRETURN ret;
12796 
12797     HSTMT_LOCK(stmt);
12798     if (cat) {
12799 	c = uc_to_utf_c(cat, catLen);
12800 	if (!c) {
12801 	    ret = nomem((STMT *) stmt);
12802 	    goto done;
12803 	}
12804     }
12805     if (schema) {
12806 	s = uc_to_utf_c(schema, schemaLen);
12807 	if (!s) {
12808 	    ret = nomem((STMT *) stmt);
12809 	    goto done;
12810 	}
12811     }
12812     if (table) {
12813 	t = uc_to_utf_c(table, tableLen);
12814 	if (!t) {
12815 	    ret = nomem((STMT *) stmt);
12816 	    goto done;
12817 	}
12818     }
12819     ret = drvstatistics(stmt, (SQLCHAR *) c, SQL_NTS, (SQLCHAR *) s, SQL_NTS,
12820 			(SQLCHAR *) t, SQL_NTS, itype, resv);
12821 done:
12822     HSTMT_UNLOCK(stmt);
12823     uc_free(t);
12824     uc_free(s);
12825     uc_free(c);
12826     return ret;
12827 }
12828 #endif
12829 
12830 /**
12831  * Retrieve row data after fetch.
12832  * @param stmt statement handle
12833  * @param col column number, starting at 1
12834  * @param type output type
12835  * @param val output buffer
12836  * @param len length of output buffer
12837  * @param lenp output length
12838  * @result ODBC error code
12839  */
12840 
12841 SQLRETURN SQL_API
SQLGetData(SQLHSTMT stmt,SQLUSMALLINT col,SQLSMALLINT type,SQLPOINTER val,SQLLEN len,SQLLEN * lenp)12842 SQLGetData(SQLHSTMT stmt, SQLUSMALLINT col, SQLSMALLINT type,
12843 	   SQLPOINTER val, SQLLEN len, SQLLEN *lenp)
12844 {
12845     STMT *s;
12846     SQLRETURN ret = SQL_ERROR;
12847 
12848     HSTMT_LOCK(stmt);
12849     if (stmt == SQL_NULL_HSTMT) {
12850 	return SQL_INVALID_HANDLE;
12851     }
12852     s = (STMT *) stmt;
12853     if (col == 0 && s->bkmrk && type == SQL_C_BOOKMARK) {
12854 	*((long *) val) = s->rowp;
12855 	if (lenp) {
12856 	    *lenp = sizeof (long);
12857 	}
12858 	ret = SQL_SUCCESS;
12859 	goto done;
12860     }
12861     if (col < 1 || col > s->ncols) {
12862 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
12863 	goto done;
12864     }
12865     --col;
12866     ret = getrowdata(s, col, type, val, len, lenp, 1);
12867 done:
12868     HSTMT_UNLOCK(stmt);
12869     return ret;
12870 }
12871 
12872 /**
12873  * Internal: fetch and bind from statement's current row
12874  * @param s statement pointer
12875  * @param rsi rowset index
12876  * @result ODBC error code
12877  */
12878 
12879 static SQLRETURN
dofetchbind(STMT * s,int rsi)12880 dofetchbind(STMT *s, int rsi)
12881 {
12882     int ret, i, withinfo = 0;
12883 
12884     s->row_status0[rsi] = SQL_ROW_SUCCESS;
12885     if (s->bkmrk && s->bkmrkcol.valp) {
12886 	long *val;
12887 
12888 	if (s->bind_type != SQL_BIND_BY_COLUMN) {
12889 	    val = (long *) ((char *) s->bkmrkcol.valp + s->bind_type * rsi);
12890 	} else {
12891 	    val = (long *) s->bkmrkcol.valp + rsi;
12892 	}
12893 	if (s->bind_offs) {
12894 	    val = (long *) ((char *) val + *s->bind_offs);
12895 	}
12896 	*val = s->rowp;
12897 	if (s->bkmrkcol.lenp) {
12898 	    SQLLEN *ival;
12899 
12900 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
12901 		ival = (SQLLEN *) ((char *) s->bkmrkcol.lenp +
12902 				   s->bind_type * rsi);
12903 	    } else {
12904 		ival = &s->bkmrkcol.lenp[rsi];
12905 	    }
12906 	    if (s->bind_offs) {
12907 		ival = (SQLLEN *) ((char *) ival + *s->bind_offs);
12908 	    }
12909 	    *ival = sizeof (long);
12910 	}
12911     }
12912     ret = SQL_SUCCESS;
12913     for (i = 0; s->bindcols && i < s->ncols; i++) {
12914 	BINDCOL *b = &s->bindcols[i];
12915 	SQLPOINTER dp = 0;
12916 	SQLLEN *lp = 0;
12917 
12918 	b->offs = 0;
12919 	if (b->valp) {
12920 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
12921 		dp = (SQLPOINTER) ((char *) b->valp + s->bind_type * rsi);
12922 	    } else {
12923 		dp = (SQLPOINTER) ((char *) b->valp + b->max * rsi);
12924 	    }
12925 	    if (s->bind_offs) {
12926 		dp = (SQLPOINTER) ((char *) dp + *s->bind_offs);
12927 	    }
12928 	}
12929 	if (b->lenp) {
12930 	    if (s->bind_type != SQL_BIND_BY_COLUMN) {
12931 		lp = (SQLLEN *) ((char *) b->lenp + s->bind_type * rsi);
12932 	    } else {
12933 		lp = b->lenp + rsi;
12934 	    }
12935 	    if (s->bind_offs) {
12936 		lp = (SQLLEN *) ((char *) lp + *s->bind_offs);
12937 	    }
12938 	}
12939 	if (dp || lp) {
12940 	    ret = getrowdata(s, (SQLUSMALLINT) i, b->type, dp, b->max, lp, 0);
12941 	    if (!SQL_SUCCEEDED(ret)) {
12942 		s->row_status0[rsi] = SQL_ROW_ERROR;
12943 		break;
12944 	    }
12945 	    if (ret != SQL_SUCCESS) {
12946 		withinfo = 1;
12947 #ifdef SQL_ROW_SUCCESS_WITH_INFO
12948 		s->row_status0[rsi] = SQL_ROW_SUCCESS_WITH_INFO;
12949 #endif
12950 	    }
12951 	}
12952     }
12953     if (SQL_SUCCEEDED(ret)) {
12954 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
12955     }
12956     return ret;
12957 }
12958 
12959 /**
12960  * Internal fetch function for SQLFetchScroll() and SQLExtendedFetch().
12961  * @param stmt statement handle
12962  * @param orient fetch direction
12963  * @param offset offset for fetch direction
12964  * @result ODBC error code
12965  */
12966 
12967 static SQLRETURN
drvfetchscroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLINTEGER offset)12968 drvfetchscroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLINTEGER offset)
12969 {
12970     STMT *s;
12971     int i, withinfo = 0;
12972     SQLRETURN ret;
12973 
12974     if (stmt == SQL_NULL_HSTMT) {
12975 	return SQL_INVALID_HANDLE;
12976     }
12977     s = (STMT *) stmt;
12978     for (i = 0; i < s->rowset_size; i++) {
12979 	s->row_status0[i] = SQL_ROW_NOROW;
12980     }
12981     if (s->row_status) {
12982 	memcpy(s->row_status, s->row_status0,
12983 	       sizeof (SQLUSMALLINT) * s->rowset_size);
12984     }
12985     s->row_count0 = 0;
12986     if (s->row_count) {
12987 	*s->row_count = s->row_count0;
12988     }
12989     if (!s->bindcols) {
12990 	for (i = 0; i < s->rowset_size; i++) {
12991 	    s->row_status0[i] = SQL_ROW_ERROR;
12992 	}
12993 	ret = SQL_ERROR;
12994 	i = 0;
12995 	goto done2;
12996     }
12997     if (s->isselect != 1 && s->isselect != -1) {
12998 	setstat(s, -1, "no result set available", "24000");
12999 	ret = SQL_ERROR;
13000 	i = s->nrows;
13001 	goto done2;
13002     }
13003     if (s->curtype == SQL_CURSOR_FORWARD_ONLY && orient != SQL_FETCH_NEXT) {
13004 	setstat(s, -1, "wrong fetch direction", "01000");
13005 	ret = SQL_ERROR;
13006 	i = 0;
13007 	goto done2;
13008     }
13009     ret = SQL_SUCCESS;
13010     i = 0;
13011     if (((DBC *) (s->dbc))->vm_stmt == s && s->vm) {
13012 	s->rowp = 0;
13013 	for (; i < s->rowset_size; i++) {
13014 	    ret = vm_step(s);
13015 	    if (ret != SQL_SUCCESS) {
13016 		s->row_status0[i] = SQL_ROW_ERROR;
13017 		break;
13018 	    }
13019 	    if (s->nrows < 1) {
13020 		break;
13021 	    }
13022 	    ret = dofetchbind(s, i);
13023 	    if (!SQL_SUCCEEDED(ret)) {
13024 		break;
13025 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
13026 		withinfo = 1;
13027 	    }
13028 	}
13029     } else if (s->rows) {
13030 	switch (orient) {
13031 	case SQL_FETCH_NEXT:
13032 	    if (s->nrows < 1) {
13033 		return SQL_NO_DATA;
13034 	    }
13035 	    if (s->rowp < 0) {
13036 		s->rowp = -1;
13037 	    }
13038 	    if (s->rowp >= s->nrows) {
13039 		s->rowp = s->nrows;
13040 		return SQL_NO_DATA;
13041 	    }
13042 	    break;
13043 	case SQL_FETCH_PRIOR:
13044 	    if (s->nrows < 1 || s->rowp <= 0) {
13045 		s->rowp = -1;
13046 		return SQL_NO_DATA;
13047 	    }
13048 	    s->rowp -= s->rowset_size + 1;
13049 	    if (s->rowp < -1) {
13050 		s->rowp = -1;
13051 		return SQL_NO_DATA;
13052 	    }
13053 	    break;
13054 	case SQL_FETCH_FIRST:
13055 	    if (s->nrows < 1) {
13056 		return SQL_NO_DATA;
13057 	    }
13058 	    s->rowp = -1;
13059 	    break;
13060 	case SQL_FETCH_LAST:
13061 	    if (s->nrows < 1) {
13062 		return SQL_NO_DATA;
13063 	    }
13064 	    s->rowp = s->nrows - s->rowset_size;
13065 	    if (--s->rowp < -1) {
13066 		s->rowp = -1;
13067 	    }
13068 	    break;
13069 	case SQL_FETCH_ABSOLUTE:
13070 	    if (offset == 0) {
13071 		s->rowp = -1;
13072 		return SQL_NO_DATA;
13073 	    } else if (offset < 0) {
13074 		if (0 - offset <= s->nrows) {
13075 		    s->rowp = s->nrows + offset - 1;
13076 		    break;
13077 		}
13078 		s->rowp = -1;
13079 		return SQL_NO_DATA;
13080 	    } else if (offset > s->nrows) {
13081 		s->rowp = s->nrows;
13082 		return SQL_NO_DATA;
13083 	    }
13084 	    s->rowp = offset - 1 - 1;
13085 	    break;
13086 	case SQL_FETCH_RELATIVE:
13087 	    if (offset >= 0) {
13088 		s->rowp += offset * s->rowset_size - 1;
13089 		if (s->rowp >= s->nrows) {
13090 		    s->rowp = s->nrows;
13091 		    return SQL_NO_DATA;
13092 		}
13093 	    } else {
13094 		s->rowp += offset * s->rowset_size - 1;
13095 		if (s->rowp < -1) {
13096 		    s->rowp = -1;
13097 		    return SQL_NO_DATA;
13098 		}
13099 	    }
13100 	    break;
13101 	case SQL_FETCH_BOOKMARK:
13102 	    if (s->bkmrk) {
13103 		if (offset < 0 || offset >= s->nrows) {
13104 		    return SQL_NO_DATA;
13105 		}
13106 		s->rowp = offset - 1;
13107 		break;
13108 	    }
13109 	    /* fall through */
13110 	default:
13111 	    s->row_status0[0] = SQL_ROW_ERROR;
13112 	    ret = SQL_ERROR;
13113 	    goto done;
13114 	}
13115 	for (; i < s->rowset_size; i++) {
13116 	    ++s->rowp;
13117 	    if (s->rowp < 0 || s->rowp >= s->nrows) {
13118 		break;
13119 	    }
13120 	    ret = dofetchbind(s, i);
13121 	    if (!SQL_SUCCEEDED(ret)) {
13122 		break;
13123 	    } else if (ret == SQL_SUCCESS_WITH_INFO) {
13124 		withinfo = 1;
13125 	    }
13126 	}
13127     }
13128 done:
13129     if (i == 0) {
13130 	if (SQL_SUCCEEDED(ret)) {
13131 	    return SQL_NO_DATA;
13132 	}
13133 	return ret;
13134     }
13135     if (SQL_SUCCEEDED(ret)) {
13136 	ret = withinfo ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
13137     }
13138 done2:
13139     if (s->row_status) {
13140 	memcpy(s->row_status, s->row_status0,
13141 	       sizeof (SQLUSMALLINT) * s->rowset_size);
13142     }
13143     s->row_count0 = i;
13144     if (s->row_count) {
13145 	*s->row_count = s->row_count0;
13146     }
13147     return ret;
13148 }
13149 
13150 /**
13151  * Fetch next result row.
13152  * @param stmt statement handle
13153  * @result ODBC error code
13154  */
13155 
13156 SQLRETURN SQL_API
SQLFetch(SQLHSTMT stmt)13157 SQLFetch(SQLHSTMT stmt)
13158 {
13159     SQLRETURN ret;
13160 
13161     HSTMT_LOCK(stmt);
13162     ret = drvfetchscroll(stmt, SQL_FETCH_NEXT, 0);
13163     HSTMT_UNLOCK(stmt);
13164     return ret;
13165 }
13166 
13167 /**
13168  * Fetch result row with scrolling.
13169  * @param stmt statement handle
13170  * @param orient fetch direction
13171  * @param offset offset for fetch direction
13172  * @result ODBC error code
13173  */
13174 
13175 SQLRETURN SQL_API
SQLFetchScroll(SQLHSTMT stmt,SQLSMALLINT orient,SQLLEN offset)13176 SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT orient, SQLLEN offset)
13177 {
13178     SQLRETURN ret;
13179 
13180     HSTMT_LOCK(stmt);
13181     ret = drvfetchscroll(stmt, orient, offset);
13182     HSTMT_UNLOCK(stmt);
13183     return ret;
13184 }
13185 
13186 /**
13187  * Fetch result row with scrolling and row status.
13188  * @param stmt statement handle
13189  * @param orient fetch direction
13190  * @param offset offset for fetch direction
13191  * @param rowcount output number of fetched rows
13192  * @param rowstatus array for row stati
13193  * @result ODBC error code
13194  */
13195 
13196 SQLRETURN SQL_API
SQLExtendedFetch(SQLHSTMT stmt,SQLUSMALLINT orient,SQLROWOFFSET offset,SQLROWSETSIZE * rowcount,SQLUSMALLINT * rowstatus)13197 SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT orient, SQLROWOFFSET offset,
13198 		 SQLROWSETSIZE *rowcount, SQLUSMALLINT *rowstatus)
13199 {
13200     STMT *s;
13201     SQLRETURN ret;
13202     SQLUSMALLINT *rst;
13203 
13204     HSTMT_LOCK(stmt);
13205     if (stmt == SQL_NULL_HSTMT) {
13206 	return SQL_INVALID_HANDLE;
13207     }
13208     s = (STMT *) stmt;
13209     /* temporarily turn off SQL_ATTR_ROW_STATUS_PTR */
13210     rst = s->row_status;
13211     s->row_status = 0;
13212     ret = drvfetchscroll(stmt, orient, offset);
13213     s->row_status = rst;
13214     if (rowstatus) {
13215 	memcpy(rowstatus, s->row_status0,
13216 	       sizeof (SQLUSMALLINT) * s->rowset_size);
13217     }
13218     if (rowcount) {
13219 	*rowcount = s->row_count0;
13220     }
13221     HSTMT_UNLOCK(stmt);
13222     return ret;
13223 }
13224 
13225 /**
13226  * Return number of affected rows of HSTMT.
13227  * @param stmt statement handle
13228  * @param nrows output number of rows
13229  * @result ODBC error code
13230  */
13231 
13232 SQLRETURN SQL_API
SQLRowCount(SQLHSTMT stmt,SQLLEN * nrows)13233 SQLRowCount(SQLHSTMT stmt, SQLLEN *nrows)
13234 {
13235     STMT *s;
13236 
13237     HSTMT_LOCK(stmt);
13238     if (stmt == SQL_NULL_HSTMT) {
13239 	return SQL_INVALID_HANDLE;
13240     }
13241     s = (STMT *) stmt;
13242     if (nrows) {
13243 	*nrows = s->isselect ? 0 : s->nrows;
13244     }
13245     HSTMT_UNLOCK(stmt);
13246     return SQL_SUCCESS;
13247 }
13248 
13249 /**
13250  * Return number of columns of result set given HSTMT.
13251  * @param stmt statement handle
13252  * @param ncols output number of columns
13253  * @result ODBC error code
13254  */
13255 
13256 SQLRETURN SQL_API
SQLNumResultCols(SQLHSTMT stmt,SQLSMALLINT * ncols)13257 SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT *ncols)
13258 {
13259     STMT *s;
13260 
13261     HSTMT_LOCK(stmt);
13262     if (stmt == SQL_NULL_HSTMT) {
13263 	return SQL_INVALID_HANDLE;
13264     }
13265     s = (STMT *) stmt;
13266     if (ncols) {
13267 	*ncols = s->ncols;
13268     }
13269     HSTMT_UNLOCK(stmt);
13270     return SQL_SUCCESS;
13271 }
13272 
13273 /**
13274  * Internal describe column information.
13275  * @param stmt statement handle
13276  * @param col column number, starting at 1
13277  * @param name buffer for column name
13278  * @param nameMax length of name buffer
13279  * @param nameLen output length of column name
13280  * @param type output SQL type
13281  * @param size output column size
13282  * @param digits output number of digits
13283  * @param nullable output NULL allowed indicator
13284  * @result ODBC error code
13285  */
13286 
13287 static SQLRETURN
drvdescribecol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)13288 drvdescribecol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
13289 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
13290 	       SQLSMALLINT *type, SQLULEN *size,
13291 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
13292 {
13293     STMT *s;
13294     COL *c;
13295     int didname = 0;
13296 
13297     if (stmt == SQL_NULL_HSTMT) {
13298 	return SQL_INVALID_HANDLE;
13299     }
13300     s = (STMT *) stmt;
13301     if (!s->cols) {
13302 	setstat(s, -1, "no columns", (*s->ov3) ? "07009" : "S1002");
13303 	return SQL_ERROR;
13304     }
13305     if (col < 1 || col > s->ncols) {
13306 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
13307 	return SQL_ERROR;
13308     }
13309     c = s->cols + col - 1;
13310     if (name && nameMax > 0) {
13311 	strncpy((char *) name, c->column, nameMax);
13312 	name[nameMax - 1] = '\0';
13313 	didname = 1;
13314     }
13315     if (nameLen) {
13316 	if (didname) {
13317 	    *nameLen = strlen((char *) name);
13318 	} else {
13319 	    *nameLen = strlen(c->column);
13320 	}
13321     }
13322     if (type) {
13323 	*type = c->type;
13324 #ifdef WINTERFACE
13325 	if (s->nowchar[0] || s->nowchar[1]) {
13326 	    switch (c->type) {
13327 	    case SQL_WCHAR:
13328 		*type = SQL_CHAR;
13329 		break;
13330 	    case SQL_WVARCHAR:
13331 		*type = SQL_VARCHAR;
13332 		break;
13333 #ifdef SQL_LONGVARCHAR
13334 	    case SQL_WLONGVARCHAR:
13335 		*type = SQL_LONGVARCHAR;
13336 		break;
13337 #endif
13338 	    }
13339 	}
13340 #endif
13341     }
13342     if (size) {
13343 	*size = c->size;
13344     }
13345     if (digits) {
13346 	*digits = 0;
13347     }
13348     if (nullable) {
13349 	*nullable = 1;
13350     }
13351     return SQL_SUCCESS;
13352 }
13353 
13354 #ifndef WINTERFACE
13355 /**
13356  * Describe column information.
13357  * @param stmt statement handle
13358  * @param col column number, starting at 1
13359  * @param name buffer for column name
13360  * @param nameMax length of name buffer
13361  * @param nameLen output length of column name
13362  * @param type output SQL type
13363  * @param size output column size
13364  * @param digits output number of digits
13365  * @param nullable output NULL allowed indicator
13366  * @result ODBC error code
13367  */
13368 
13369 SQLRETURN SQL_API
SQLDescribeCol(SQLHSTMT stmt,SQLUSMALLINT col,SQLCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)13370 SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT col, SQLCHAR *name,
13371 	       SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
13372 	       SQLSMALLINT *type, SQLULEN *size,
13373 	       SQLSMALLINT *digits, SQLSMALLINT *nullable)
13374 {
13375     SQLRETURN ret;
13376 
13377     HSTMT_LOCK(stmt);
13378     ret = drvdescribecol(stmt, col, name, nameMax, nameLen,
13379 			 type, size, digits, nullable);
13380     HSTMT_UNLOCK(stmt);
13381     return ret;
13382 }
13383 #endif
13384 
13385 #ifdef WINTERFACE
13386 /**
13387  * Describe column information (UNICODE version).
13388  * @param stmt statement handle
13389  * @param col column number, starting at 1
13390  * @param name buffer for column name
13391  * @param nameMax length of name buffer
13392  * @param nameLen output length of column name
13393  * @param type output SQL type
13394  * @param size output column size
13395  * @param digits output number of digits
13396  * @param nullable output NULL allowed indicator
13397  * @result ODBC error code
13398  */
13399 
13400 SQLRETURN SQL_API
SQLDescribeColW(SQLHSTMT stmt,SQLUSMALLINT col,SQLWCHAR * name,SQLSMALLINT nameMax,SQLSMALLINT * nameLen,SQLSMALLINT * type,SQLULEN * size,SQLSMALLINT * digits,SQLSMALLINT * nullable)13401 SQLDescribeColW(SQLHSTMT stmt, SQLUSMALLINT col, SQLWCHAR *name,
13402 		SQLSMALLINT nameMax, SQLSMALLINT *nameLen,
13403 		SQLSMALLINT *type, SQLULEN *size,
13404 		SQLSMALLINT *digits, SQLSMALLINT *nullable)
13405 {
13406     SQLRETURN ret;
13407     SQLSMALLINT len = 0;
13408 
13409     HSTMT_LOCK(stmt);
13410     ret = drvdescribecol(stmt, col, (SQLCHAR *) name,
13411 			 (SQLSMALLINT) (nameMax * sizeof (SQLWCHAR)),
13412 			 &len, type, size, digits, nullable);
13413     if (ret == SQL_SUCCESS) {
13414 	if (name) {
13415 	    if (len > 0) {
13416 		SQLWCHAR *n = NULL;
13417 
13418 		n = uc_from_utf((SQLCHAR *) name, len);
13419 		if (n) {
13420 		    uc_strncpy(name, n, nameMax);
13421 		    n[len] = 0;
13422 		    len = min(nameMax, uc_strlen(n));
13423 		    uc_free(n);
13424 		} else {
13425 		    len = 0;
13426 		}
13427 	    }
13428 	    if (len <= 0) {
13429 		len = 0;
13430 		if (nameMax > 0) {
13431 		    name[0] = 0;
13432 		}
13433 	    }
13434 	} else {
13435 	    STMT *s = (STMT *) stmt;
13436 	    COL *c = s->cols + col - 1;
13437 
13438 	    len = 0;
13439 	    if (c->column) {
13440 		len = strlen(c->column);
13441 	    }
13442 	}
13443 	if (nameLen) {
13444 	    *nameLen = len;
13445 	}
13446     }
13447     HSTMT_UNLOCK(stmt);
13448     return ret;
13449 }
13450 #endif
13451 
13452 /**
13453  * Internal retrieve column attributes.
13454  * @param stmt statement handle
13455  * @param col column number, starting at 1
13456  * @param id attribute id
13457  * @param val output buffer
13458  * @param valMax length of output buffer
13459  * @param valLen output length
13460  * @param val2 integer output buffer
13461  * @result ODBC error code
13462  */
13463 
13464 static SQLRETURN
drvcolattributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)13465 drvcolattributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
13466 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
13467 		 SQLLEN *val2)
13468 {
13469     STMT *s;
13470     COL *c;
13471     SQLSMALLINT dummy;
13472     char *valc = (char *) val;
13473 
13474     if (stmt == SQL_NULL_HSTMT) {
13475 	return SQL_INVALID_HANDLE;
13476     }
13477     s = (STMT *) stmt;
13478     if (!s->cols) {
13479 	return SQL_ERROR;
13480     }
13481     if (!valLen) {
13482 	valLen = &dummy;
13483     }
13484     if (id == SQL_COLUMN_COUNT) {
13485 	if (val2) {
13486 	    *val2 = s->ncols;
13487 	}
13488 	*valLen = sizeof (int);
13489 	return SQL_SUCCESS;
13490     }
13491     if (id == SQL_COLUMN_TYPE && col == 0) {
13492 	if (val2) {
13493 	    *val2 = SQL_INTEGER;
13494 	}
13495 	*valLen = sizeof (int);
13496 	return SQL_SUCCESS;
13497     }
13498 #ifdef SQL_DESC_OCTET_LENGTH
13499     if (id == SQL_DESC_OCTET_LENGTH && col == 0) {
13500 	if (val2) {
13501 	    *val2 = 4;
13502 	}
13503 	*valLen = sizeof (int);
13504 	return SQL_SUCCESS;
13505     }
13506 #endif
13507     if (col < 1 || col > s->ncols) {
13508 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009": "S1002");
13509 	return SQL_ERROR;
13510     }
13511     c = s->cols + col - 1;
13512 
13513     switch (id) {
13514     case SQL_COLUMN_LABEL:
13515 	if (c->label) {
13516 	    if (valc && valMax > 0) {
13517 		strncpy(valc, c->label, valMax);
13518 		valc[valMax - 1] = '\0';
13519 	    }
13520 	    *valLen = strlen(c->label);
13521 	    goto checkLen;
13522 	}
13523 	/* fall through */
13524     case SQL_COLUMN_NAME:
13525     case SQL_DESC_NAME:
13526 	if (valc && valMax > 0) {
13527 	    strncpy(valc, c->column, valMax);
13528 	    valc[valMax - 1] = '\0';
13529 	}
13530 	*valLen = strlen(c->column);
13531 checkLen:
13532 	if (*valLen >= valMax) {
13533 	    setstat(s, -1, "data right truncated", "01004");
13534 	    return SQL_SUCCESS_WITH_INFO;
13535 	}
13536 	return SQL_SUCCESS;
13537 #ifdef SQL_DESC_BASE_COLUMN_NAME
13538     case SQL_DESC_BASE_COLUMN_NAME:
13539 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
13540 	    if (valc && valMax > 0) {
13541 		valc[0] = '\0';
13542 	    }
13543 	    *valLen = 0;
13544 	} else if (valc && valMax > 0) {
13545 	    strncpy(valc, c->column, valMax);
13546 	    valc[valMax - 1] = '\0';
13547 	    *valLen = strlen(c->column);
13548 	}
13549 	goto checkLen;
13550 #endif
13551     case SQL_COLUMN_TYPE:
13552     case SQL_DESC_TYPE:
13553 #ifdef WINTERFACE
13554 	{
13555 	    int type = c->type;
13556 
13557 	    if (s->nowchar[0] || s->nowchar[1]) {
13558 		switch (type) {
13559 		case SQL_WCHAR:
13560 		    type = SQL_CHAR;
13561 		    break;
13562 		case SQL_WVARCHAR:
13563 		    type = SQL_VARCHAR;
13564 		    break;
13565 #ifdef SQL_LONGVARCHAR
13566 		case SQL_WLONGVARCHAR:
13567 		    type = SQL_LONGVARCHAR;
13568 		    break;
13569 		}
13570 	    }
13571 	    if (val2) {
13572 		*val2 = type;
13573 	    }
13574 #endif
13575 	}
13576 #else
13577 	if (val2) {
13578 	    *val2 = c->type;
13579 	}
13580 #endif
13581 	*valLen = sizeof (int);
13582 	return SQL_SUCCESS;
13583     case SQL_COLUMN_DISPLAY_SIZE:
13584 	if (val2) {
13585 	    *val2 = c->size;
13586 	}
13587 	*valLen = sizeof (int);
13588 	return SQL_SUCCESS;
13589     case SQL_COLUMN_UNSIGNED:
13590 	if (val2) {
13591 	    *val2 = c->nosign ? SQL_TRUE : SQL_FALSE;
13592 	}
13593 	*valLen = sizeof (int);
13594 	return SQL_SUCCESS;
13595     case SQL_COLUMN_SCALE:
13596     case SQL_DESC_SCALE:
13597 	if (val2) {
13598 	    *val2 = c->scale;
13599 	}
13600 	*valLen = sizeof (int);
13601 	return SQL_SUCCESS;
13602     case SQL_COLUMN_PRECISION:
13603     case SQL_DESC_PRECISION:
13604 	if (val2) {
13605 	    switch (c->type) {
13606 	    case SQL_SMALLINT:
13607 		*val2 = 5;
13608 		break;
13609 	    case SQL_INTEGER:
13610 		*val2 = 10;
13611 		break;
13612 	    case SQL_FLOAT:
13613 	    case SQL_REAL:
13614 	    case SQL_DOUBLE:
13615 		*val2 = 15;
13616 		break;
13617 	    case SQL_DATE:
13618 		*val2 = 0;
13619 		break;
13620 	    case SQL_TIME:
13621 		*val2 = 0;
13622 		break;
13623 #ifdef SQL_TYPE_TIMESTAMP
13624 	    case SQL_TYPE_TIMESTAMP:
13625 #endif
13626 	    case SQL_TIMESTAMP:
13627 		*val2 = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
13628 		break;
13629 	    default:
13630 		*val2 = c->prec;
13631 		break;
13632 	    }
13633 	}
13634 	*valLen = sizeof (int);
13635 	return SQL_SUCCESS;
13636     case SQL_COLUMN_MONEY:
13637 	if (val2) {
13638 	    *val2 = SQL_FALSE;
13639 	}
13640 	*valLen = sizeof (int);
13641 	return SQL_SUCCESS;
13642     case SQL_COLUMN_AUTO_INCREMENT:
13643 	if (val2) {
13644 	    *val2 = c->autoinc;
13645 	}
13646 	*valLen = sizeof (int);
13647 	return SQL_SUCCESS;
13648     case SQL_COLUMN_LENGTH:
13649     case SQL_DESC_LENGTH:
13650 	if (val2) {
13651 	    *val2 = c->size;
13652 	}
13653 	*valLen = sizeof (int);
13654 	return SQL_SUCCESS;
13655     case SQL_COLUMN_NULLABLE:
13656     case SQL_DESC_NULLABLE:
13657 	if (val2) {
13658 	    *val2 = c->notnull;
13659 	}
13660 	*valLen = sizeof (int);
13661 	return SQL_SUCCESS;
13662     case SQL_COLUMN_SEARCHABLE:
13663 	if (val2) {
13664 	    *val2 = SQL_SEARCHABLE;
13665 	}
13666 	*valLen = sizeof (int);
13667 	return SQL_SUCCESS;
13668     case SQL_COLUMN_CASE_SENSITIVE:
13669 	if (val2) {
13670 	    *val2 = SQL_TRUE;
13671 	}
13672 	*valLen = sizeof (int);
13673 	return SQL_SUCCESS;
13674     case SQL_COLUMN_UPDATABLE:
13675 	if (val2) {
13676 	    *val2 = SQL_TRUE;
13677 	}
13678 	*valLen = sizeof (int);
13679 	return SQL_SUCCESS;
13680     case SQL_DESC_COUNT:
13681 	if (val2) {
13682 	    *val2 = s->ncols;
13683 	}
13684 	*valLen = sizeof (int);
13685 	return SQL_SUCCESS;
13686     case SQL_COLUMN_TYPE_NAME: {
13687 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
13688 
13689 #ifdef WINTERFACE
13690 	if (c->type == SQL_WCHAR ||
13691 	    c->type == SQL_WVARCHAR ||
13692 	    c->type == SQL_WLONGVARCHAR) {
13693 	    if (!(s->nowchar[0] || s->nowchar[1])) {
13694 		if (strcasecmp(tn, "varchar") == 0) {
13695 		    tn = "wvarchar";
13696 		}
13697 	    }
13698 	}
13699 #endif
13700 	if (valc && valMax > 0) {
13701 	    strncpy(valc, tn, valMax);
13702 	    valc[valMax - 1] = '\0';
13703 	    p = strchr(valc, '(');
13704 	    if (p) {
13705 		*p = '\0';
13706 		while (p > valc && ISSPACE(p[-1])) {
13707 		    --p;
13708 		    *p = '\0';
13709 		}
13710 	    }
13711 	    *valLen = strlen(valc);
13712 	} else {
13713 	    *valLen = strlen(tn);
13714 	    p = strchr(tn, '(');
13715 	    if (p) {
13716 		*valLen = p - tn;
13717 		while (p > tn && ISSPACE(p[-1])) {
13718 		    --p;
13719 		    *valLen -= 1;
13720 		}
13721 	    }
13722 	}
13723 	goto checkLen;
13724     }
13725     case SQL_COLUMN_OWNER_NAME:
13726     case SQL_COLUMN_QUALIFIER_NAME: {
13727 	char *z = "";
13728 
13729 	if (valc && valMax > 0) {
13730 	    strncpy(valc, z, valMax);
13731 	    valc[valMax - 1] = '\0';
13732 	}
13733 	*valLen = strlen(z);
13734 	goto checkLen;
13735     }
13736     case SQL_COLUMN_TABLE_NAME:
13737 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
13738     case SQL_DESC_TABLE_NAME:
13739 #endif
13740 #ifdef SQL_DESC_BASE_TABLE_NAME
13741     case SQL_DESC_BASE_TABLE_NAME:
13742 #endif
13743 	if (valc && valMax > 0) {
13744 	    strncpy(valc, c->table, valMax);
13745 	    valc[valMax - 1] = '\0';
13746 	}
13747 	*valLen = strlen(c->table);
13748 	goto checkLen;
13749 #ifdef SQL_DESC_NUM_PREC_RADIX
13750     case SQL_DESC_NUM_PREC_RADIX:
13751 	if (val2) {
13752 	    switch (c->type) {
13753 #ifdef WINTERFACE
13754 	    case SQL_WCHAR:
13755 	    case SQL_WVARCHAR:
13756 #ifdef SQL_LONGVARCHAR
13757 	    case SQL_WLONGVARCHAR:
13758 #endif
13759 #endif
13760 	    case SQL_CHAR:
13761 	    case SQL_VARCHAR:
13762 #ifdef SQL_LONGVARCHAR
13763 	    case SQL_LONGVARCHAR:
13764 #endif
13765 	    case SQL_BINARY:
13766 	    case SQL_VARBINARY:
13767 	    case SQL_LONGVARBINARY:
13768 		*val2 = 0;
13769 		break;
13770 	    default:
13771 		*val2 = 2;
13772 	    }
13773 	}
13774 	*valLen = sizeof (int);
13775 	return SQL_SUCCESS;
13776 #endif
13777     }
13778     setstat(s, -1, "unsupported column attributes %d", "HY091", id);
13779     return SQL_ERROR;
13780 }
13781 
13782 #ifndef WINTERFACE
13783 /**
13784  * Retrieve column attributes.
13785  * @param stmt statement handle
13786  * @param col column number, starting at 1
13787  * @param id attribute id
13788  * @param val output buffer
13789  * @param valMax length of output buffer
13790  * @param valLen output length
13791  * @param val2 integer output buffer
13792  * @result ODBC error code
13793  */
13794 
13795 SQLRETURN SQL_API
SQLColAttributes(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)13796 SQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
13797 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
13798 		 SQLLEN *val2)
13799 {
13800     SQLRETURN ret;
13801 
13802     HSTMT_LOCK(stmt);
13803     ret = drvcolattributes(stmt, col, id, val, valMax, valLen, val2);
13804     HSTMT_UNLOCK(stmt);
13805     return ret;
13806 }
13807 #endif
13808 
13809 #ifdef WINTERFACE
13810 /**
13811  * Retrieve column attributes (UNICODE version).
13812  * @param stmt statement handle
13813  * @param col column number, starting at 1
13814  * @param id attribute id
13815  * @param val output buffer
13816  * @param valMax length of output buffer
13817  * @param valLen output length
13818  * @param val2 integer output buffer
13819  * @result ODBC error code
13820  */
13821 
13822 SQLRETURN SQL_API
SQLColAttributesW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLLEN * val2)13823 SQLColAttributesW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
13824 		  SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
13825 		  SQLLEN *val2)
13826 {
13827     SQLRETURN ret;
13828     SQLSMALLINT len = 0;
13829 
13830     HSTMT_LOCK(stmt);
13831     ret = drvcolattributes(stmt, col, id, val, valMax, &len, val2);
13832     if (SQL_SUCCEEDED(ret)) {
13833 	SQLWCHAR *v = NULL;
13834 
13835 	switch (id) {
13836 	case SQL_COLUMN_LABEL:
13837 	case SQL_COLUMN_NAME:
13838 	case SQL_DESC_NAME:
13839 	case SQL_COLUMN_TYPE_NAME:
13840 	case SQL_COLUMN_OWNER_NAME:
13841 	case SQL_COLUMN_QUALIFIER_NAME:
13842 	case SQL_COLUMN_TABLE_NAME:
13843 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
13844 	case SQL_DESC_TABLE_NAME:
13845 #endif
13846 #ifdef SQL_DESC_BASE_COLUMN_NAME
13847 	case SQL_DESC_BASE_COLUMN_NAME:
13848 #endif
13849 #ifdef SQL_DESC_BASE_TABLE_NAME
13850     case SQL_DESC_BASE_TABLE_NAME:
13851 #endif
13852 	    if (val && valMax > 0) {
13853 		int vmax = valMax / sizeof (SQLWCHAR);
13854 
13855 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
13856 		if (v) {
13857 		    uc_strncpy(val, v, vmax);
13858 		    len = min(vmax, uc_strlen(v));
13859 		    uc_free(v);
13860 		    len *= sizeof (SQLWCHAR);
13861 		}
13862 		if (vmax > 0) {
13863 		    v = (SQLWCHAR *) val;
13864 		    v[vmax - 1] = '\0';
13865 		}
13866 	    }
13867 	    if (len <= 0) {
13868 		len = 0;
13869 	    }
13870 	    break;
13871 	}
13872 	if (valLen) {
13873 	    *valLen = len;
13874 	}
13875     }
13876     HSTMT_UNLOCK(stmt);
13877     return ret;
13878 }
13879 #endif
13880 
13881 /**
13882  * Internal retrieve column attributes.
13883  * @param stmt statement handle
13884  * @param col column number, starting at 1
13885  * @param id attribute id
13886  * @param val output buffer
13887  * @param valMax length of output buffer
13888  * @param valLen output length
13889  * @param val2 integer output buffer
13890  * @result ODBC error code
13891  */
13892 
13893 static SQLRETURN
drvcolattribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,SQLPOINTER val2)13894 drvcolattribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
13895 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
13896 		SQLPOINTER val2)
13897 {
13898     STMT *s;
13899     COL *c;
13900     int v = 0;
13901     char *valc = (char *) val;
13902     SQLSMALLINT dummy;
13903 
13904     if (stmt == SQL_NULL_HSTMT) {
13905 	return SQL_INVALID_HANDLE;
13906     }
13907     s = (STMT *) stmt;
13908     if (!s->cols) {
13909 	return SQL_ERROR;
13910     }
13911     if (col < 1 || col > s->ncols) {
13912 	setstat(s, -1, "invalid column", (*s->ov3) ? "07009" : "S1002");
13913 	return SQL_ERROR;
13914     }
13915     if (!valLen) {
13916 	valLen = &dummy;
13917     }
13918     c = s->cols + col - 1;
13919     switch (id) {
13920     case SQL_DESC_COUNT:
13921 	v = s->ncols;
13922 	break;
13923     case SQL_DESC_CATALOG_NAME:
13924 	if (valc && valMax > 0) {
13925 	    strncpy(valc, c->db, valMax);
13926 	    valc[valMax - 1] = '\0';
13927 	}
13928 	*valLen = strlen(c->db);
13929 checkLen:
13930 	if (*valLen >= valMax) {
13931 	    setstat(s, -1, "data right truncated", "01004");
13932 	    return SQL_SUCCESS_WITH_INFO;
13933 	}
13934 	break;
13935     case SQL_COLUMN_LENGTH:
13936     case SQL_DESC_LENGTH:
13937 	v = c->size;
13938 	break;
13939     case SQL_COLUMN_LABEL:
13940 	if (c->label) {
13941 	    if (valc && valMax > 0) {
13942 		strncpy(valc, c->label, valMax);
13943 		valc[valMax - 1] = '\0';
13944 	    }
13945 	    *valLen = strlen(c->label);
13946 	    goto checkLen;
13947 	}
13948 	/* fall through */
13949     case SQL_COLUMN_NAME:
13950     case SQL_DESC_NAME:
13951 	if (valc && valMax > 0) {
13952 	    strncpy(valc, c->column, valMax);
13953 	    valc[valMax - 1] = '\0';
13954 	}
13955 	*valLen = strlen(c->column);
13956 	goto checkLen;
13957     case SQL_DESC_SCHEMA_NAME: {
13958 	char *z = "";
13959 
13960 	if (valc && valMax > 0) {
13961 	    strncpy(valc, z, valMax);
13962 	    valc[valMax - 1] = '\0';
13963 	}
13964 	*valLen = strlen(z);
13965 	goto checkLen;
13966     }
13967 #ifdef SQL_DESC_BASE_COLUMN_NAME
13968     case SQL_DESC_BASE_COLUMN_NAME:
13969 	if (strchr(c->column, '(') || strchr(c->column, ')')) {
13970 	    valc[0] = '\0';
13971 	    *valLen = 0;
13972 	} else if (valc && valMax > 0) {
13973 	    strncpy(valc, c->column, valMax);
13974 	    valc[valMax - 1] = '\0';
13975 	    *valLen = strlen(c->column);
13976 	}
13977 	goto checkLen;
13978 #endif
13979     case SQL_DESC_TYPE_NAME: {
13980 	char *p = NULL, *tn = c->typename ? c->typename : "varchar";
13981 
13982 #ifdef WINTERFACE
13983 	if (c->type == SQL_WCHAR ||
13984 	    c->type == SQL_WVARCHAR ||
13985 	    c->type == SQL_WLONGVARCHAR) {
13986 	    if (!(s->nowchar[0] || s->nowchar[1])) {
13987 		if (strcasecmp(tn, "varchar") == 0) {
13988 		    tn = "wvarchar";
13989 		}
13990 	    }
13991 	}
13992 #endif
13993 	if (valc && valMax > 0) {
13994 	    strncpy(valc, tn, valMax);
13995 	    valc[valMax - 1] = '\0';
13996 	    p = strchr(valc, '(');
13997 	    if (p) {
13998 		*p = '\0';
13999 		while (p > valc && ISSPACE(p[-1])) {
14000 		    --p;
14001 		    *p = '\0';
14002 		}
14003 	    }
14004 	    *valLen = strlen(valc);
14005 	} else {
14006 	    *valLen = strlen(tn);
14007 	    p = strchr(tn, '(');
14008 	    if (p) {
14009 		*valLen = p - tn;
14010 		while (p > tn && ISSPACE(p[-1])) {
14011 		    --p;
14012 		    *valLen -= 1;
14013 		}
14014 	    }
14015 	}
14016 	goto checkLen;
14017     }
14018     case SQL_DESC_OCTET_LENGTH:
14019 	v = c->size;
14020 #ifdef WINTERFACE
14021 	if (c->type == SQL_WCHAR ||
14022 	    c->type == SQL_WVARCHAR ||
14023 	    c->type == SQL_WLONGVARCHAR) {
14024 	    if (!(s->nowchar[0] || s->nowchar[1])) {
14025 		v *= sizeof (SQLWCHAR);
14026 	    }
14027 	}
14028 #endif
14029 	break;
14030 #if (SQL_COLUMN_TABLE_NAME != SQL_DESC_TABLE_NAME)
14031     case SQL_COLUMN_TABLE_NAME:
14032 #endif
14033     case SQL_DESC_TABLE_NAME:
14034 #ifdef SQL_DESC_BASE_TABLE_NAME
14035     case SQL_DESC_BASE_TABLE_NAME:
14036 #endif
14037 	if (valc && valMax > 0) {
14038 	    strncpy(valc, c->table, valMax);
14039 	    valc[valMax - 1] = '\0';
14040 	}
14041 	*valLen = strlen(c->table);
14042 	goto checkLen;
14043     case SQL_DESC_TYPE:
14044 	v = c->type;
14045 #ifdef WINTERFACE
14046 	if (s->nowchar[0] || s->nowchar[1]) {
14047 	    switch (v) {
14048 	    case SQL_WCHAR:
14049 		v = SQL_CHAR;
14050 		break;
14051 	    case SQL_WVARCHAR:
14052 		v = SQL_VARCHAR;
14053 		break;
14054 #ifdef SQL_LONGVARCHAR
14055 	    case SQL_WLONGVARCHAR:
14056 		v = SQL_LONGVARCHAR;
14057 		break;
14058 #endif
14059 	    }
14060 	}
14061 #endif
14062 	break;
14063     case SQL_DESC_CONCISE_TYPE:
14064 	switch (c->type) {
14065 	case SQL_INTEGER:
14066 	    v = SQL_C_LONG;
14067 	    break;
14068 	case SQL_TINYINT:
14069 	    v = SQL_C_TINYINT;
14070 	    break;
14071 	case SQL_SMALLINT:
14072 	    v = SQL_C_SHORT;
14073 	    break;
14074 	case SQL_FLOAT:
14075 	    v = SQL_C_FLOAT;
14076 	    break;
14077 	case SQL_DOUBLE:
14078 	    v = SQL_C_DOUBLE;
14079 	    break;
14080 	case SQL_TIMESTAMP:
14081 	    v = SQL_C_TIMESTAMP;
14082 	    break;
14083 	case SQL_TIME:
14084 	    v = SQL_C_TIME;
14085 	    break;
14086 	case SQL_DATE:
14087 	    v = SQL_C_DATE;
14088 	    break;
14089 #ifdef SQL_C_TYPE_TIMESTAMP
14090 	case SQL_TYPE_TIMESTAMP:
14091 	    v = SQL_C_TYPE_TIMESTAMP;
14092 	    break;
14093 #endif
14094 #ifdef SQL_C_TYPE_TIME
14095 	case SQL_TYPE_TIME:
14096 	    v = SQL_C_TYPE_TIME;
14097 	    break;
14098 #endif
14099 #ifdef SQL_C_TYPE_DATE
14100 	case SQL_TYPE_DATE:
14101 	    v = SQL_C_TYPE_DATE;
14102 	    break;
14103 #endif
14104 #ifdef SQL_BIT
14105 	case SQL_BIT:
14106 	    v = SQL_C_BIT;
14107 	    break;
14108 #endif
14109 	default:
14110 #ifdef WINTERFACE
14111 	    v = (s->nowchar[0] || s->nowchar[1]) ? SQL_C_CHAR : SQL_C_WCHAR;
14112 #else
14113 	    v = SQL_C_CHAR;
14114 #endif
14115 	    break;
14116 	}
14117 	break;
14118     case SQL_DESC_UPDATABLE:
14119 	v = SQL_TRUE;
14120 	break;
14121     case SQL_COLUMN_DISPLAY_SIZE:
14122 	v = c->size;
14123 	break;
14124     case SQL_COLUMN_UNSIGNED:
14125 	v = c->nosign ? SQL_TRUE : SQL_FALSE;
14126 	break;
14127     case SQL_COLUMN_SEARCHABLE:
14128 	v = SQL_SEARCHABLE;
14129 	break;
14130     case SQL_COLUMN_SCALE:
14131     case SQL_DESC_SCALE:
14132 	v = c->scale;
14133 	break;
14134     case SQL_COLUMN_PRECISION:
14135     case SQL_DESC_PRECISION:
14136 	switch (c->type) {
14137 	case SQL_SMALLINT:
14138 	    v = 5;
14139 	    break;
14140 	case SQL_INTEGER:
14141 	    v = 10;
14142 	    break;
14143 	case SQL_FLOAT:
14144 	case SQL_REAL:
14145 	case SQL_DOUBLE:
14146 	    v = 15;
14147 	    break;
14148 	case SQL_DATE:
14149 	    v = 0;
14150 	    break;
14151 	case SQL_TIME:
14152 	    v = 0;
14153 	    break;
14154 #ifdef SQL_TYPE_TIMESTAMP
14155 	case SQL_TYPE_TIMESTAMP:
14156 #endif
14157 	case SQL_TIMESTAMP:
14158 	    v = (c->prec >= 0 && c->prec <= 3) ? c->prec : 3;
14159 	    break;
14160 	default:
14161 	    v = c->prec;
14162 	    break;
14163 	}
14164 	break;
14165     case SQL_COLUMN_MONEY:
14166 	v = SQL_FALSE;
14167 	break;
14168     case SQL_COLUMN_AUTO_INCREMENT:
14169 	v = c->autoinc;
14170 	break;
14171     case SQL_DESC_NULLABLE:
14172 	v = c->notnull;
14173 	break;
14174 #ifdef SQL_DESC_NUM_PREC_RADIX
14175     case SQL_DESC_NUM_PREC_RADIX:
14176 	switch (c->type) {
14177 #ifdef WINTERFACE
14178 	case SQL_WCHAR:
14179 	case SQL_WVARCHAR:
14180 #ifdef SQL_LONGVARCHAR
14181 	case SQL_WLONGVARCHAR:
14182 #endif
14183 #endif
14184 	case SQL_CHAR:
14185 	case SQL_VARCHAR:
14186 #ifdef SQL_LONGVARCHAR
14187 	case SQL_LONGVARCHAR:
14188 #endif
14189 	case SQL_BINARY:
14190 	case SQL_VARBINARY:
14191 	case SQL_LONGVARBINARY:
14192 	    v = 0;
14193 	    break;
14194 	default:
14195 	    v = 2;
14196 	}
14197 	break;
14198 #endif
14199     default:
14200 	setstat(s, -1, "unsupported column attribute %d", "HY091", id);
14201 	return SQL_ERROR;
14202     }
14203     if (val2) {
14204 	*(SQLLEN *) val2 = v;
14205     }
14206     return SQL_SUCCESS;
14207 }
14208 
14209 #ifndef WINTERFACE
14210 /**
14211  * Retrieve column attributes.
14212  * @param stmt statement handle
14213  * @param col column number, starting at 1
14214  * @param id attribute id
14215  * @param val output buffer
14216  * @param valMax length of output buffer
14217  * @param valLen output length
14218  * @param val2 integer output buffer
14219  * @result ODBC error code
14220  */
14221 
14222 SQLRETURN SQL_API
SQLColAttribute(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)14223 SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
14224 		SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
14225 		COLATTRIBUTE_LAST_ARG_TYPE val2)
14226 {
14227     SQLRETURN ret;
14228 
14229     HSTMT_LOCK(stmt);
14230     ret = drvcolattribute(stmt, col, id, val, valMax, valLen,
14231 			  (SQLPOINTER) val2);
14232     HSTMT_UNLOCK(stmt);
14233     return ret;
14234 }
14235 #endif
14236 
14237 #ifdef WINTERFACE
14238 /**
14239  * Retrieve column attributes (UNICODE version).
14240  * @param stmt statement handle
14241  * @param col column number, starting at 1
14242  * @param id attribute id
14243  * @param val output buffer
14244  * @param valMax length of output buffer
14245  * @param valLen output length
14246  * @param val2 integer output buffer
14247  * @result ODBC error code
14248  */
14249 
14250 SQLRETURN SQL_API
SQLColAttributeW(SQLHSTMT stmt,SQLUSMALLINT col,SQLUSMALLINT id,SQLPOINTER val,SQLSMALLINT valMax,SQLSMALLINT * valLen,COLATTRIBUTE_LAST_ARG_TYPE val2)14251 SQLColAttributeW(SQLHSTMT stmt, SQLUSMALLINT col, SQLUSMALLINT id,
14252 		 SQLPOINTER val, SQLSMALLINT valMax, SQLSMALLINT *valLen,
14253 		 COLATTRIBUTE_LAST_ARG_TYPE val2)
14254 {
14255     SQLRETURN ret;
14256     SQLSMALLINT len = 0;
14257 
14258     HSTMT_LOCK(stmt);
14259     ret = drvcolattribute(stmt, col, id, val, valMax, &len,
14260 			  (SQLPOINTER) val2);
14261     if (SQL_SUCCEEDED(ret)) {
14262 	SQLWCHAR *v = NULL;
14263 
14264 	switch (id) {
14265 	case SQL_DESC_SCHEMA_NAME:
14266 	case SQL_DESC_CATALOG_NAME:
14267 	case SQL_COLUMN_LABEL:
14268 	case SQL_DESC_NAME:
14269 	case SQL_DESC_TABLE_NAME:
14270 #ifdef SQL_DESC_BASE_TABLE_NAME
14271 	case SQL_DESC_BASE_TABLE_NAME:
14272 #endif
14273 #ifdef SQL_DESC_BASE_COLUMN_NAME
14274 	case SQL_DESC_BASE_COLUMN_NAME:
14275 #endif
14276 	case SQL_DESC_TYPE_NAME:
14277 	    if (val && valMax > 0) {
14278 		int vmax = valMax / sizeof (SQLWCHAR);
14279 
14280 		v = uc_from_utf((SQLCHAR *) val, SQL_NTS);
14281 		if (v) {
14282 		    uc_strncpy(val, v, vmax);
14283 		    len = min(vmax, uc_strlen(v));
14284 		    uc_free(v);
14285 		    len *= sizeof (SQLWCHAR);
14286 		}
14287 		if (vmax > 0) {
14288 		    v = (SQLWCHAR *) val;
14289 		    v[vmax - 1] = '\0';
14290 		}
14291 	    }
14292 	    if (len <= 0) {
14293 		len = 0;
14294 	    }
14295 	    break;
14296 	}
14297 	if (valLen) {
14298 	    *valLen = len;
14299 	}
14300     }
14301     HSTMT_UNLOCK(stmt);
14302     return ret;
14303 }
14304 #endif
14305 
14306 /**
14307  * Internal return last HDBC or HSTMT error message.
14308  * @param env environment handle or NULL
14309  * @param dbc database connection handle or NULL
14310  * @param stmt statement handle or NULL
14311  * @param sqlState output buffer for SQL state
14312  * @param nativeErr output buffer for native error code
14313  * @param errmsg output buffer for error message
14314  * @param errmax length of output buffer for error message
14315  * @param errlen output length of error message
14316  * @result ODBC error code
14317  */
14318 
14319 static SQLRETURN
drverror(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)14320 drverror(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
14321 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
14322 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
14323 {
14324     SQLCHAR dummy0[6];
14325     SQLINTEGER dummy1;
14326     SQLSMALLINT dummy2;
14327 
14328     if (env == SQL_NULL_HENV &&
14329 	dbc == SQL_NULL_HDBC &&
14330 	stmt == SQL_NULL_HSTMT) {
14331 	return SQL_INVALID_HANDLE;
14332     }
14333     if (sqlState) {
14334 	sqlState[0] = '\0';
14335     } else {
14336 	sqlState = dummy0;
14337     }
14338     if (!nativeErr) {
14339 	nativeErr = &dummy1;
14340     }
14341     *nativeErr = 0;
14342     if (!errlen) {
14343 	errlen = &dummy2;
14344     }
14345     *errlen = 0;
14346     if (errmsg) {
14347 	if (errmax > 0) {
14348 	    errmsg[0] = '\0';
14349 	}
14350     } else {
14351 	errmsg = dummy0;
14352 	errmax = 0;
14353     }
14354     if (stmt) {
14355 	STMT *s = (STMT *) stmt;
14356 
14357 	HSTMT_LOCK(stmt);
14358 	if (s->logmsg[0] == '\0') {
14359 	    HSTMT_UNLOCK(stmt);
14360 	    goto noerr;
14361 	}
14362 	*nativeErr = s->naterr;
14363 	strcpy((char *) sqlState, s->sqlstate);
14364 	if (errmax == SQL_NTS) {
14365 	    strcpy((char *) errmsg, "[SQLite]");
14366 	    strcat((char *) errmsg, (char *) s->logmsg);
14367 	    *errlen = strlen((char *) errmsg);
14368 	} else {
14369 	    strncpy((char *) errmsg, "[SQLite]", errmax);
14370 	    if (errmax - 8 > 0) {
14371 		strncpy((char *) errmsg + 8, (char *) s->logmsg, errmax - 8);
14372 	    }
14373 	    *errlen = min(strlen((char *) s->logmsg) + 8, errmax);
14374 	}
14375 	s->logmsg[0] = '\0';
14376 	HSTMT_UNLOCK(stmt);
14377 	return SQL_SUCCESS;
14378     }
14379     if (dbc) {
14380 	DBC *d = (DBC *) dbc;
14381 
14382 	HDBC_LOCK(dbc);
14383 	if (d->magic != DBC_MAGIC || d->logmsg[0] == '\0') {
14384 	    HDBC_UNLOCK(dbc);
14385 	    goto noerr;
14386 	}
14387 	*nativeErr = d->naterr;
14388 	strcpy((char *) sqlState, d->sqlstate);
14389 	if (errmax == SQL_NTS) {
14390 	    strcpy((char *) errmsg, "[SQLite]");
14391 	    strcat((char *) errmsg, (char *) d->logmsg);
14392 	    *errlen = strlen((char *) errmsg);
14393 	} else {
14394 	    strncpy((char *) errmsg, "[SQLite]", errmax);
14395 	    if (errmax - 8 > 0) {
14396 		strncpy((char *) errmsg + 8, (char *) d->logmsg, errmax - 8);
14397 	    }
14398 	    *errlen = min(strlen((char *) d->logmsg) + 8, errmax);
14399 	}
14400 	d->logmsg[0] = '\0';
14401 	HDBC_UNLOCK(dbc);
14402 	return SQL_SUCCESS;
14403     }
14404 noerr:
14405     sqlState[0] = '\0';
14406     errmsg[0] = '\0';
14407     *nativeErr = 0;
14408     *errlen = 0;
14409     return SQL_NO_DATA;
14410 }
14411 
14412 #ifndef WINTERFACE
14413 /**
14414  * Return last HDBC or HSTMT error message.
14415  * @param env environment handle or NULL
14416  * @param dbc database connection handle or NULL
14417  * @param stmt statement handle or NULL
14418  * @param sqlState output buffer for SQL state
14419  * @param nativeErr output buffer for native error code
14420  * @param errmsg output buffer for error message
14421  * @param errmax length of output buffer for error message
14422  * @param errlen output length of error message
14423  * @result ODBC error code
14424  */
14425 
14426 SQLRETURN SQL_API
SQLError(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLCHAR * sqlState,SQLINTEGER * nativeErr,SQLCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)14427 SQLError(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
14428 	 SQLCHAR *sqlState, SQLINTEGER *nativeErr,
14429 	 SQLCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
14430 {
14431     return drverror(env, dbc, stmt, sqlState, nativeErr,
14432 		    errmsg, errmax, errlen);
14433 }
14434 #endif
14435 
14436 #ifdef WINTERFACE
14437 /**
14438  * Return last HDBC or HSTMT error message (UNICODE version).
14439  * @param env environment handle or NULL
14440  * @param dbc database connection handle or NULL
14441  * @param stmt statement handle or NULL
14442  * @param sqlState output buffer for SQL state
14443  * @param nativeErr output buffer for native error code
14444  * @param errmsg output buffer for error message
14445  * @param errmax length of output buffer for error message
14446  * @param errlen output length of error message
14447  * @result ODBC error code
14448  */
14449 
14450 SQLRETURN SQL_API
SQLErrorW(SQLHENV env,SQLHDBC dbc,SQLHSTMT stmt,SQLWCHAR * sqlState,SQLINTEGER * nativeErr,SQLWCHAR * errmsg,SQLSMALLINT errmax,SQLSMALLINT * errlen)14451 SQLErrorW(SQLHENV env, SQLHDBC dbc, SQLHSTMT stmt,
14452 	  SQLWCHAR *sqlState, SQLINTEGER *nativeErr,
14453 	  SQLWCHAR *errmsg, SQLSMALLINT errmax, SQLSMALLINT *errlen)
14454 {
14455     char state[16];
14456     SQLSMALLINT len = 0;
14457     SQLRETURN ret;
14458 
14459     ret = drverror(env, dbc, stmt, (SQLCHAR *) state, nativeErr,
14460 		   (SQLCHAR *) errmsg, errmax, &len);
14461     if (ret == SQL_SUCCESS) {
14462 	if (sqlState) {
14463 	    uc_from_utf_buf((SQLCHAR *) state, -1, sqlState,
14464 			    6 * sizeof (SQLWCHAR));
14465 	}
14466 	if (errmsg) {
14467 	    if (len > 0) {
14468 		SQLWCHAR *e = NULL;
14469 
14470 		e = uc_from_utf((SQLCHAR *) errmsg, len);
14471 		if (e) {
14472 		    if (errmax > 0) {
14473 			uc_strncpy(errmsg, e, errmax);
14474 			e[len] = 0;
14475 			len = min(errmax, uc_strlen(e));
14476 		    } else {
14477 			len = uc_strlen(e);
14478 		    }
14479 		    uc_free(e);
14480 		} else {
14481 		    len = 0;
14482 		}
14483 	    }
14484 	    if (len <= 0) {
14485 		len = 0;
14486 		if (errmax > 0) {
14487 		    errmsg[0] = 0;
14488 		}
14489 	    }
14490 	} else {
14491 	    len = 0;
14492 	}
14493 	if (errlen) {
14494 	    *errlen = len;
14495 	}
14496     } else if (ret == SQL_NO_DATA) {
14497 	if (sqlState) {
14498 	    sqlState[0] = 0;
14499 	}
14500 	if (errmsg) {
14501 	    if (errmax > 0) {
14502 		errmsg[0] = 0;
14503 	    }
14504 	}
14505 	if (errlen) {
14506 	    *errlen = 0;
14507 	}
14508     }
14509     return ret;
14510 }
14511 #endif
14512 
14513 /**
14514  * Return information for more result sets.
14515  * @param stmt statement handle
14516  * @result ODBC error code
14517  */
14518 
14519 SQLRETURN SQL_API
SQLMoreResults(SQLHSTMT stmt)14520 SQLMoreResults(SQLHSTMT stmt)
14521 {
14522     HSTMT_LOCK(stmt);
14523     if (stmt == SQL_NULL_HSTMT) {
14524 	return SQL_INVALID_HANDLE;
14525     }
14526     HSTMT_UNLOCK(stmt);
14527     return SQL_NO_DATA;
14528 }
14529 
14530 /**
14531  * SQLite callback during drvprepare(), used to collect column information.
14532  * @param arg user data, actually a statement pointer
14533  * @param ncols number of columns
14534  * @param values value string array
14535  * @param cols column name string array
14536  * @result always 1 to abort sqlite_exec()
14537  */
14538 
14539 static int
selcb(void * arg,int ncols,char ** values,char ** cols)14540 selcb(void *arg, int ncols, char **values, char **cols)
14541 {
14542     STMT *s = (STMT *) arg;
14543 
14544     if (ncols > 0) {
14545 	int i, size;
14546 	char *p;
14547 	COL *dyncols;
14548 	DBC *d = (DBC *) s->dbc;
14549 
14550 	for (i = size = 0; i < ncols; i++) {
14551 	    size += 3 + 3 * strlen(cols[i]);
14552 	}
14553 	dyncols = xmalloc(ncols * sizeof (COL) + size);
14554 	if (!dyncols) {
14555 	    freedyncols(s);
14556 	    s->ncols = 0;
14557 	    return 1;
14558 	}
14559 	p = (char *) (dyncols + ncols);
14560 	for (i = 0; i < ncols; i++) {
14561 	    char *q;
14562 
14563 	    dyncols[i].db = ((DBC *) (s->dbc))->dbname;
14564 	    strcpy(p, cols[i]);
14565 	    dyncols[i].label = p;
14566 	    p += strlen(p) + 1;
14567 	    q = strchr(cols[i], '.');
14568 	    if (q) {
14569 		dyncols[i].table = p;
14570 		strncpy(p, cols[i], q - cols[i]);
14571 		p[q - cols[i]] = '\0';
14572 		p += strlen(p) + 1;
14573 		strcpy(p, q + 1);
14574 		dyncols[i].column = p;
14575 		p += strlen(p) + 1;
14576 	    } else {
14577 		dyncols[i].table = "";
14578 		strcpy(p, cols[i]);
14579 		dyncols[i].column = p;
14580 		p += strlen(p) + 1;
14581 	    }
14582 	    if (s->longnames) {
14583 		dyncols[i].column = dyncols[i].label;
14584 	    }
14585 #ifdef SQL_LONGVARCHAR
14586 	    dyncols[i].type = SQL_LONGVARCHAR;
14587 	    dyncols[i].size = 65535;
14588 #else
14589 	    dyncols[i].type = SQL_VARCHAR;
14590 	    dyncols[i].size = 255;
14591 #endif
14592 	    dyncols[i].index = i;
14593 	    dyncols[i].scale = 0;
14594 	    dyncols[i].prec = 0;
14595 	    dyncols[i].nosign = 1;
14596 	    dyncols[i].autoinc = SQL_FALSE;
14597 	    dyncols[i].notnull = SQL_NULLABLE;
14598 	    dyncols[i].typename = NULL;
14599 	}
14600 	freedyncols(s);
14601 	s->dyncols = s->cols = dyncols;
14602 	s->dcols = ncols;
14603 	fixupdyncols(s, d->sqlite, (const char **) cols + ncols);
14604     }
14605     s->ncols = ncols;
14606     return 1;
14607 }
14608 
14609 /**
14610  * Internal query preparation used by SQLPrepare() and SQLExecDirect().
14611  * @param stmt statement handle
14612  * @param query query string
14613  * @param queryLen length of query string or SQL_NTS
14614  * @result ODBC error code
14615  */
14616 
14617 static SQLRETURN
drvprepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)14618 drvprepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
14619 {
14620     STMT *s;
14621     DBC *d;
14622     char *errp = NULL;
14623     SQLRETURN sret;
14624 
14625     if (stmt == SQL_NULL_HSTMT) {
14626 	return SQL_INVALID_HANDLE;
14627     }
14628     s = (STMT *) stmt;
14629     if (s->dbc == SQL_NULL_HDBC) {
14630 noconn:
14631 	return noconn(s);
14632     }
14633     d = s->dbc;
14634     if (!d->sqlite) {
14635 	goto noconn;
14636     }
14637     vm_end(s);
14638     sret = starttran(s);
14639     if (sret != SQL_SUCCESS) {
14640 	return sret;
14641     }
14642     freep(&s->query);
14643     s->query = (SQLCHAR *) fixupsql((char *) query, queryLen, &s->nparams,
14644 				    &s->isselect, &errp,
14645 				    d->version, &s->parmnames);
14646     if (!s->query) {
14647 	if (errp) {
14648 	    setstat(s, -1, "%s", (*s->ov3) ? "HY000" : "S1000", errp);
14649 	    return SQL_ERROR;
14650 	}
14651 	return nomem(s);
14652     }
14653 #ifdef CANT_PASS_VALIST_AS_CHARPTR
14654     if (s->nparams > MAX_PARAMS_FOR_VPRINTF) {
14655 	freep(&s->query);
14656 	setstat(s, -1, "too much parameters in query",
14657 		(*s->ov3) ? "HY000" : "S1000");
14658 	return SQL_ERROR;
14659     }
14660 #endif
14661     errp = NULL;
14662     freeresult(s, -1);
14663     if (s->isselect == 1) {
14664 	int ret;
14665 	char **params = NULL;
14666 
14667 	if (s->nparams) {
14668 	    int i, maxp;
14669 
14670 #ifdef CANT_PASS_VALIST_AS_CHARPTR
14671 	    maxp = MAX_PARAMS_FOR_VPRINTF;
14672 #else
14673 	    maxp = s->nparams;
14674 #endif
14675 	    params = xmalloc(maxp * sizeof (char *));
14676 	    if (!params) {
14677 		return nomem(s);
14678 	    }
14679 	    for (i = 0; i < maxp; i++) {
14680 		params[i] = NULL;
14681 	    }
14682 	}
14683 #ifdef CANT_PASS_VALIST_AS_CHARPTR
14684 	if (params) {
14685 	    ret = sqlite_exec_printf(d->sqlite, (char *) s->query, selcb, s,
14686 				     &errp,
14687 				     params[0], params[1],
14688 				     params[2], params[3],
14689 				     params[4], params[5],
14690 				     params[6], params[7],
14691 				     params[8], params[9],
14692 				     params[10], params[11],
14693 				     params[12], params[13],
14694 				     params[14], params[15],
14695 				     params[16], params[17],
14696 				     params[18], params[19],
14697 				     params[20], params[21],
14698 				     params[22], params[23],
14699 				     params[24], params[25],
14700 				     params[26], params[27],
14701 				     params[28], params[29],
14702 				     params[30], params[31]);
14703 	} else {
14704 	    ret = sqlite_exec_printf(d->sqlite, (char *) s->query, selcb,
14705 				     s, &errp);
14706 	}
14707 #else
14708 	ret = sqlite_exec_vprintf(d->sqlite, (char *) s->query, selcb, s,
14709 				  &errp, (char *) params);
14710 #endif
14711 	if (ret != SQLITE_ABORT && ret != SQLITE_OK) {
14712 	    dbtracerc(d, ret, errp);
14713 	    freep(&params);
14714 	    setstat(s, ret, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
14715 		    errp ? errp : "unknown error", ret);
14716 	    if (errp) {
14717 		sqlite_freemem(errp);
14718 		errp = NULL;
14719 	    }
14720 	    return SQL_ERROR;
14721 	}
14722 	freep(&params);
14723 	if (errp) {
14724 	    sqlite_freemem(errp);
14725 	    errp = NULL;
14726 	}
14727     }
14728     mkbindcols(s, s->ncols);
14729     s->paramset_count = 0;
14730     return SQL_SUCCESS;
14731 }
14732 
14733 /**
14734  * Internal query execution used by SQLExecute() and SQLExecDirect().
14735  * @param stmt statement handle
14736  * @param initial false when called from SQLPutData()
14737  * @result ODBC error code
14738  */
14739 
14740 static SQLRETURN
drvexecute(SQLHSTMT stmt,int initial)14741 drvexecute(SQLHSTMT stmt, int initial)
14742 {
14743     STMT *s;
14744     DBC *d;
14745     char *errp = NULL, **params = NULL;
14746     int rc, i, ncols;
14747     SQLRETURN ret;
14748 
14749     if (stmt == SQL_NULL_HSTMT) {
14750 	return SQL_INVALID_HANDLE;
14751     }
14752     s = (STMT *) stmt;
14753     if (s->dbc == SQL_NULL_HDBC) {
14754 noconn:
14755 	return noconn(s);
14756     }
14757     d = (DBC *) s->dbc;
14758     if (!d->sqlite) {
14759 	goto noconn;
14760     }
14761     if (!s->query) {
14762 	setstat(s, -1, "no query prepared", (*s->ov3) ? "HY000" : "S1000");
14763 	return SQL_ERROR;
14764     }
14765     if (s->nbindparms < s->nparams) {
14766 unbound:
14767 	setstat(s, -1, "unbound parameters in query",
14768 		(*s->ov3) ? "HY000" : "S1000");
14769 	return SQL_ERROR;
14770     }
14771     for (i = 0; i < s->nparams; i++) {
14772 	BINDPARM *p = &s->bindparms[i];
14773 
14774 	if (!p->bound) {
14775 	    goto unbound;
14776 	}
14777 	if (initial) {
14778 	    SQLLEN *lenp = p->lenp;
14779 
14780 	    if (lenp && *lenp < 0 && *lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
14781 		*lenp != SQL_NTS && *lenp != SQL_NULL_DATA &&
14782 		*lenp != SQL_DATA_AT_EXEC) {
14783 		setstat(s, -1, "invalid length reference", "HY009");
14784 		return SQL_ERROR;
14785 	    }
14786 	    if (lenp && (*lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
14787 			 *lenp == SQL_DATA_AT_EXEC)) {
14788 		p->need = 1;
14789 		p->offs = 0;
14790 		p->len = 0;
14791 	    }
14792 	}
14793     }
14794     ret = starttran(s);
14795     if (ret != SQL_SUCCESS) {
14796 	goto cleanup;
14797     }
14798 again:
14799     vm_end(s);
14800     if (initial) {
14801 	/* fixup data-at-execution parameters and alloc'ed blobs */
14802 	s->pdcount = -1;
14803 	for (i = 0; i < s->nparams; i++) {
14804 	    BINDPARM *p = &s->bindparms[i];
14805 
14806 	    if (p->param == p->parbuf) {
14807 		p->param = NULL;
14808 	    }
14809 	    freep(&p->parbuf);
14810 	    if (p->need <= 0 &&
14811 		p->lenp && (*p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
14812 			    *p->lenp == SQL_DATA_AT_EXEC)) {
14813 		p->need = 1;
14814 		p->offs = 0;
14815 		p->len = 0;
14816 	    }
14817 	}
14818     }
14819     if (s->nparams) {
14820 	int maxp;
14821 
14822 #ifdef CANT_PASS_VALIST_AS_CHARPTR
14823 	maxp = MAX_PARAMS_FOR_VPRINTF;
14824 #else
14825 	maxp = s->nparams;
14826 #endif
14827 	params = xmalloc(maxp * sizeof (char *));
14828 	if (!params) {
14829 	    ret = nomem(s);
14830 	    goto cleanup;
14831 	}
14832 	for (i = 0; i < maxp; i++) {
14833 	    params[i] = NULL;
14834 	}
14835 	for (i = 0; i < s->nparams; i++) {
14836 	    ret = substparam(s, i, &params[i]);
14837 	    if (ret != SQL_SUCCESS) {
14838 		freep(&params);
14839 		goto cleanup;
14840 	    }
14841 	}
14842     }
14843     freeresult(s, 0);
14844     if (s->isselect == 1 && !d->intrans &&
14845 	s->curtype == SQL_CURSOR_FORWARD_ONLY &&
14846 	d->step_enable && s->nparams == 0 && d->vm_stmt == NULL) {
14847 	s->nrows = -1;
14848 	ret = vm_start(s, params);
14849 	if (ret == SQL_SUCCESS) {
14850 	    freep(&params);
14851 	    goto done2;
14852 	}
14853     }
14854 #ifdef CANT_PASS_VALIST_AS_CHARPTR
14855     if (params) {
14856 	rc = sqlite_get_table_printf(d->sqlite, (char *) s->query, &s->rows,
14857 				     &s->nrows, &ncols, &errp,
14858 				     params[0], params[1],
14859 				     params[2], params[3],
14860 				     params[4], params[5],
14861 				     params[6], params[7],
14862 				     params[8], params[9],
14863 				     params[10], params[11],
14864 				     params[12], params[13],
14865 				     params[14], params[15],
14866 				     params[16], params[17],
14867 				     params[18], params[19],
14868 				     params[20], params[21],
14869 				     params[22], params[23],
14870 				     params[24], params[25],
14871 				     params[26], params[27],
14872 				     params[28], params[29],
14873 				     params[30], params[31]);
14874     } else {
14875 	rc = sqlite_get_table_printf(d->sqlite, (char *) s->query, &s->rows,
14876 				     &s->nrows, &ncols, &errp);
14877     }
14878 #else
14879     rc = sqlite_get_table_vprintf(d->sqlite, (char *) s->query, &s->rows,
14880 				  &s->nrows, &ncols, &errp, (char *) params);
14881 #endif
14882     dbtracerc(d, rc, errp);
14883     if (rc != SQLITE_OK) {
14884 	freep(&params);
14885 	setstat(s, rc, "%s (%d)", (*s->ov3) ? "HY000" : "S1000",
14886 		errp ? errp : "unknown error", rc);
14887 	if (errp) {
14888 	    sqlite_freemem(errp);
14889 	    errp = NULL;
14890 	}
14891 	ret = SQL_ERROR;
14892 	goto cleanup;
14893     }
14894     freep(&params);
14895     if (errp) {
14896 	sqlite_freemem(errp);
14897 	errp = NULL;
14898     }
14899     s->rowfree = sqlite_free_table;
14900     if (ncols == 1 && (s->isselect <= 0 || s->isselect > 1)) {
14901 	/*
14902 	 * INSERT/UPDATE/DELETE or DDL results are immediately released.
14903 	 */
14904 	if (strcmp(s->rows[0], "rows inserted") == 0 ||
14905 	    strcmp(s->rows[0], "rows updated") == 0 ||
14906 	    strcmp(s->rows[0], "rows deleted") == 0) {
14907 	    int nrows = 0;
14908 
14909 	    nrows = strtol(s->rows[1], NULL, 0);
14910 	    freeresult(s, -1);
14911 	    s->nrows = nrows;
14912 	    goto done;
14913 	}
14914     }
14915     if (s->ncols != ncols) {
14916 	int size;
14917 	char *p;
14918 	COL *dyncols;
14919 
14920 	for (i = size = 0; i < ncols; i++) {
14921 	    size += 3 + 3 * strlen(s->rows[i]);
14922 	}
14923 	if (size == 0) {
14924 	    freeresult(s, -1);
14925 	    goto done;
14926 	}
14927 	dyncols = xmalloc(ncols * sizeof (COL) + size);
14928 	if (!dyncols) {
14929 	    ret = nomem(s);
14930 	    goto cleanup;
14931 	}
14932 	p = (char *) (dyncols + ncols);
14933 	for (i = 0; i < ncols; i++) {
14934 	    char *q;
14935 
14936 	    dyncols[i].db = d->dbname;
14937 	    strcpy(p, s->rows[i]);
14938 	    dyncols[i].label = p;
14939 	    p += strlen(p) + 1;
14940 	    q = strchr(s->rows[i], '.');
14941 	    if (q) {
14942 		dyncols[i].table = p;
14943 		strncpy(p, s->rows[i], q - s->rows[i]);
14944 		p[q - s->rows[i]] = '\0';
14945 		p += strlen(p) + 1;
14946 		dyncols[i].column = q + 1;
14947 	    } else {
14948 		dyncols[i].table = "";
14949 		dyncols[i].column = s->rows[i];
14950 	    }
14951 	    if (s->longnames) {
14952 		dyncols[i].column = dyncols[i].label;
14953 	    }
14954 #ifdef SQL_LONGVARCHAR
14955 	    dyncols[i].type = SQL_LONGVARCHAR;
14956 	    dyncols[i].size = 65536;
14957 #else
14958 	    dyncols[i].type = SQL_VARCHAR;
14959 	    dyncols[i].size = 255;
14960 #endif
14961 	    dyncols[i].index = i;
14962 	    dyncols[i].scale = 0;
14963 	    dyncols[i].prec = 0;
14964 	    dyncols[i].nosign = 1;
14965 	    dyncols[i].autoinc = SQL_FALSE;
14966 	    dyncols[i].notnull = SQL_NULLABLE;
14967 	    dyncols[i].typename = NULL;
14968 	}
14969 	freedyncols(s);
14970 	s->ncols = s->dcols = ncols;
14971 	s->dyncols = s->cols = dyncols;
14972 	fixupdyncols(s, d->sqlite, NULL);
14973     }
14974 done:
14975     mkbindcols(s, s->ncols);
14976 done2:
14977     ret = SQL_SUCCESS;
14978     s->rowp = -1;
14979     s->paramset_count++;
14980     s->paramset_nrows += s->nrows;
14981     if (s->paramset_count < s->paramset_size) {
14982 	for (i = 0; i < s->nparams; i++) {
14983 	    BINDPARM *p = &s->bindparms[i];
14984 
14985 	    if (p->param == p->parbuf) {
14986 		p->param = NULL;
14987 	    }
14988 	    freep(&p->parbuf);
14989 	    if (p->lenp0 &&
14990 		s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
14991 		p->lenp = (SQLLEN *) ((char *) p->lenp0 +
14992 				      s->paramset_count * s->parm_bind_type);
14993 	    } else if (p->lenp0 && p->inc > 0) {
14994 		p->lenp = p->lenp0 + s->paramset_count;
14995 	    }
14996 	    if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
14997 			     *p->lenp != SQL_DATA_AT_EXEC)) {
14998 		if (p->param0 &&
14999 		    s->parm_bind_type != SQL_PARAM_BIND_BY_COLUMN) {
15000 		    p->param = (char *) p->param0 +
15001 			s->paramset_count * s->parm_bind_type;
15002 		} else if (p->param0 && p->inc > 0) {
15003 		    p->param = (char *) p->param0 +
15004 			s->paramset_count * p->inc;
15005 		}
15006 	    } else if (p->lenp && (*p->lenp <= SQL_LEN_DATA_AT_EXEC_OFFSET ||
15007 				   *p->lenp == SQL_DATA_AT_EXEC)) {
15008 		p->need = 1;
15009 		p->offs = 0;
15010 		p->len = 0;
15011 	    }
15012 	}
15013 	goto again;
15014     }
15015 cleanup:
15016     if (ret != SQL_NEED_DATA) {
15017 	for (i = 0; i < s->nparams; i++) {
15018 	    BINDPARM *p = &s->bindparms[i];
15019 
15020 	    if (p->param == p->parbuf) {
15021 		p->param = NULL;
15022 	    }
15023 	    freep(&p->parbuf);
15024 	    if (!p->lenp || (*p->lenp > SQL_LEN_DATA_AT_EXEC_OFFSET &&
15025 			     *p->lenp != SQL_DATA_AT_EXEC)) {
15026 		p->param = p->param0;
15027 	    }
15028 	    p->lenp = p->lenp0;
15029 	}
15030 	s->nrows = s->paramset_nrows;
15031 	if (s->parm_proc) {
15032 	    *s->parm_proc = s->paramset_count;
15033 	}
15034 	s->paramset_count = 0;
15035 	s->paramset_nrows = 0;
15036     }
15037     return ret;
15038 }
15039 
15040 #ifndef WINTERFACE
15041 /**
15042  * Prepare HSTMT.
15043  * @param stmt statement handle
15044  * @param query query string
15045  * @param queryLen length of query string or SQL_NTS
15046  * @result ODBC error code
15047  */
15048 
15049 SQLRETURN SQL_API
SQLPrepare(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)15050 SQLPrepare(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
15051 {
15052     SQLRETURN ret;
15053 
15054     HSTMT_LOCK(stmt);
15055     ret = drvprepare(stmt, query, queryLen);
15056     HSTMT_UNLOCK(stmt);
15057     return ret;
15058 }
15059 #endif
15060 
15061 #ifdef WINTERFACE
15062 /**
15063  * Prepare HSTMT (UNICODE version).
15064  * @param stmt statement handle
15065  * @param query query string
15066  * @param queryLen length of query string or SQL_NTS
15067  * @result ODBC error code
15068  */
15069 
15070 SQLRETURN SQL_API
SQLPrepareW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)15071 SQLPrepareW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
15072 {
15073     SQLRETURN ret;
15074     char *q = uc_to_utf_c(query, queryLen);
15075 
15076     HSTMT_LOCK(stmt);
15077     if (!q) {
15078 	ret = nomem((STMT *) stmt);
15079 	goto done;
15080     }
15081     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
15082     uc_free(q);
15083 done:
15084     HSTMT_UNLOCK(stmt);
15085     return ret;
15086 }
15087 #endif
15088 
15089 /**
15090  * Execute query.
15091  * @param stmt statement handle
15092  * @result ODBC error code
15093  */
15094 
15095 SQLRETURN SQL_API
SQLExecute(SQLHSTMT stmt)15096 SQLExecute(SQLHSTMT stmt)
15097 {
15098     SQLRETURN ret;
15099 
15100     HSTMT_LOCK(stmt);
15101     ret = drvexecute(stmt, 1);
15102     HSTMT_UNLOCK(stmt);
15103     return ret;
15104 }
15105 
15106 #ifndef WINTERFACE
15107 /**
15108  * Execute query directly.
15109  * @param stmt statement handle
15110  * @param query query string
15111  * @param queryLen length of query string or SQL_NTS
15112  * @result ODBC error code
15113  */
15114 
15115 SQLRETURN SQL_API
SQLExecDirect(SQLHSTMT stmt,SQLCHAR * query,SQLINTEGER queryLen)15116 SQLExecDirect(SQLHSTMT stmt, SQLCHAR *query, SQLINTEGER queryLen)
15117 {
15118     SQLRETURN ret;
15119 
15120     HSTMT_LOCK(stmt);
15121     ret = drvprepare(stmt, query, queryLen);
15122     if (ret == SQL_SUCCESS) {
15123 	ret = drvexecute(stmt, 1);
15124     }
15125     HSTMT_UNLOCK(stmt);
15126     return ret;
15127 }
15128 #endif
15129 
15130 #ifdef WINTERFACE
15131 /**
15132  * Execute query directly (UNICODE version).
15133  * @param stmt statement handle
15134  * @param query query string
15135  * @param queryLen length of query string or SQL_NTS
15136  * @result ODBC error code
15137  */
15138 
15139 SQLRETURN SQL_API
SQLExecDirectW(SQLHSTMT stmt,SQLWCHAR * query,SQLINTEGER queryLen)15140 SQLExecDirectW(SQLHSTMT stmt, SQLWCHAR *query, SQLINTEGER queryLen)
15141 {
15142     SQLRETURN ret;
15143     char *q = uc_to_utf_c(query, queryLen);
15144 
15145     HSTMT_LOCK(stmt);
15146     if (!q) {
15147 	ret = nomem((STMT *) stmt);
15148 	goto done;
15149     }
15150     ret = drvprepare(stmt, (SQLCHAR *) q, SQL_NTS);
15151     uc_free(q);
15152     if (ret == SQL_SUCCESS) {
15153 	ret = drvexecute(stmt, 1);
15154     }
15155 done:
15156     HSTMT_UNLOCK(stmt);
15157     return ret;
15158 }
15159 #endif
15160 
15161 #if defined(_WIN32) || defined(_WIN64) || defined(__OS2__)
15162 
15163 #ifndef WITHOUT_DRIVERMGR
15164 
15165 #if defined(_WIN32) || defined(_WIN64)
15166 /*
15167  * Windows configuration dialog stuff.
15168  */
15169 
15170 #include <windowsx.h>
15171 #include <winuser.h>
15172 
15173 #endif
15174 
15175 #ifdef __OS2__
15176 #define INCL_WIN
15177 #define INCL_PM
15178 #define INCL_DOSMODULEMGR
15179 #define INCL_DOSERRORS
15180 #define INCL_WINSTDFILE
15181 
15182 #include <os2.h>
15183 #include <stdlib.h>
15184 
15185 #include "resourceos2.h"
15186 
15187 #endif
15188 
15189 #define MAXPATHLEN      (259+1)           /* Max path length */
15190 #define MAXKEYLEN       (15+1)            /* Max keyword length */
15191 #define MAXDESC         (255+1)           /* Max description length */
15192 #define MAXDSNAME       (255+1)           /* Max data source name length */
15193 #define MAXTONAME       (32+1)            /* Max timeout length */
15194 #define MAXDBNAME       MAXPATHLEN
15195 
15196 /* Attribute key indexes into an array of Attr structs, see below */
15197 
15198 #define KEY_DSN 		0
15199 #define KEY_DESC		1
15200 #define KEY_DBNAME		2
15201 #define KEY_BUSY		3
15202 #define KEY_DRIVER		4
15203 #define KEY_NOWCHAR		5
15204 #define KEY_STEPAPI		6
15205 #define KEY_NOTXN		7
15206 #define KEY_LONGNAM		8
15207 #define NUMOFKEYS		9
15208 
15209 typedef struct {
15210     BOOL supplied;
15211     char attr[MAXPATHLEN];
15212 } ATTR;
15213 
15214 typedef struct {
15215     SQLHWND parent;
15216 #ifdef __OS2__
15217     HMODULE hDLL;
15218 #endif
15219     LPCSTR  driver;
15220     ATTR    attr[NUMOFKEYS];
15221     char    DSN[MAXDSNAME];
15222     BOOL    newDSN;
15223     BOOL    defDSN;
15224 } SETUPDLG;
15225 
15226 static struct {
15227     char *key;
15228     int ikey;
15229 } attrLookup[] = {
15230     { "DSN", KEY_DSN },
15231     { "DESC", KEY_DESC },
15232     { "Description", KEY_DESC},
15233     { "Database", KEY_DBNAME },
15234     { "Timeout", KEY_BUSY },
15235     { "Driver", KEY_DRIVER },
15236     { "NoWCHAR", KEY_NOWCHAR },
15237     { "StepAPI", KEY_STEPAPI },
15238     { "NoTXN", KEY_NOTXN },
15239     { "LongNames", KEY_LONGNAM },
15240     { NULL, 0 }
15241 };
15242 
15243 /**
15244  * Setup dialog data from datasource attributes.
15245  * @param attribs attribute string
15246  * @param setupdlg pointer to dialog data
15247  */
15248 
15249 static void
ParseAttributes(LPCSTR attribs,SETUPDLG * setupdlg)15250 ParseAttributes(LPCSTR attribs, SETUPDLG *setupdlg)
15251 {
15252     char *str = (char *) attribs, *start, key[MAXKEYLEN];
15253     int elem, nkey;
15254 
15255     while (*str) {
15256 	start = str;
15257 	if ((str = strchr(str, '=')) == NULL) {
15258 	    return;
15259 	}
15260 	elem = -1;
15261 	nkey = str - start;
15262 	if (nkey < sizeof (key)) {
15263 	    int i;
15264 
15265 	    memcpy(key, start, nkey);
15266 	    key[nkey] = '\0';
15267 	    for (i = 0; attrLookup[i].key; i++) {
15268 		if (strcasecmp(attrLookup[i].key, key) == 0) {
15269 		    elem = attrLookup[i].ikey;
15270 		    break;
15271 		}
15272 	    }
15273 	}
15274 	start = ++str;
15275 	while (*str && *str != ';') {
15276 	    ++str;
15277 	}
15278 	if (elem >= 0) {
15279 	    int end = min(str - start, sizeof (setupdlg->attr[elem].attr) - 1);
15280 
15281 	    setupdlg->attr[elem].supplied = TRUE;
15282 	    memcpy(setupdlg->attr[elem].attr, start, end);
15283 	    setupdlg->attr[elem].attr[end] = '\0';
15284 	}
15285 	++str;
15286     }
15287 }
15288 
15289 /**
15290  * Set datasource attributes in registry.
15291  * @param parent handle of parent window
15292  * @param setupdlg pointer to dialog data
15293  * @result true or false
15294  */
15295 
15296 static BOOL
SetDSNAttributes(HWND parent,SETUPDLG * setupdlg)15297 SetDSNAttributes(HWND parent, SETUPDLG *setupdlg)
15298 {
15299     char *dsn = setupdlg->attr[KEY_DSN].attr;
15300 
15301     if (setupdlg->newDSN && strlen(dsn) == 0) {
15302 	return FALSE;
15303     }
15304     if (!SQLWriteDSNToIni(dsn, setupdlg->driver)) {
15305 	if (parent) {
15306 #if defined(_WIN32) || defined(_WIN64)
15307 	    char buf[MAXPATHLEN], msg[MAXPATHLEN];
15308 
15309 	    LoadString(hModule, IDS_BADDSN, buf, sizeof (buf));
15310 	    wsprintf(msg, buf, dsn);
15311 	    LoadString(hModule, IDS_MSGTITLE, buf, sizeof (buf));
15312 	    MessageBox(parent, msg, buf,
15313 		       MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL |
15314 		       MB_SETFOREGROUND);
15315 #endif
15316 #ifdef __OS2__
15317 	    WinMessageBox(HWND_DESKTOP, parent, "Bad DSN", "Configure Error",
15318 			  0, MB_ERROR | MB_OK );
15319 #endif
15320 	}
15321 	return FALSE;
15322     }
15323     if (parent || setupdlg->attr[KEY_DESC].supplied) {
15324 	SQLWritePrivateProfileString(dsn, "Description",
15325 				     setupdlg->attr[KEY_DESC].attr,
15326 				     ODBC_INI);
15327     }
15328     if (parent || setupdlg->attr[KEY_DBNAME].supplied) {
15329 	SQLWritePrivateProfileString(dsn, "Database",
15330 				     setupdlg->attr[KEY_DBNAME].attr,
15331 				     ODBC_INI);
15332     }
15333     if (parent || setupdlg->attr[KEY_BUSY].supplied) {
15334 	SQLWritePrivateProfileString(dsn, "Timeout",
15335 				     setupdlg->attr[KEY_BUSY].attr,
15336 				     ODBC_INI);
15337     }
15338     if (parent || setupdlg->attr[KEY_NOWCHAR].supplied) {
15339 	SQLWritePrivateProfileString(dsn, "NoWCHAR",
15340 				     setupdlg->attr[KEY_NOWCHAR].attr,
15341 				     ODBC_INI);
15342     }
15343     if (parent || setupdlg->attr[KEY_STEPAPI].supplied) {
15344 	SQLWritePrivateProfileString(dsn, "StepAPI",
15345 				     setupdlg->attr[KEY_STEPAPI].attr,
15346 				     ODBC_INI);
15347     }
15348     if (parent || setupdlg->attr[KEY_NOTXN].supplied) {
15349 	SQLWritePrivateProfileString(dsn, "NoTXN",
15350 				     setupdlg->attr[KEY_NOTXN].attr,
15351 				     ODBC_INI);
15352     }
15353     if (parent || setupdlg->attr[KEY_LONGNAM].supplied) {
15354 	SQLWritePrivateProfileString(dsn, "LongNames",
15355 				     setupdlg->attr[KEY_LONGNAM].attr,
15356 				     ODBC_INI);
15357     }
15358     if (setupdlg->attr[KEY_DSN].supplied &&
15359 	strcasecmp(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr)) {
15360 	SQLRemoveDSNFromIni(setupdlg->DSN);
15361     }
15362     return TRUE;
15363 }
15364 
15365 /**
15366  * Get datasource attributes from registry.
15367  * @param setupdlg pointer to dialog data
15368  */
15369 
15370 static void
GetAttributes(SETUPDLG * setupdlg)15371 GetAttributes(SETUPDLG *setupdlg)
15372 {
15373     char *dsn = setupdlg->attr[KEY_DSN].attr;
15374 
15375     if (!setupdlg->attr[KEY_DESC].supplied) {
15376 	SQLGetPrivateProfileString(dsn, "Description", "",
15377 				   setupdlg->attr[KEY_DESC].attr,
15378 				   sizeof (setupdlg->attr[KEY_DESC].attr),
15379 				   ODBC_INI);
15380     }
15381     if (!setupdlg->attr[KEY_DBNAME].supplied) {
15382 	SQLGetPrivateProfileString(dsn, "Database", "",
15383 				   setupdlg->attr[KEY_DBNAME].attr,
15384 				   sizeof (setupdlg->attr[KEY_DBNAME].attr),
15385 				   ODBC_INI);
15386     }
15387     if (!setupdlg->attr[KEY_BUSY].supplied) {
15388 	SQLGetPrivateProfileString(dsn, "Timeout", "100000",
15389 				   setupdlg->attr[KEY_BUSY].attr,
15390 				   sizeof (setupdlg->attr[KEY_BUSY].attr),
15391 				   ODBC_INI);
15392     }
15393     if (!setupdlg->attr[KEY_NOWCHAR].supplied) {
15394 	SQLGetPrivateProfileString(dsn, "NoWCHAR", "",
15395 				   setupdlg->attr[KEY_NOWCHAR].attr,
15396 				   sizeof (setupdlg->attr[KEY_NOWCHAR].attr),
15397 				   ODBC_INI);
15398     }
15399     if (!setupdlg->attr[KEY_STEPAPI].supplied) {
15400 	SQLGetPrivateProfileString(dsn, "StepAPI", "0",
15401 				   setupdlg->attr[KEY_STEPAPI].attr,
15402 				   sizeof (setupdlg->attr[KEY_STEPAPI].attr),
15403 				   ODBC_INI);
15404     }
15405     if (!setupdlg->attr[KEY_NOTXN].supplied) {
15406 	SQLGetPrivateProfileString(dsn, "NoTXN", "",
15407 				   setupdlg->attr[KEY_NOTXN].attr,
15408 				   sizeof (setupdlg->attr[KEY_NOTXN].attr),
15409 				   ODBC_INI);
15410     }
15411     if (!setupdlg->attr[KEY_LONGNAM].supplied) {
15412 	SQLGetPrivateProfileString(dsn, "LongNames", "",
15413 				   setupdlg->attr[KEY_LONGNAM].attr,
15414 				   sizeof (setupdlg->attr[KEY_LONGNAM].attr),
15415 				   ODBC_INI);
15416     }
15417 }
15418 
15419 /**
15420  * Open file dialog for selection of SQLite database file.
15421  * @param hdlg handle of originating dialog window
15422  */
15423 
15424 static void
GetDBFile(HWND hdlg)15425 GetDBFile(HWND hdlg)
15426 {
15427 #if defined(_WIN32) || defined(_WIN64)
15428 #ifdef _WIN64
15429     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
15430 #else
15431     SETUPDLG *setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
15432 #endif
15433     OPENFILENAME ofn;
15434 
15435     memset(&ofn, 0, sizeof (ofn));
15436     ofn.lStructSize = sizeof (ofn);
15437     ofn.hwndOwner = hdlg;
15438 #ifdef _WIN64
15439     ofn.hInstance = (HINSTANCE) GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
15440 #else
15441     ofn.hInstance = (HINSTANCE) GetWindowLong(hdlg, GWL_HINSTANCE);
15442 #endif
15443     ofn.lpstrFile = (LPTSTR) setupdlg->attr[KEY_DBNAME].attr;
15444     ofn.nMaxFile = MAXPATHLEN;
15445     ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
15446 		OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_FILEMUSTEXIST;
15447     if (GetOpenFileName(&ofn)) {
15448 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
15449 	setupdlg->attr[KEY_DBNAME].supplied = TRUE;
15450     }
15451 #endif
15452 #ifdef __OS2__
15453     SETUPDLG *setupdlg = (SETUPDLG *) WinQueryWindowULong(hdlg, QWL_USER);
15454     FILEDLG ofn;
15455 
15456     memset(&ofn, 0, sizeof (ofn));
15457     ofn.cbSize = sizeof (FILEDLG);
15458     strcpy(ofn.szFullFile, setupdlg->attr[KEY_DBNAME].attr);
15459     ofn.fl = FDS_OPEN_DIALOG | FDS_CENTER;
15460     WinFileDlg(hdlg, hdlg, &ofn);
15461     if (ofn.lReturn == DID_OK) {
15462 	strcpy(setupdlg->attr[KEY_DBNAME].attr, ofn.szFullFile);
15463 	WinSetDlgItemText(hdlg, EF_DATABASE, setupdlg->attr[KEY_DBNAME].attr);
15464 	setupdlg->attr[KEY_DBNAME].supplied = TRUE;
15465     }
15466 #endif
15467 }
15468 
15469 #if defined(_WIN32) || defined(_WIN64)
15470 /**
15471  * Dialog procedure for ConfigDSN().
15472  * @param hdlg handle of dialog window
15473  * @param wmsg type of message
15474  * @param wparam wparam of message
15475  * @param lparam lparam of message
15476  * @result true or false
15477  */
15478 
15479 static BOOL CALLBACK
ConfigDlgProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)15480 ConfigDlgProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
15481 {
15482     SETUPDLG *setupdlg = NULL;
15483 
15484     switch (wmsg) {
15485     case WM_INITDIALOG:
15486 #ifdef _WIN64
15487 	SetWindowLongPtr(hdlg, DWLP_USER, lparam);
15488 #else
15489 	SetWindowLong(hdlg, DWL_USER, lparam);
15490 #endif
15491 	setupdlg = (SETUPDLG *) lparam;
15492 	GetAttributes(setupdlg);
15493 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
15494 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
15495 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
15496 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
15497 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
15498 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
15499 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
15500 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
15501 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
15502 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
15503 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
15504 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
15505 	CheckDlgButton(hdlg, IDC_NOWCHAR,
15506 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
15507 		       BST_CHECKED : BST_UNCHECKED);
15508 	CheckDlgButton(hdlg, IDC_STEPAPI,
15509 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
15510 		       BST_CHECKED : BST_UNCHECKED);
15511 	CheckDlgButton(hdlg, IDC_NOTXN,
15512 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
15513 		       BST_CHECKED : BST_UNCHECKED);
15514 	CheckDlgButton(hdlg, IDC_LONGNAM,
15515 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
15516 		       BST_CHECKED : BST_UNCHECKED);
15517 	if (setupdlg->defDSN) {
15518 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
15519 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
15520 	}
15521 	return TRUE;
15522     case WM_COMMAND:
15523 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
15524 	case IDC_DSNAME:
15525 	    if (GET_WM_COMMAND_CMD(wparam, lparam) == EN_CHANGE) {
15526 		char item[MAXDSNAME];
15527 
15528 		EnableWindow(GetDlgItem(hdlg, IDOK),
15529 			     GetDlgItemText(hdlg, IDC_DSNAME,
15530 					    item, sizeof (item)));
15531 		return TRUE;
15532 	    }
15533 	    break;
15534 	case IDC_BROWSE:
15535 	    GetDBFile(hdlg);
15536 	    break;
15537 	case IDOK:
15538 #ifdef _WIN64
15539 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
15540 #else
15541 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
15542 #endif
15543 	    if (!setupdlg->defDSN) {
15544 		GetDlgItemText(hdlg, IDC_DSNAME,
15545 			       setupdlg->attr[KEY_DSN].attr,
15546 			       sizeof (setupdlg->attr[KEY_DSN].attr));
15547 	    }
15548 	    GetDlgItemText(hdlg, IDC_DESC,
15549 			   setupdlg->attr[KEY_DESC].attr,
15550 			   sizeof (setupdlg->attr[KEY_DESC].attr));
15551 	    GetDlgItemText(hdlg, IDC_DBNAME,
15552 			   setupdlg->attr[KEY_DBNAME].attr,
15553 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
15554 	    GetDlgItemText(hdlg, IDC_TONAME,
15555 			   setupdlg->attr[KEY_BUSY].attr,
15556 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
15557 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
15558 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
15559 		   "1" : "0");
15560 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
15561 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
15562 		   "1" : "0");
15563 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
15564 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
15565 		   "1" : "0");
15566 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
15567 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
15568 		   "1" : "0");
15569 	    SetDSNAttributes(hdlg, setupdlg);
15570 	    /* FALL THROUGH */
15571 	case IDCANCEL:
15572 	    EndDialog(hdlg, wparam);
15573 	    return TRUE;
15574 	}
15575 	break;
15576     }
15577     return FALSE;
15578 }
15579 #endif
15580 
15581 #ifdef __OS2__
15582 /**
15583  * Dialog procedure for ConfigDSN().
15584  * @param hdlg handle of dialog window
15585  * @param wmsg type of message
15586  * @param wparam wparam of message
15587  * @param lparam lparam of message
15588  * @result standard MRESULT
15589  */
15590 
15591 static MRESULT EXPENTRY
ConfigDlgProc(HWND hdlg,ULONG wmsg,MPARAM wparam,MPARAM lparam)15592 ConfigDlgProc(HWND hdlg, ULONG wmsg, MPARAM wparam, MPARAM lparam)
15593 {
15594     SETUPDLG *setupdlg = NULL;
15595 
15596     switch (wmsg) {
15597     case WM_INITDLG:
15598 	WinSetWindowULong(hdlg, QWL_USER, (ULONG) lparam);
15599 	setupdlg = (SETUPDLG *) lparam;
15600 	GetAttributes(setupdlg);
15601 	WinSetDlgItemText(hdlg, EF_DSNNAME, setupdlg->attr[KEY_DSN].attr);
15602 	WinSetDlgItemText(hdlg, EF_DSNDESC, setupdlg->attr[KEY_DESC].attr);
15603 	WinSetDlgItemText(hdlg, EF_DATABASE, setupdlg->attr[KEY_DBNAME].attr);
15604 	WinSetDlgItemText(hdlg, EF_TIMEOUT, setupdlg->attr[KEY_BUSY].attr);
15605 	WinSendDlgItemMsg(hdlg, EF_DSNNAME, EM_SETTEXTLIMIT,
15606 			  MPFROMSHORT(MAXDSNAME - 1), 0L);
15607 	WinSendDlgItemMsg(hdlg, EF_DSNDESC, EM_SETTEXTLIMIT,
15608 			  MPFROMSHORT(MAXDESC - 1), 0L);
15609 	WinSendDlgItemMsg(hdlg, EF_DATABASE, EM_SETTEXTLIMIT,
15610 			  MPFROMSHORT(MAXDBNAME - 1), 0L);
15611 	WinSendDlgItemMsg(hdlg, EF_TIMEOUT, EM_SETTEXTLIMIT,
15612 			  MPFROMSHORT(MAXTONAME - 1), 0L);
15613 	WinCheckButton(hdlg, IDC_NOWCHAR,
15614 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr));
15615 	WinCheckButton(hdlg, IDC_STEPAPI,
15616 		       getbool(setupdlg->attr[KEY_STEPAPI].attr));
15617 	WinCheckButton(hdlg, IDC_NOTXN,
15618 		       getbool(setupdlg->attr[KEY_NOTXN].attr));
15619 	WinCheckButton(hdlg, IDC_LONGNAM,
15620 		       getbool(setupdlg->attr[KEY_LONGNAM].attr));
15621 	if (setupdlg->defDSN) {
15622 	    WinEnableWindow(WinWindowFromID(hdlg, EF_DSNNAME), FALSE);
15623 	}
15624 	return 0;
15625     case WM_COMMAND:
15626 	switch (SHORT1FROMMP(wparam)) {
15627 	case IDC_BROWSE:
15628 	    GetDBFile(hdlg);
15629 	    break;
15630 	case DID_OK:
15631 	    setupdlg = (SETUPDLG *) WinQueryWindowULong(hdlg, QWL_USER);
15632 	    if (!setupdlg->defDSN) {
15633 		WinQueryDlgItemText(hdlg, EF_DSNNAME,
15634 				    sizeof (setupdlg->attr[KEY_DSN].attr),
15635 				    setupdlg->attr[KEY_DSN].attr);
15636 	    }
15637 	    WinQueryDlgItemText(hdlg, EF_DSNDESC,
15638 				sizeof (setupdlg->attr[KEY_DESC].attr),
15639 				setupdlg->attr[KEY_DESC].attr);
15640 	    WinQueryDlgItemText(hdlg, EF_DATABASE,
15641 				sizeof (setupdlg->attr[KEY_DBNAME].attr),
15642 				setupdlg->attr[KEY_DBNAME].attr);
15643 	    WinQueryDlgItemText(hdlg, EF_TIMEOUT,
15644 				sizeof (setupdlg->attr[KEY_BUSY].attr),
15645 				setupdlg->attr[KEY_BUSY].attr);
15646 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_NOWCHAR, BM_QUERYCHECK,
15647 					 0, 0) == 1) {
15648 		strcpy(setupdlg->attr[KEY_NOWCHAR].attr, "1");
15649 	    } else {
15650 		strcpy(setupdlg->attr[KEY_NOWCHAR].attr, "0");
15651 	    }
15652 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_STEPAPI, BM_QUERYCHECK,
15653 					 0, 0) == 1) {
15654 		strcpy(setupdlg->attr[KEY_STEPAPI].attr, "1");
15655 	    } else {
15656 		strcpy(setupdlg->attr[KEY_STEPAPI].attr, "0");
15657 	    }
15658 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_NOTXN, BM_QUERYCHECK,
15659 					 0, 0) == 1) {
15660 		strcpy(setupdlg->attr[KEY_NOTXN].attr, "1");
15661 	    } else {
15662 		strcpy(setupdlg->attr[KEY_NOTXN].attr, "0");
15663 	    }
15664 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_LONGNAM, BM_QUERYCHECK,
15665 					 0, 0) == 1) {
15666 		strcpy(setupdlg->attr[KEY_LONGNAM].attr, "1");
15667 	    } else {
15668 		strcpy(setupdlg->attr[KEY_LONGNAM].attr, "0");
15669 	    }
15670 	    SetDSNAttributes(hdlg, setupdlg);
15671 	    WinDismissDlg(hdlg, DID_OK);
15672 	    return 0;
15673 	case DID_CANCEL:
15674 	    WinDismissDlg(hdlg, DID_OK);
15675 	    return 0;
15676 	}
15677 	break;
15678     }
15679     return WinDefDlgProc(hdlg, wmsg, wparam, lparam);
15680 }
15681 #endif
15682 
15683 /**
15684  * ODBC INSTAPI procedure for DSN configuration.
15685  * @param hwnd parent window handle
15686  * @param request type of request
15687  * @param driver driver name
15688  * @param attribs attribute string of DSN
15689  * @result true or false
15690  */
15691 
15692 BOOL INSTAPI
ConfigDSN(HWND hwnd,WORD request,LPCSTR driver,LPCSTR attribs)15693 ConfigDSN(HWND hwnd, WORD request, LPCSTR driver, LPCSTR attribs)
15694 {
15695     BOOL success;
15696     SETUPDLG *setupdlg;
15697 
15698     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
15699     if (setupdlg == NULL) {
15700 	return FALSE;
15701     }
15702     memset(setupdlg, 0, sizeof (SETUPDLG));
15703     if (attribs) {
15704 	ParseAttributes(attribs, setupdlg);
15705     }
15706     if (setupdlg->attr[KEY_DSN].supplied) {
15707 	strcpy(setupdlg->DSN, setupdlg->attr[KEY_DSN].attr);
15708     } else {
15709 	setupdlg->DSN[0] = '\0';
15710     }
15711     if (request == ODBC_REMOVE_DSN) {
15712 	if (!setupdlg->attr[KEY_DSN].supplied) {
15713 	    success = FALSE;
15714 	} else {
15715 	    success = SQLRemoveDSNFromIni(setupdlg->attr[KEY_DSN].attr);
15716 	}
15717     } else {
15718 #if defined(_WIN32) || defined(_WIN64)
15719 	setupdlg->parent = hwnd;
15720 #endif
15721 #ifdef __OS2__
15722 	setupdlg->parent = (SQLHWND) hwnd;
15723 #endif
15724 	setupdlg->driver = driver;
15725 	setupdlg->newDSN = request == ODBC_ADD_DSN;
15726 	setupdlg->defDSN = strcasecmp(setupdlg->attr[KEY_DSN].attr,
15727 				      "Default") == 0;
15728 	if (hwnd) {
15729 #if defined(_WIN32) || defined(_WIN64)
15730 	    success = DialogBoxParam(hModule, MAKEINTRESOURCE(CONFIGDSN),
15731 				     hwnd, (DLGPROC) ConfigDlgProc,
15732 				     (LPARAM) setupdlg) == IDOK;
15733 #endif
15734 #ifdef __OS2__
15735 	    HMODULE hDLL;
15736 
15737 	    DosQueryModuleHandle("SQLLODBC.DLL", &hDLL);
15738 	    setupdlg->hDLL = hDLL;
15739 	    success = WinDlgBox(HWND_DESKTOP, hwnd, ConfigDlgProc, hDLL,
15740 				DLG_SQLITEODBCCONFIGURATION, setupdlg);
15741 	    success = (success == DID_OK) ? TRUE : FALSE;
15742 #endif
15743 	} else if (setupdlg->attr[KEY_DSN].supplied) {
15744 	    success = SetDSNAttributes(hwnd, setupdlg);
15745 	} else {
15746 	    success = FALSE;
15747 	}
15748     }
15749     xfree(setupdlg);
15750     return success;
15751 }
15752 
15753 #if defined(_WIN32) || defined(_WIN64)
15754 /**
15755  * Dialog procedure for SQLDriverConnect().
15756  * @param hdlg handle of dialog window
15757  * @param wmsg type of message
15758  * @param wparam wparam of message
15759  * @param lparam lparam of message
15760  * @result true or false
15761  */
15762 
15763 static BOOL CALLBACK
DriverConnectProc(HWND hdlg,WORD wmsg,WPARAM wparam,LPARAM lparam)15764 DriverConnectProc(HWND hdlg, WORD wmsg, WPARAM wparam, LPARAM lparam)
15765 {
15766     SETUPDLG *setupdlg;
15767 
15768     switch (wmsg) {
15769     case WM_INITDIALOG:
15770 #ifdef _WIN64
15771 	SetWindowLongPtr(hdlg, DWLP_USER, lparam);
15772 #else
15773 	SetWindowLong(hdlg, DWL_USER, lparam);
15774 #endif
15775 	setupdlg = (SETUPDLG *) lparam;
15776 	SetDlgItemText(hdlg, IDC_DSNAME, setupdlg->attr[KEY_DSN].attr);
15777 	SetDlgItemText(hdlg, IDC_DESC, setupdlg->attr[KEY_DESC].attr);
15778 	SetDlgItemText(hdlg, IDC_DBNAME, setupdlg->attr[KEY_DBNAME].attr);
15779 	SetDlgItemText(hdlg, IDC_TONAME, setupdlg->attr[KEY_BUSY].attr);
15780 	SendDlgItemMessage(hdlg, IDC_DSNAME, EM_LIMITTEXT,
15781 			   (WPARAM) (MAXDSNAME - 1), (LPARAM) 0);
15782 	SendDlgItemMessage(hdlg, IDC_DESC, EM_LIMITTEXT,
15783 			   (WPARAM) (MAXDESC - 1), (LPARAM) 0);
15784 	SendDlgItemMessage(hdlg, IDC_DBNAME, EM_LIMITTEXT,
15785 			   (WPARAM) (MAXDBNAME - 1), (LPARAM) 0);
15786 	SendDlgItemMessage(hdlg, IDC_TONAME, EM_LIMITTEXT,
15787 			   (WPARAM) (MAXTONAME - 1), (LPARAM) 0);
15788 	CheckDlgButton(hdlg, IDC_NOWCHAR,
15789 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr) ?
15790 		       BST_CHECKED : BST_UNCHECKED);
15791 	CheckDlgButton(hdlg, IDC_STEPAPI,
15792 		       getbool(setupdlg->attr[KEY_STEPAPI].attr) ?
15793 		       BST_CHECKED : BST_UNCHECKED);
15794 	CheckDlgButton(hdlg, IDC_NOTXN,
15795 		       getbool(setupdlg->attr[KEY_NOTXN].attr) ?
15796 		       BST_CHECKED : BST_UNCHECKED);
15797 	CheckDlgButton(hdlg, IDC_LONGNAM,
15798 		       getbool(setupdlg->attr[KEY_LONGNAM].attr) ?
15799 		       BST_CHECKED : BST_UNCHECKED);
15800 	if (setupdlg->defDSN) {
15801 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAME), FALSE);
15802 	    EnableWindow(GetDlgItem(hdlg, IDC_DSNAMETEXT), FALSE);
15803 	}
15804 	return TRUE;
15805     case WM_COMMAND:
15806 	switch (GET_WM_COMMAND_ID(wparam, lparam)) {
15807 	case IDC_BROWSE:
15808 	    GetDBFile(hdlg);
15809 	    break;
15810 	case IDOK:
15811 #ifdef _WIN64
15812 	    setupdlg = (SETUPDLG *) GetWindowLongPtr(hdlg, DWLP_USER);
15813 #else
15814 	    setupdlg = (SETUPDLG *) GetWindowLong(hdlg, DWL_USER);
15815 #endif
15816 	    GetDlgItemText(hdlg, IDC_DSNAME,
15817 			   setupdlg->attr[KEY_DSN].attr,
15818 			   sizeof (setupdlg->attr[KEY_DSN].attr));
15819 	    GetDlgItemText(hdlg, IDC_DBNAME,
15820 			   setupdlg->attr[KEY_DBNAME].attr,
15821 			   sizeof (setupdlg->attr[KEY_DBNAME].attr));
15822 	    GetDlgItemText(hdlg, IDC_TONAME,
15823 			   setupdlg->attr[KEY_BUSY].attr,
15824 			   sizeof (setupdlg->attr[KEY_BUSY].attr));
15825 	    strcpy(setupdlg->attr[KEY_NOWCHAR].attr,
15826 		   (IsDlgButtonChecked(hdlg, IDC_NOWCHAR) == BST_CHECKED) ?
15827 		   "1" : "0");
15828 	    strcpy(setupdlg->attr[KEY_STEPAPI].attr,
15829 		   (IsDlgButtonChecked(hdlg, IDC_STEPAPI) == BST_CHECKED) ?
15830 		   "1" : "0");
15831 	    strcpy(setupdlg->attr[KEY_NOTXN].attr,
15832 		   (IsDlgButtonChecked(hdlg, IDC_NOTXN) == BST_CHECKED) ?
15833 		   "1" : "0");
15834 	    strcpy(setupdlg->attr[KEY_LONGNAM].attr,
15835 		   (IsDlgButtonChecked(hdlg, IDC_LONGNAM) == BST_CHECKED) ?
15836 		   "1" : "0");
15837 	    /* FALL THROUGH */
15838 	case IDCANCEL:
15839 	    EndDialog(hdlg, GET_WM_COMMAND_ID(wparam, lparam) == IDOK);
15840 	    return TRUE;
15841 	}
15842     }
15843     return FALSE;
15844 }
15845 #endif
15846 
15847 #ifdef __OS2__
15848 /**
15849  * Dialog procedure for SQLDriverConnect().
15850  * @param hdlg handle of dialog window
15851  * @param wmsg type of message
15852  * @param wparam wparam of message
15853  * @param lparam lparam of message
15854  * @result standard MRESULT
15855  */
15856 
15857 static MRESULT EXPENTRY
DriverConnectProc(HWND hdlg,ULONG wmsg,MPARAM wparam,MPARAM lparam)15858 DriverConnectProc(HWND hdlg, ULONG wmsg, MPARAM wparam, MPARAM lparam)
15859 {
15860     SETUPDLG *setupdlg;
15861 
15862     switch (wmsg) {
15863     case WM_INITDLG:
15864 	WinSetWindowULong(hdlg, QWL_USER, (ULONG) lparam);
15865 	setupdlg = (SETUPDLG *) lparam;
15866 	WinSetDlgItemText(hdlg, EF_DSNNAME, setupdlg->attr[KEY_DSN].attr);
15867 	WinSetDlgItemText(hdlg, EF_DSNDESC, setupdlg->attr[KEY_DESC].attr);
15868 	WinSetDlgItemText(hdlg, EF_DATABASE, setupdlg->attr[KEY_DBNAME].attr);
15869 	WinSetDlgItemText(hdlg, EF_TIMEOUT, setupdlg->attr[KEY_BUSY].attr);
15870 	WinCheckButton(hdlg, IDC_NOWCHAR,
15871 		       getbool(setupdlg->attr[KEY_NOWCHAR].attr));
15872 	WinCheckButton(hdlg, IDC_STEPAPI,
15873 		       getbool(setupdlg->attr[KEY_STEPAPI].attr));
15874 	WinCheckButton(hdlg, IDC_NOTXN,
15875 		       getbool(setupdlg->attr[KEY_NOTXN].attr));
15876 	WinCheckButton(hdlg, IDC_LONGNAM,
15877 		       getbool(setupdlg->attr[KEY_LONGNAM].attr));
15878 	return 0;
15879     case WM_COMMAND:
15880 	switch (SHORT1FROMMP(wparam)) {
15881 	case IDC_BROWSE:
15882 	    GetDBFile(hdlg);
15883 	    return 0;
15884 	case DID_OK:
15885 	    setupdlg = (SETUPDLG *) WinQueryWindowULong(hdlg, QWL_USER);
15886 	    WinQueryDlgItemText(hdlg, EF_DSNNAME,
15887 				sizeof (setupdlg->attr[KEY_DSN].attr),
15888 				setupdlg->attr[KEY_DSN].attr);
15889 	    WinQueryDlgItemText(hdlg, EF_DATABASE,
15890 				sizeof (setupdlg->attr[KEY_DBNAME].attr),
15891 				setupdlg->attr[KEY_DBNAME].attr);
15892 	    WinQueryDlgItemText(hdlg, EF_TIMEOUT,
15893 				sizeof (setupdlg->attr[KEY_BUSY].attr),
15894 				setupdlg->attr[KEY_BUSY].attr);
15895 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_NOWCHAR, BM_QUERYCHECK,
15896 					 0, 0) == 1) {
15897 		strcpy(setupdlg->attr[KEY_NOWCHAR].attr, "1");
15898 	    } else {
15899 		strcpy(setupdlg->attr[KEY_NOWCHAR].attr, "0");
15900 	    }
15901 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_STEPAPI, BM_QUERYCHECK,
15902 					 0, 0) == 1) {
15903 		strcpy(setupdlg->attr[KEY_STEPAPI].attr, "1");
15904 	    } else {
15905 		strcpy(setupdlg->attr[KEY_STEPAPI].attr, "0");
15906 	    }
15907 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_NOTXN, BM_QUERYCHECK,
15908 					 0, 0) == 1) {
15909 		strcpy(setupdlg->attr[KEY_NOTXN].attr, "1");
15910 	    } else {
15911 		strcpy(setupdlg->attr[KEY_NOTXN].attr, "0");
15912 	    }
15913 	    if ((ULONG)WinSendDlgItemMsg(hdlg, IDC_LONGNAM, BM_QUERYCHECK,
15914 					 0, 0) == 1) {
15915 		strcpy(setupdlg->attr[KEY_LONGNAM].attr, "1");
15916 	    } else {
15917 		strcpy(setupdlg->attr[KEY_LONGNAM].attr, "0");
15918 	    }
15919 	    WinDismissDlg(hdlg, DID_OK);
15920 	    return 0;
15921 	case DID_CANCEL:
15922 	    WinDismissDlg(hdlg, DID_CANCEL);
15923 	    return 0;
15924 	}
15925     }
15926     return WinDefDlgProc(hdlg, wmsg, wparam, lparam);
15927 }
15928 #endif
15929 
15930 /**
15931  * Internal connect using a driver connection string.
15932  * @param dbc database connection handle
15933  * @param hwnd parent window handle
15934  * @param connIn driver connect input string
15935  * @param connInLen length of driver connect input string or SQL_NTS
15936  * @param connOut driver connect output string
15937  * @param connOutMax length of driver connect output string
15938  * @param connOutLen output length of driver connect output string
15939  * @param drvcompl completion type
15940  * @result ODBC error code
15941  */
15942 
15943 static SQLRETURN
drvdriverconnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)15944 drvdriverconnect(SQLHDBC dbc, SQLHWND hwnd,
15945 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
15946 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
15947 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
15948 {
15949     BOOL maybeprompt, prompt = FALSE, defaultdsn = FALSE;
15950     DBC *d;
15951     SETUPDLG *setupdlg;
15952     SQLRETURN ret;
15953 
15954     if (dbc == SQL_NULL_HDBC) {
15955 	return SQL_INVALID_HANDLE;
15956     }
15957     d = (DBC *) dbc;
15958     if (d->sqlite) {
15959 	setstatd(d, -1, "connection already established", "08002");
15960 	return SQL_ERROR;
15961     }
15962     setupdlg = (SETUPDLG *) xmalloc(sizeof (SETUPDLG));
15963     if (setupdlg == NULL) {
15964 	return SQL_ERROR;
15965     }
15966     memset(setupdlg, 0, sizeof (SETUPDLG));
15967     maybeprompt = drvcompl == SQL_DRIVER_COMPLETE ||
15968 	drvcompl == SQL_DRIVER_COMPLETE_REQUIRED;
15969     if (connIn == NULL || !connInLen ||
15970 	(connInLen == SQL_NTS && !connIn[0])) {
15971 	prompt = TRUE;
15972     } else {
15973 	ParseAttributes((LPCSTR) connIn, setupdlg);
15974 	if (!setupdlg->attr[KEY_DSN].attr[0] &&
15975 	    drvcompl == SQL_DRIVER_COMPLETE_REQUIRED) {
15976 	    strcpy(setupdlg->attr[KEY_DSN].attr, "DEFAULT");
15977 	    defaultdsn = TRUE;
15978 	}
15979 	GetAttributes(setupdlg);
15980 	if (drvcompl == SQL_DRIVER_PROMPT ||
15981 	    (maybeprompt &&
15982 	     !setupdlg->attr[KEY_DBNAME].attr[0])) {
15983 	    prompt = TRUE;
15984 	}
15985     }
15986 retry:
15987     if (prompt) {
15988 	short dlgret;
15989 
15990 	setupdlg->defDSN = setupdlg->attr[KEY_DRIVER].attr[0] != '\0';
15991 #if defined(_WIN32) || defined(_WIN64)
15992 	dlgret = DialogBoxParam(hModule, MAKEINTRESOURCE(DRIVERCONNECT),
15993 				hwnd, (DLGPROC) DriverConnectProc,
15994 				(LPARAM) setupdlg);
15995 #endif
15996 #ifdef __OS2__
15997 	HMODULE hDLL;
15998 
15999 	DosQueryModuleHandle("SQLLODBC.DLL", &hDLL);
16000 	setupdlg->hDLL = hDLL;
16001 	dlgret = WinDlgBox(HWND_DESKTOP, (HWND) hwnd, DriverConnectProc, hDLL,
16002 			   DLG_SQLITEODBCCONFIGURATION, setupdlg);
16003 #endif
16004 	if (!dlgret || dlgret == -1) {
16005 	    xfree(setupdlg);
16006 	    return SQL_NO_DATA;
16007 	}
16008     }
16009     if (connOut || connOutLen) {
16010 	char buf[SQL_MAX_MESSAGE_LENGTH * 8];
16011 	int len, count;
16012 	char dsn_0 = (setupdlg->attr[KEY_DSN].attr[0] && !defaultdsn) ?
16013 	    setupdlg->attr[KEY_DSN].attr[0] : '\0';
16014 	char drv_0 = setupdlg->attr[KEY_DRIVER].attr[0];
16015 
16016 	buf[0] = '\0';
16017 	count = snprintf(buf, sizeof (buf),
16018 			 "%s%s%s%s%s%sDatabase=%s;StepAPI=%s;"
16019 			 "NoTXN=%s;Timeout=%s;NoWCHAR=%s;LongNames=%s",
16020 			 dsn_0 ? "DSN=" : "",
16021 			 dsn_0 ? setupdlg->attr[KEY_DSN].attr : "",
16022 			 dsn_0 ? ";" : "",
16023 			 drv_0 ? "Driver=" : "",
16024 			 drv_0 ? setupdlg->attr[KEY_DRIVER].attr : "",
16025 			 drv_0 ? ";" : "",
16026 			 setupdlg->attr[KEY_DBNAME].attr,
16027 			 setupdlg->attr[KEY_STEPAPI].attr,
16028 			 setupdlg->attr[KEY_NOTXN].attr,
16029 			 setupdlg->attr[KEY_BUSY].attr,
16030 			 setupdlg->attr[KEY_NOWCHAR].attr,
16031 			 setupdlg->attr[KEY_LONGNAM].attr);
16032 	if (count < 0) {
16033 	    buf[sizeof (buf) - 1] = '\0';
16034 	}
16035 	len = min(connOutMax - 1, strlen(buf));
16036 	if (connOut) {
16037 	    strncpy((char *) connOut, buf, len);
16038 	    connOut[len] = '\0';
16039 	}
16040 	if (connOutLen) {
16041 	    *connOutLen = len;
16042 	}
16043     }
16044 #if defined(HAVE_SQLITETRACE) && (HAVE_SQLITETRACE)
16045     if (setupdlg->attr[KEY_DSN].attr[0]) {
16046 	char tracef[SQL_MAX_MESSAGE_LENGTH];
16047 
16048 	tracef[0] = '\0';
16049 	SQLGetPrivateProfileString(setupdlg->attr[KEY_DSN].attr,
16050 				   "tracefile", "", tracef,
16051 				   sizeof (tracef), ODBC_INI);
16052 	if (tracef[0] != '\0') {
16053 	    d->trace = fopen(tracef, "a");
16054 	}
16055     }
16056 #endif
16057     d->nowchar = getbool(setupdlg->attr[KEY_NOWCHAR].attr);
16058     d->longnames = getbool(setupdlg->attr[KEY_LONGNAM].attr);
16059     ret = dbopen(d, setupdlg->attr[KEY_DBNAME].attr,
16060 		 setupdlg->attr[KEY_DSN].attr,
16061 		 setupdlg->attr[KEY_STEPAPI].attr,
16062 		 setupdlg->attr[KEY_NOTXN].attr,
16063 		 setupdlg->attr[KEY_BUSY].attr);
16064     if (ret != SQL_SUCCESS) {
16065 	if (maybeprompt && !prompt) {
16066 	    prompt = TRUE;
16067 	    goto retry;
16068 	}
16069 	xfree(setupdlg);
16070 	return ret;
16071     }
16072     xfree(setupdlg);
16073     return SQL_SUCCESS;
16074 }
16075 
16076 #endif /* WITHOUT_DRIVERMGR */
16077 #endif /* _WIN32 || _WIN64 || __OS2__ */
16078 
16079 #ifndef WINTERFACE
16080 /**
16081  * Connect using a driver connection string.
16082  * @param dbc database connection handle
16083  * @param hwnd parent window handle
16084  * @param connIn driver connect input string
16085  * @param connInLen length of driver connect input string or SQL_NTS
16086  * @param connOut driver connect output string
16087  * @param connOutMax length of driver connect output string
16088  * @param connOutLen output length of driver connect output string
16089  * @param drvcompl completion type
16090  * @result ODBC error code
16091  */
16092 
16093 SQLRETURN SQL_API
SQLDriverConnect(SQLHDBC dbc,SQLHWND hwnd,SQLCHAR * connIn,SQLSMALLINT connInLen,SQLCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)16094 SQLDriverConnect(SQLHDBC dbc, SQLHWND hwnd,
16095 		 SQLCHAR *connIn, SQLSMALLINT connInLen,
16096 		 SQLCHAR *connOut, SQLSMALLINT connOutMax,
16097 		 SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
16098 {
16099     SQLRETURN ret;
16100 
16101     HDBC_LOCK(dbc);
16102     ret = drvdriverconnect(dbc, hwnd, connIn, connInLen,
16103 			   connOut, connOutMax, connOutLen, drvcompl);
16104     HDBC_UNLOCK(dbc);
16105     return ret;
16106 }
16107 #endif
16108 
16109 #ifdef WINTERFACE
16110 /**
16111  * Connect using a driver connection string (UNICODE version).
16112  * @param dbc database connection handle
16113  * @param hwnd parent window handle
16114  * @param connIn driver connect input string
16115  * @param connInLen length of driver connect input string or SQL_NTS
16116  * @param connOut driver connect output string
16117  * @param connOutMax length of driver connect output string
16118  * @param connOutLen output length of driver connect output string
16119  * @param drvcompl completion type
16120  * @result ODBC error code
16121  */
16122 
16123 SQLRETURN SQL_API
SQLDriverConnectW(SQLHDBC dbc,SQLHWND hwnd,SQLWCHAR * connIn,SQLSMALLINT connInLen,SQLWCHAR * connOut,SQLSMALLINT connOutMax,SQLSMALLINT * connOutLen,SQLUSMALLINT drvcompl)16124 SQLDriverConnectW(SQLHDBC dbc, SQLHWND hwnd,
16125 		  SQLWCHAR *connIn, SQLSMALLINT connInLen,
16126 		  SQLWCHAR *connOut, SQLSMALLINT connOutMax,
16127 		  SQLSMALLINT *connOutLen, SQLUSMALLINT drvcompl)
16128 {
16129     SQLRETURN ret;
16130     char *ci = NULL;
16131     SQLSMALLINT len = 0;
16132 
16133     HDBC_LOCK(dbc);
16134     if (connIn) {
16135 	if (connInLen == SQL_NTS) {
16136 	    connInLen = -1;
16137 	}
16138 	ci = uc_to_utf_c(connIn, connInLen);
16139 	if (!ci) {
16140 	    DBC *d = (DBC *) dbc;
16141 
16142 	    setstatd(d, -1, "out of memory", (*d->ov3) ? "HY000" : "S1000");
16143 	    HDBC_UNLOCK(dbc);
16144 	    return SQL_ERROR;
16145 	}
16146     }
16147     ret = drvdriverconnect(dbc, hwnd, (SQLCHAR *) ci, SQL_NTS,
16148 			   (SQLCHAR *) connOut, connOutMax, &len, drvcompl);
16149     HDBC_UNLOCK(dbc);
16150     uc_free(ci);
16151     if (ret == SQL_SUCCESS) {
16152 	SQLWCHAR *co = NULL;
16153 
16154 	if (connOut) {
16155 	    if (len > 0) {
16156 		co = uc_from_utf((SQLCHAR *) connOut, len);
16157 		if (co) {
16158 		    uc_strncpy(connOut, co, connOutMax / sizeof (SQLWCHAR));
16159 		    len = min(connOutMax / sizeof (SQLWCHAR), uc_strlen(co));
16160 		    uc_free(co);
16161 		} else {
16162 		    len = 0;
16163 		}
16164 	    }
16165 	    if (len <= 0) {
16166 		len = 0;
16167 		connOut[0] = 0;
16168 	    }
16169 	} else {
16170 	    len = 0;
16171 	}
16172 	if (connOutLen) {
16173 	    *connOutLen = len;
16174 	}
16175     }
16176     return ret;
16177 }
16178 #endif
16179 
16180 #if defined(_WIN32) || defined(_WIN64)
16181 
16182 /**
16183  * DLL initializer for WIN32.
16184  * @param hinst instance handle
16185  * @param reason reason code for entry point
16186  * @param reserved
16187  * @result always true
16188  */
16189 
16190 BOOL APIENTRY
LibMain(HANDLE hinst,DWORD reason,LPVOID reserved)16191 LibMain(HANDLE hinst, DWORD reason, LPVOID reserved)
16192 {
16193     static int initialized = 0;
16194 
16195     switch (reason) {
16196     case DLL_PROCESS_ATTACH:
16197 	if (!initialized++) {
16198 	    hModule = hinst;
16199 #ifdef WINTERFACE
16200 	    /* MS Access hack part 1 (reserved error -7748) */
16201 	    statSpec2P = statSpec2;
16202 	    statSpec3P = statSpec3;
16203 #endif
16204 	}
16205 	break;
16206     case DLL_THREAD_ATTACH:
16207 	break;
16208     case DLL_PROCESS_DETACH:
16209 	--initialized;
16210 	break;
16211     case DLL_THREAD_DETACH:
16212 	break;
16213     default:
16214 	break;
16215     }
16216     return TRUE;
16217 }
16218 
16219 /**
16220  * DLL entry point for WIN32.
16221  * @param hinst instance handle
16222  * @param reason reason code for entry point
16223  * @param reserved
16224  * @result always true
16225  */
16226 
16227 int __stdcall
DllMain(HANDLE hinst,DWORD reason,LPVOID reserved)16228 DllMain(HANDLE hinst, DWORD reason, LPVOID reserved)
16229 {
16230     return LibMain(hinst, reason, reserved);
16231 }
16232 
16233 #ifndef WITHOUT_INSTALLER
16234 
16235 /**
16236  * Handler for driver installer/uninstaller error messages.
16237  * @param name name of API function for which to show error messages
16238  * @result true when error message retrieved
16239  */
16240 
16241 static BOOL
InUnError(char * name)16242 InUnError(char *name)
16243 {
16244     WORD err = 1;
16245     DWORD code;
16246     char errmsg[301];
16247     WORD errlen, errmax = sizeof (errmsg) - 1;
16248     int sqlret;
16249     BOOL ret = FALSE;
16250 
16251     do {
16252 	errmsg[0] = '\0';
16253 	sqlret = SQLInstallerError(err, &code, errmsg, errmax, &errlen);
16254 	if (SQL_SUCCEEDED(sqlret)) {
16255 	    MessageBox(NULL, errmsg, name,
16256 		       MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
16257 	    ret = TRUE;
16258 	}
16259 	err++;
16260     } while (sqlret != SQL_NO_DATA);
16261     return ret;
16262 }
16263 
16264 /**
16265  * Built in driver installer/uninstaller.
16266  * @param remove true for uninstall
16267  * @param cmdline command line string of rundll32
16268  */
16269 
16270 static BOOL
InUn(int remove,char * cmdline)16271 InUn(int remove, char *cmdline)
16272 {
16273 #ifdef WINTERFACE
16274     static char *drivername = "SQLite ODBC (UTF-8) Driver";
16275     static char *dsname = "SQLite3 UTF-8 Datasource";
16276 #else
16277     static char *drivername = "SQLite3 ODBC Driver";
16278     static char *dsname = "SQLite Datasource";
16279 #endif
16280     char *dllname, *p;
16281     char dllbuf[301], path[301], driver[300], attr[300], inst[400];
16282     WORD pathmax = sizeof (path) - 1, pathlen;
16283     DWORD usecnt, mincnt;
16284     int quiet = 0;
16285 
16286     dllbuf[0] = '\0';
16287     GetModuleFileName(hModule, dllbuf, sizeof (dllbuf));
16288     p = strrchr(dllbuf, '\\');
16289     dllname = p ? (p + 1) : dllbuf;
16290     quiet = cmdline && strstr(cmdline, "quiet");
16291     if (SQLInstallDriverManager(path, pathmax, &pathlen)) {
16292 	sprintf(driver, "%s;Driver=%s;Setup=%s;",
16293 		drivername, dllname, dllname);
16294 	p = driver;
16295 	while (*p) {
16296 	    if (*p == ';') {
16297 		*p = '\0';
16298 	    }
16299 	    ++p;
16300 	}
16301 	usecnt = 0;
16302 	path[0] = '\0';
16303 	SQLInstallDriverEx(driver, NULL, path, pathmax, NULL,
16304 			   ODBC_INSTALL_INQUIRY, &usecnt);
16305 	pathlen = strlen(path);
16306 	while (pathlen > 0 && path[pathlen - 1] == '\\') {
16307 	    --pathlen;
16308 	    path[pathlen] = '\0';
16309 	}
16310 	sprintf(driver, "%s;Driver=%s\\%s;Setup=%s\\%s;",
16311 		drivername, path, dllname, path, dllname);
16312 	p = driver;
16313 	while (*p) {
16314 	    if (*p == ';') {
16315 		*p = '\0';
16316 	    }
16317 	    ++p;
16318 	}
16319 	sprintf(inst, "%s\\%s", path, dllname);
16320 	if (!remove && usecnt > 0) {
16321 	    /* first install try: copy over driver dll, keeping DSNs */
16322 	    if (GetFileAttributesA(dllbuf) != INVALID_FILE_ATTRIBUTES &&
16323 		CopyFile(dllbuf, inst, 0)) {
16324 		if (!quiet) {
16325 		    char buf[512];
16326 
16327 		    sprintf(buf, "%s replaced.", drivername);
16328 		    MessageBox(NULL, buf, "Info",
16329 			       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
16330 			       MB_SETFOREGROUND);
16331 		}
16332 		return TRUE;
16333 	    }
16334 	}
16335 	mincnt = remove ? 1 : 0;
16336 	while (usecnt != mincnt) {
16337 	    if (!SQLRemoveDriver(driver, TRUE, &usecnt)) {
16338 		break;
16339 	    }
16340 	}
16341 	if (remove) {
16342 	    if (usecnt && !SQLRemoveDriver(driver, TRUE, &usecnt)) {
16343 		InUnError("SQLRemoveDriver");
16344 		return FALSE;
16345 	    }
16346 	    if (!usecnt) {
16347 		char buf[512];
16348 
16349 		DeleteFile(inst);
16350 		if (!quiet) {
16351 		    sprintf(buf, "%s uninstalled.", drivername);
16352 		    MessageBox(NULL, buf, "Info",
16353 			       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
16354 			       MB_SETFOREGROUND);
16355 		}
16356 	    }
16357 	    sprintf(attr, "DSN=%s;Database=;", dsname);
16358 	    p = attr;
16359 	    while (*p) {
16360 		if (*p == ';') {
16361 		    *p = '\0';
16362 		}
16363 		++p;
16364 	    }
16365 	    SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
16366 	    return TRUE;
16367 	}
16368 	if (GetFileAttributesA(dllbuf) == INVALID_FILE_ATTRIBUTES) {
16369 	    return FALSE;
16370 	}
16371 	if (strcasecmp(dllbuf, inst) != 0 && !CopyFile(dllbuf, inst, 0)) {
16372 	    char buf[512];
16373 
16374 	    sprintf(buf, "Copy %s to %s failed.", dllbuf, inst);
16375 	    MessageBox(NULL, buf, "CopyFile",
16376 		       MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
16377 	    return FALSE;
16378 	}
16379 	if (!SQLInstallDriverEx(driver, path, path, pathmax, &pathlen,
16380 				ODBC_INSTALL_COMPLETE, &usecnt)) {
16381 	    InUnError("SQLInstallDriverEx");
16382 	    return FALSE;
16383 	}
16384 	sprintf(attr, "DSN=%s;Database=;", dsname);
16385 	p = attr;
16386 	while (*p) {
16387 	    if (*p == ';') {
16388 		*p = '\0';
16389 	    }
16390 	    ++p;
16391 	}
16392 	SQLConfigDataSource(NULL, ODBC_REMOVE_SYS_DSN, drivername, attr);
16393 	if (!SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, drivername, attr)) {
16394 	    InUnError("SQLConfigDataSource");
16395 	    return FALSE;
16396 	}
16397 	if (!quiet) {
16398 	    char buf[512];
16399 
16400 	    sprintf(buf, "%s installed.", drivername);
16401 	    MessageBox(NULL, buf, "Info",
16402 		       MB_ICONINFORMATION | MB_OK | MB_TASKMODAL |
16403 		       MB_SETFOREGROUND);
16404 	}
16405     } else {
16406 	InUnError("SQLInstallDriverManager");
16407 	return FALSE;
16408     }
16409     return TRUE;
16410 }
16411 
16412 /**
16413  * RunDLL32 entry point for driver installation.
16414  * @param hwnd window handle of caller
16415  * @param hinst of this DLL
16416  * @param lpszCmdLine rundll32 command line tail
16417  * @param nCmdShow ignored
16418  */
16419 
16420 void CALLBACK
install(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)16421 install(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
16422 {
16423     InUn(0, lpszCmdLine);
16424 }
16425 
16426 /**
16427  * RunDLL32 entry point for driver uninstallation.
16428  * @param hwnd window handle of caller
16429  * @param hinst of this DLL
16430  * @param lpszCmdLine rundll32 command line tail
16431  * @param nCmdShow ignored
16432  */
16433 
16434 void CALLBACK
uninstall(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)16435 uninstall(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
16436 {
16437     InUn(1, lpszCmdLine);
16438 }
16439 
16440 #endif /* WITHOUT_INSTALLER */
16441 
16442 #ifndef WITHOUT_SHELL
16443 
16444 /**
16445  * Setup argv vector from string
16446  * @param argcp pointer to argc
16447  * @param argvp pointer to argv
16448  * @param cmdline command line string
16449  * @param argv0 0th element for argv or NULL, must be static
16450  */
16451 
16452 static void
setargv(int * argcp,char *** argvp,char * cmdline,char * argv0)16453 setargv(int *argcp, char ***argvp, char *cmdline, char *argv0)
16454 {
16455     char *p, *arg, *argspace, **argv;
16456     int argc, size, inquote, copy, slashes;
16457 
16458     size = 2 + (argv0 ? 1 : 0);
16459     for (p = cmdline; *p != '\0'; p++) {
16460 	if (ISSPACE(*p)) {
16461 	    size++;
16462 	    while (ISSPACE(*p)) {
16463 		p++;
16464 	    }
16465 	    if (*p == '\0') {
16466 		break;
16467 	    }
16468 	}
16469     }
16470     argspace = malloc(size * sizeof (char *) + strlen(cmdline) + 1);
16471     argv = (char **) argspace;
16472     argspace += size * sizeof (char *);
16473     size--;
16474     argc = 0;
16475     if (argv0) {
16476 	argv[argc++] = argv0;
16477     }
16478     p = cmdline;
16479     for (; argc < size; argc++) {
16480 	argv[argc] = arg = argspace;
16481 	while (ISSPACE(*p)) {
16482 	    p++;
16483 	}
16484 	if (*p == '\0') {
16485 	    break;
16486 	}
16487 	inquote = 0;
16488 	slashes = 0;
16489 	while (1) {
16490 	    copy = 1;
16491 	    while (*p == '\\') {
16492 		slashes++;
16493 		p++;
16494 	    }
16495 	    if (*p == '"') {
16496 		if ((slashes & 1) == 0) {
16497 		    copy = 0;
16498 		    if (inquote && p[1] == '"') {
16499 			p++;
16500 			copy = 1;
16501 		    } else {
16502 			inquote = !inquote;
16503 		    }
16504 		}
16505 		slashes >>= 1;
16506 	    }
16507 	    while (slashes) {
16508 		*arg = '\\';
16509 		arg++;
16510 		slashes--;
16511 	    }
16512 	    if (*p == '\0' || (!inquote && ISSPACE(*p))) {
16513 		break;
16514 	    }
16515 	    if (copy != 0) {
16516 		*arg = *p;
16517 		arg++;
16518 	    }
16519 	    p++;
16520 	}
16521 	*arg = '\0';
16522 	argspace = arg + 1;
16523     }
16524     argv[argc] = 0;
16525     *argcp = argc;
16526     *argvp = argv;
16527 }
16528 
16529 /**
16530  * RunDLL32 entry point for SQLite shell
16531  * @param hwnd window handle of caller
16532  * @param hinst of this DLL
16533  * @param lpszCmdLine rundll32 command line tail
16534  * @param nCmdShow ignored
16535  */
16536 
16537 void CALLBACK
shell(HWND hwnd,HINSTANCE hinst,LPSTR lpszCmdLine,int nCmdShow)16538 shell(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
16539 {
16540     int argc, needcon = 0;
16541     char **argv;
16542     extern int sqlite_main(int, char **);
16543     static const char *name = "SQLite Shell";
16544     DWORD ftype0, ftype1, ftype2;
16545 
16546     ftype0 = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
16547     ftype1 = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
16548     ftype2 = GetFileType(GetStdHandle(STD_ERROR_HANDLE));
16549     if (ftype0 != FILE_TYPE_DISK && ftype0 != FILE_TYPE_CHAR &&
16550 	ftype0 != FILE_TYPE_PIPE) {
16551 	fclose(stdin);
16552 	++needcon;
16553 	ftype0 = FILE_TYPE_UNKNOWN;
16554     }
16555     if (ftype1 != FILE_TYPE_DISK && ftype1 != FILE_TYPE_CHAR &&
16556 	ftype1 != FILE_TYPE_PIPE) {
16557 	fclose(stdout);
16558 	++needcon;
16559 	ftype1 = FILE_TYPE_UNKNOWN;
16560     }
16561     if (ftype2 != FILE_TYPE_DISK && ftype2 != FILE_TYPE_CHAR &&
16562 	ftype2 != FILE_TYPE_PIPE) {
16563 	fclose(stderr);
16564 	++needcon;
16565 	ftype2 = FILE_TYPE_UNKNOWN;
16566     }
16567     if (needcon > 0) {
16568 	AllocConsole();
16569 	SetConsoleTitle(name);
16570     }
16571     if (ftype0 == FILE_TYPE_UNKNOWN) {
16572 	freopen("CONIN$", "r", stdin);
16573     }
16574     if (ftype1 == FILE_TYPE_UNKNOWN) {
16575 	freopen("CONOUT$", "w", stdout);
16576     }
16577     if (ftype2 == FILE_TYPE_UNKNOWN) {
16578 	freopen("CONOUT$", "w", stderr);
16579     }
16580     setargv(&argc, &argv, lpszCmdLine, (char *) name);
16581     sqlite_main(argc, argv);
16582 }
16583 
16584 #endif /* WITHOUT_SHELL */
16585 
16586 #endif /* _WIN32 || _WIN64 */
16587 
16588 #if defined(HAVE_ODBCINSTEXT_H) && (HAVE_ODBCINSTEXT_H)
16589 
16590 /*
16591  * unixODBC property page for this driver,
16592  * may or may not work depending on unixODBC version.
16593  */
16594 
16595 #include <odbcinstext.h>
16596 
16597 int
ODBCINSTGetProperties(HODBCINSTPROPERTY prop)16598 ODBCINSTGetProperties(HODBCINSTPROPERTY prop)
16599 {
16600     static const char *instYN[] = { "No", "Yes", NULL };
16601 
16602     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
16603     prop = prop->pNext;
16604     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
16605     prop->nPromptType = ODBCINST_PROMPTTYPE_FILENAME;
16606     strncpy(prop->szName, "Database", INI_MAX_PROPERTY_NAME);
16607     strncpy(prop->szValue, "", INI_MAX_PROPERTY_VALUE);
16608     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
16609     prop = prop->pNext;
16610     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
16611     prop->nPromptType = ODBCINST_PROMPTTYPE_TEXTEDIT;
16612     strncpy(prop->szName, "Timeout", INI_MAX_PROPERTY_NAME);
16613     strncpy(prop->szValue, "100000", INI_MAX_PROPERTY_VALUE);
16614     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
16615     prop = prop->pNext;
16616     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
16617     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
16618     prop->aPromptData = malloc(sizeof (instYN));
16619     memcpy(prop->aPromptData, instYN, sizeof (instYN));
16620     strncpy(prop->szName, "StepAPI", INI_MAX_PROPERTY_NAME);
16621     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
16622 #ifdef WINTERFACE
16623     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
16624     prop = prop->pNext;
16625     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
16626     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
16627     prop->aPromptData = malloc(sizeof (instYN));
16628     memcpy(prop->aPromptData, instYN, sizeof (instYN));
16629     strncpy(prop->szName, "NoWCHAR", INI_MAX_PROPERTY_NAME);
16630     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
16631 #endif
16632     prop->pNext = (HODBCINSTPROPERTY) malloc(sizeof (ODBCINSTPROPERTY));
16633     prop = prop->pNext;
16634     memset(prop, 0, sizeof (ODBCINSTPROPERTY));
16635     prop->nPromptType = ODBCINST_PROMPTTYPE_COMBOBOX;
16636     prop->aPromptData = malloc(sizeof (instYN));
16637     memcpy(prop->aPromptData, instYN, sizeof (instYN));
16638     strncpy(prop->szName, "LongNames", INI_MAX_PROPERTY_NAME);
16639     strncpy(prop->szValue, "No", INI_MAX_PROPERTY_VALUE);
16640     return 1;
16641 }
16642 
16643 #endif /* HAVE_ODBCINSTEXT_H */
16644 
16645 /*
16646  * Local Variables:
16647  * mode: c
16648  * c-basic-offset: 4
16649  * fill-column: 78
16650  * tab-width: 8
16651  * End:
16652  */
16653