Merge commit 'origin/master'
[versaplex.git] / vxodbc / convert.cc
blob6266871b116973ef58464f298486545e466561bc
1 /*
2 * Description: This module contains routines related to
3 * converting parameters and columns into requested data types.
4 * Parameters are converted from their SQL_C data types into
5 * the appropriate postgres type. Columns are converted from
6 * their postgres type (SQL type) into the appropriate SQL_C
7 * data type.
8 */
9 /* Multibyte support Eiji Tokuya 2001-03-15 */
11 #include "convert.h"
12 #ifdef WIN32
13 #include <float.h>
14 #endif /* WIN32 */
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
20 #include "multibyte.h"
22 #include <time.h>
23 #ifdef HAVE_LOCALE_H
24 #include <locale.h>
25 #endif
26 #include <math.h>
27 #include <stdlib.h>
28 #include "statement.h"
29 #include "qresult.h"
30 #include "bind.h"
31 #include "pgtypes.h"
32 #include "connection.h"
33 #include "catfunc.h"
34 #include "pgapifunc.h"
36 #if defined(UNICODE_SUPPORT) && defined(WIN32)
37 #define WIN_UNICODE_SUPPORT
38 #endif
40 CSTR NAN_STRING = "NaN";
41 CSTR INFINITY_STRING = "Infinity";
42 CSTR MINFINITY_STRING = "-Infinity";
44 #ifdef __CYGWIN__
45 #define TIMEZONE_GLOBAL _timezone
46 #elif defined(WIN32) || defined(HAVE_INT_TIMEZONE)
47 #define TIMEZONE_GLOBAL timezone
48 #endif
51 static int conv_from_octal(const UCHAR * s);
52 static SQLLEN pg_bin2hex(UCHAR * src, UCHAR * dst, SQLLEN length);
54 /*---------
55 * A Guide for date/time/timestamp conversions
57 * field_type fCType Output
58 * ---------- ------ ----------
59 * PG_TYPE_DATE SQL_C_DEFAULT SQL_C_DATE
60 * PG_TYPE_DATE SQL_C_DATE SQL_C_DATE
61 * PG_TYPE_DATE SQL_C_TIMESTAMP SQL_C_TIMESTAMP (time = 0 (midnight))
62 * PG_TYPE_TIME SQL_C_DEFAULT SQL_C_TIME
63 * PG_TYPE_TIME SQL_C_TIME SQL_C_TIME
64 * PG_TYPE_TIME SQL_C_TIMESTAMP SQL_C_TIMESTAMP (date = current date)
65 * PG_TYPE_ABSTIME SQL_C_DEFAULT SQL_C_TIMESTAMP
66 * PG_TYPE_ABSTIME SQL_C_DATE SQL_C_DATE (time is truncated)
67 * PG_TYPE_ABSTIME SQL_C_TIME SQL_C_TIME (date is truncated)
68 * PG_TYPE_ABSTIME SQL_C_TIMESTAMP SQL_C_TIMESTAMP
69 *---------
74 * Macros for unsigned long handling.
76 #ifdef WIN32
77 #define ATOI32U atol
78 #elif defined(HAVE_STRTOUL)
79 #define ATOI32U(val) strtoul(val, NULL, 10)
80 #else /* HAVE_STRTOUL */
81 #define ATOI32U atol
82 #endif /* WIN32 */
85 * Macros for BIGINT handling.
87 #ifdef ODBCINT64
88 #ifdef WIN32
89 #define ATOI64 _atoi64
90 #define ATOI64U _atoi64
91 #define FORMATI64 "%I64d"
92 #define FORMATI64U "%I64u"
93 #elif (SIZEOF_LONG == 8)
94 #define ATOI64(val) strtol(val, NULL, 10)
95 #define ATOI64U(val) strtoul(val, NULL, 10)
96 #define FORMATI64 "%ld"
97 #define FORMATI64U "%lu"
98 #else
99 #define FORMATI64 "%lld"
100 #define FORMATI64U "%llu"
101 #if defined(HAVE_STRTOLL)
102 #define ATOI64(val) strtoll(val, NULL, 10)
103 #define ATOI64U(val) strtoull(val, NULL, 10)
104 #else
105 static ODBCINT64 ATOI64(const char *val)
107 ODBCINT64 ll;
108 sscanf(val, "%lld", &ll);
109 return ll;
111 static unsigned ODBCINT64 ATOI64U(const char *val)
113 unsigned ODBCINT64 ll;
114 sscanf(val, "%llu", &ll);
115 return ll;
117 #endif /* HAVE_STRTOLL */
118 #endif /* WIN32 */
119 #endif /* ODBCINT64 */
122 * TIMESTAMP <-----> SIMPLE_TIME
123 * precision support since 7.2.
124 * time zone support is unavailable(the stuff is unreliable)
126 // FIXME: Anyone calling this function is probably doing something undesirable
127 static BOOL
128 stime2timestamp(const SIMPLE_TIME * st, char *str, BOOL bZone,
129 BOOL precision)
131 char precstr[16], zonestr[16];
132 int i;
134 precstr[0] = '\0';
135 if (st->infinity > 0)
137 strcpy(str, INFINITY_STRING);
138 return TRUE;
139 } else if (st->infinity < 0)
141 strcpy(str, MINFINITY_STRING);
142 return TRUE;
144 if (precision && st->fr)
146 sprintf(precstr, ".%09d", st->fr);
147 for (i = 9; i > 0; i--)
149 if (precstr[i] != '0')
150 break;
151 precstr[i] = '\0';
154 zonestr[0] = '\0';
155 #ifdef TIMEZONE_GLOBAL
156 if (bZone && tzname[0] && tzname[0][0] && st->y >= 1970)
158 long zoneint;
159 struct tm tm;
160 time_t time0;
162 zoneint = TIMEZONE_GLOBAL;
163 if (daylight && st->y >= 1900)
165 tm.tm_year = st->y - 1900;
166 tm.tm_mon = st->m - 1;
167 tm.tm_mday = st->d;
168 tm.tm_hour = st->hh;
169 tm.tm_min = st->mm;
170 tm.tm_sec = st->ss;
171 tm.tm_isdst = -1;
172 time0 = mktime(&tm);
173 if (time0 >= 0 && tm.tm_isdst > 0)
174 zoneint -= 3600;
176 if (zoneint > 0)
177 sprintf(zonestr, "-%02d", (int) zoneint / 3600);
178 else
179 sprintf(zonestr, "+%02d", -(int) zoneint / 3600);
181 #endif /* TIMEZONE_GLOBAL */
182 if (st->y < 0)
183 sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s BC", -st->y,
184 st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr);
185 else
186 sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st->y, st->m,
187 st->d, st->hh, st->mm, st->ss, precstr, zonestr);
188 return TRUE;
191 /* This is called by SQLFetch() */
193 copy_and_convert_field_bindinfo(StatementClass * stmt, OID field_type,
194 void *value, int col)
196 ARDFields *opts = SC_get_ARDF(stmt);
197 BindInfoClass *bic = &(opts->bindings[col]);
198 SQLULEN offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
200 SC_set_current_col(stmt, -1);
201 return copy_and_convert_field(stmt, field_type, value,
202 bic->returntype,
203 (PTR) (bic->buffer + offset),
204 bic->buflen, LENADDR_SHIFT(bic->used,
205 offset),
206 LENADDR_SHIFT(bic->indicator,
207 offset));
210 static double get_double_value(const char *str)
212 if (stricmp(str, NAN_STRING) == 0)
213 return NAN;
214 else if (stricmp(str, INFINITY_STRING) == 0)
215 return INFINITY;
216 else if (stricmp(str, MINFINITY_STRING) == 0)
217 return -INFINITY;
218 return atof(str);
221 /* This is called by SQLGetData() */
223 copy_and_convert_field(StatementClass * stmt, OID field_type,
224 void *valuei, SQLSMALLINT fCType, PTR rgbValue,
225 SQLLEN cbValueMax, SQLLEN * pcbValue,
226 SQLLEN * pIndicator)
228 CSTR func = "copy_and_convert_field";
229 const char *value = (const char *)valuei;
230 ARDFields *opts = SC_get_ARDF(stmt);
231 GetDataInfo *gdata = SC_get_GDTI(stmt);
232 SQLLEN len = 0, copy_len = 0, needbuflen = 0;
233 SIMPLE_TIME std_time;
234 time_t stmt_t = SC_get_time(stmt);
235 struct tm *tim;
236 SQLLEN pcbValueOffset, rgbValueOffset;
237 char *rgbValueBindRow = NULL;
238 SQLLEN *pcbValueBindRow = NULL, *pIndicatorBindRow = NULL;
239 const char *ptr;
240 SQLSETPOSIROW bind_row = stmt->bind_row;
241 int bind_size = opts->bind_size;
242 int result = COPY_OK;
243 ConnectionClass *conn = SC_get_conn(stmt);
244 BOOL changed, true_is_minus1 = FALSE;
245 BOOL text_handling, localize_needed;
246 const char *neut_str = value;
247 char midtemp[2][32];
248 int mtemp_cnt = 0;
249 GetDataClass *pgdc;
250 #ifdef UNICODE_SUPPORT
251 BOOL wconverted = FALSE;
252 #endif /* UNICODE_SUPPORT */
253 #ifdef WIN_UNICODE_SUPPORT
254 SQLWCHAR *allocbuf = NULL;
255 ssize_t wstrlen;
256 #endif /* WIN_UNICODE_SUPPORT */
257 #ifdef HAVE_LOCALE_H
258 char *saved_locale;
259 #endif /* HAVE_LOCALE_H */
261 if (stmt->current_col >= 0)
263 if (stmt->current_col >= opts->allocated)
265 return SQL_ERROR;
267 if (gdata->allocated != opts->allocated)
268 extend_getdata_info(gdata, opts->allocated, TRUE);
269 pgdc = &gdata->gdata[stmt->current_col];
270 if (pgdc->data_left == -2)
271 pgdc->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
272 * needed by ADO ? */
273 if (pgdc->data_left == 0)
275 if (pgdc->ttlbuf != NULL)
277 free(pgdc->ttlbuf);
278 pgdc->ttlbuf = NULL;
279 pgdc->ttlbuflen = 0;
281 pgdc->data_left = -2; /* needed by ADO ? */
282 return COPY_NO_DATA_FOUND;
285 /*---------
286 * rgbValueOffset is *ONLY* for character and binary data.
287 * pcbValueOffset is for computing any pcbValue location
288 *---------
291 if (bind_size > 0)
292 pcbValueOffset = rgbValueOffset = (bind_size * bind_row);
293 else
295 pcbValueOffset = bind_row * sizeof(SQLLEN);
296 rgbValueOffset = bind_row * cbValueMax;
299 * The following is applicable in case bind_size > 0
300 * or the fCType is of variable length.
302 if (rgbValue)
303 rgbValueBindRow = (char *) rgbValue + rgbValueOffset;
304 if (pcbValue)
305 pcbValueBindRow = LENADDR_SHIFT(pcbValue, pcbValueOffset);
306 if (pIndicator)
308 pIndicatorBindRow = LENADDR_SHIFT(pIndicator, pcbValueOffset);
309 *pIndicatorBindRow = 0;
312 memset(&std_time, 0, sizeof(SIMPLE_TIME));
314 /* Initialize current date */
315 #ifdef HAVE_GMTIME_R
316 struct tm tm;
317 tim = gmtime_r(&stmt_t, &tm);
318 #else
319 tim = gmtime(&stmt_t);
320 #endif /* HAVE_GMTIME_R */
321 std_time.m = tim->tm_mon + 1;
322 std_time.d = tim->tm_mday;
323 std_time.y = tim->tm_year + 1900;
325 mylog
326 ("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n",
327 field_type, fCType, (value == NULL) ? "<NULL>" : value,
328 cbValueMax);
330 if (!value)
332 mylog("null_cvt_date_string=%d\n",
333 conn->connInfo.cvt_null_date_string);
334 /* a speicial handling for FOXPRO NULL -> NULL_STRING */
335 if (conn->connInfo.cvt_null_date_string > 0 &&
336 PG_TYPE_DATE == field_type &&
337 (SQL_C_CHAR == fCType ||
338 SQL_C_TYPE_DATE == fCType || SQL_C_DEFAULT == fCType))
340 if (pcbValueBindRow)
341 *pcbValueBindRow = 0;
342 switch (fCType)
344 case SQL_C_CHAR:
345 if (rgbValueBindRow && cbValueMax > 0)
346 rgbValueBindRow = '\0';
347 else
348 result = COPY_RESULT_TRUNCATED;
349 break;
350 case SQL_C_TYPE_DATE:
351 case SQL_C_DEFAULT:
352 if (rgbValueBindRow
353 && cbValueMax >= sizeof(DATE_STRUCT))
355 memset(rgbValueBindRow, 0, cbValueMax);
356 if (pcbValueBindRow)
357 *pcbValueBindRow = sizeof(DATE_STRUCT);
358 } else
359 result = COPY_RESULT_TRUNCATED;
360 break;
361 #ifdef UNICODE_SUPPORT
362 case SQL_C_WCHAR:
363 if (rgbValueBindRow && cbValueMax >= WCLEN)
364 memset(rgbValueBindRow, 0, WCLEN);
365 else
366 result = COPY_RESULT_TRUNCATED;
367 break;
368 #endif /* UNICODE_SUPPORT */
370 return result;
373 * handle a null just by returning SQL_NULL_DATA in pcbValue, and
374 * doing nothing to the buffer.
376 else if (pIndicator)
378 *pIndicatorBindRow = SQL_NULL_DATA;
379 return COPY_OK;
380 } else
382 SC_set_error(stmt, STMT_RETURN_NULL_WITHOUT_INDICATOR,
383 "StrLen_or_IndPtr was a null pointer and NULL data was retrieved",
384 func);
385 return SQL_ERROR;
389 if (stmt->hdbc->DataSourceToDriver != NULL)
391 size_t length = strlen(value);
393 stmt->hdbc->DataSourceToDriver(stmt->hdbc->translation_option,
394 SQL_CHAR, valuei,
395 (SDWORD) length, valuei,
396 (SDWORD) length, NULL, NULL, 0,
397 NULL);
401 * First convert any specific postgres types into more useable data.
403 * NOTE: Conversions from PG char/varchar of a date/time/timestamp value
404 * to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
406 switch (field_type)
409 * $$$ need to add parsing for date/time/timestamp strings in
410 * PG_TYPE_CHAR,VARCHAR $$$
412 case VX_TYPE_DATETIME:
414 long long secs;
415 int usecs;
416 sscanf(value, "[%lld,%d]", &secs, &usecs);
418 // January 1, 1900, 00:00:00. Note: outside the range of 32-bit time_t.
419 long long sql_epoch = -2208988800LL;
420 int seconds_per_day = 60*60*24;
421 if (secs >= sql_epoch && secs < sql_epoch + seconds_per_day)
423 // The value is a time of day for the SQL Epoch, aka a SQL time
424 // value. Fudge it to the Unix Epoch, so gmtime() can deal
425 // with it on 32-bit systems. If it was a DateTime, it was going
426 // to be wrong anyway.
427 secs += -sql_epoch;
430 // FIXME: This loses precision on 32-bit systems.
431 time_t secs_time_t = (time_t)secs;
433 struct tm *ptm;
434 #ifdef HAVE_GMTIME_R
435 struct tm tm;
436 if ((ptm = gmtime_r(&secs_time_t, &tm)) != NULL)
437 #else
438 if ((ptm = gmtime(&secs_time_t)) != NULL)
439 #endif /* HAVE_GMTIME_R */
441 std_time.y = ptm->tm_year + 1900;
442 std_time.m = ptm->tm_mon + 1;
443 std_time.d = ptm->tm_mday;
444 std_time.hh = ptm->tm_hour;
445 std_time.mm = ptm->tm_min;
446 std_time.ss = ptm->tm_sec;
447 // The server provides us with millionths of a second, but ODBC
448 // uses billionths
449 std_time.fr = usecs * 1000;
451 break;
453 case PG_TYPE_DATE:
454 sscanf(value, "%4d-%2d-%2d", &std_time.y, &std_time.m,
455 &std_time.d);
456 break;
458 case PG_TYPE_TIME:
459 sscanf(value, "%2d:%2d:%2d", &std_time.hh, &std_time.mm,
460 &std_time.ss);
461 break;
463 case PG_TYPE_BOOL:
464 { /* change T/F to 1/0 */
465 char *s;
467 s = midtemp[mtemp_cnt];
468 switch (((char *) value)[0])
470 case 'f':
471 case 'F':
472 case 'n':
473 case 'N':
474 case '0':
475 strcpy(s, "0");
476 break;
477 default:
478 if (true_is_minus1)
479 strcpy(s, "-1");
480 else
481 strcpy(s, "1");
483 neut_str = midtemp[mtemp_cnt];
484 mtemp_cnt++;
486 break;
488 /* This is for internal use by SQLStatistics() */
489 case PG_TYPE_INT2VECTOR:
490 if (SQL_C_DEFAULT == fCType)
492 int i, nval, maxc;
493 const char *vp;
494 /* this is an array of eight integers */
495 short *short_array = (short *) rgbValueBindRow, shortv;
497 maxc = 0;
498 if (NULL != short_array)
499 maxc = (int) cbValueMax / sizeof(short);
500 vp = value;
501 nval = 0;
502 mylog("index=(");
503 for (i = 0;; i++)
505 if (sscanf(vp, "%hi", &shortv) != 1)
506 break;
507 mylog(" %hi", shortv);
508 if (0 == shortv && PG_VERSION_LT(conn, 7.2))
509 break;
510 nval++;
511 if (nval < maxc)
512 short_array[i + 1] = shortv;
514 /* skip the current token */
515 while ((*vp != '\0') && (!isspace((UCHAR) * vp)))
516 vp++;
517 /* and skip the space to the next token */
518 while ((*vp != '\0') && (isspace((UCHAR) * vp)))
519 vp++;
520 if (*vp == '\0')
521 break;
523 mylog(") nval = %i\n", nval);
524 if (maxc > 0)
525 short_array[0] = nval;
527 /* There is no corresponding fCType for this. */
528 len = (nval + 1) * sizeof(short);
529 if (pcbValue)
530 *pcbValueBindRow = len;
532 if (len <= cbValueMax)
533 return COPY_OK; /* dont go any further or the data will be
534 * trashed */
535 else
536 return COPY_RESULT_TRUNCATED;
538 break;
541 * This is a large object OID, which is used to store
542 * LONGVARBINARY objects.
544 case PG_TYPE_LO_UNDEFINED:
546 SC_set_error(stmt, STMT_EXEC_ERROR, "Large objects are not supported.",
547 func);
548 return SQL_ERROR;
550 default:
551 break;
555 /* Change default into something useable */
556 if (fCType == SQL_C_DEFAULT)
558 fCType = pgtype_to_ctype(stmt, field_type);
559 if (fCType == SQL_C_WCHAR && CC_default_is_c(conn))
560 fCType = SQL_C_CHAR;
562 mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
565 text_handling = localize_needed = FALSE;
566 switch (fCType)
568 case INTERNAL_ASIS_TYPE:
569 #ifdef UNICODE_SUPPORT
570 case SQL_C_WCHAR:
571 #endif /* UNICODE_SUPPORT */
572 case SQL_C_CHAR:
573 text_handling = TRUE;
574 break;
575 case SQL_C_BINARY:
576 switch (field_type)
578 case PG_TYPE_UNKNOWN:
579 case PG_TYPE_BPCHAR:
580 case PG_TYPE_VARCHAR:
581 case PG_TYPE_TEXT:
582 case PG_TYPE_BPCHARARRAY:
583 case PG_TYPE_VARCHARARRAY:
584 case PG_TYPE_TEXTARRAY:
585 text_handling = TRUE;
586 break;
588 break;
590 if (text_handling)
592 #ifdef WIN_UNICODE_SUPPORT
593 if (SQL_C_CHAR == fCType || SQL_C_BINARY == fCType)
594 localize_needed = TRUE;
595 #endif /* WIN_UNICODE_SUPPORT */
598 if (text_handling)
600 /* Special character formatting as required */
603 * These really should return error if cbValueMax is not big
604 * enough.
606 switch (field_type)
608 case PG_TYPE_DATE:
609 len = 10;
610 if (cbValueMax > len)
611 sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d", std_time.y,
612 std_time.m, std_time.d);
613 break;
615 case PG_TYPE_TIME:
616 len = 8;
617 if (cbValueMax > len)
618 sprintf(rgbValueBindRow, "%.2d:%.2d:%.2d", std_time.hh,
619 std_time.mm, std_time.ss);
620 break;
622 case VX_TYPE_DATETIME:
623 len = 19;
624 if (cbValueMax > len)
626 if (!std_time.hh && !std_time.mm &&!std_time.ss)
627 sprintf(rgbValueBindRow,
628 "%.4d-%.2d-%.2d", std_time.y,
629 std_time.m, std_time.d);
630 else
631 sprintf(rgbValueBindRow,
632 "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", std_time.y,
633 std_time.m, std_time.d, std_time.hh,
634 std_time.mm, std_time.ss);
635 len = strlen(rgbValueBindRow);
637 break;
639 case PG_TYPE_BOOL:
640 len = strlen(neut_str);
641 if (cbValueMax > len)
643 strcpy(rgbValueBindRow, neut_str);
644 mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n",
645 rgbValueBindRow);
647 break;
650 * Currently, data is SILENTLY TRUNCATED for BYTEA and
651 * character data types if there is not enough room in
652 * cbValueMax because the driver can't handle multiple
653 * calls to SQLGetData for these, yet. Most likely, the
654 * buffer passed in will be big enough to handle the
655 * maximum limit of postgres, anyway.
657 * LongVarBinary types are handled correctly above, observing
658 * truncation and all that stuff since there is
659 * essentially no limit on the large object used to store
660 * those.
662 case PG_TYPE_BYTEA: /* convert binary data to hex strings
663 * (i.e, 255 = "FF") */
665 default:
666 if (stmt->current_col < 0)
668 pgdc = &(gdata->fdata);
669 pgdc->data_left = -1;
670 } else
671 pgdc = &gdata->gdata[stmt->current_col];
672 #ifdef UNICODE_SUPPORT
673 if (fCType == SQL_C_WCHAR)
674 wconverted = TRUE;
675 #endif /* UNICODE_SUPPORT */
676 if (pgdc->data_left < 0)
678 BOOL lf_conv = conn->connInfo.lf_conversion;
679 #ifdef UNICODE_SUPPORT
680 if (fCType == SQL_C_WCHAR)
682 len =
683 utf8_to_ucs2_lf(neut_str, SQL_NTS, lf_conv,
684 NULL, 0);
685 len *= WCLEN;
686 changed = TRUE;
687 } else
688 #endif /* UNICODE_SUPPORT */
689 if (PG_TYPE_BYTEA == field_type)
691 len = convert_from_pgbinary((const UCHAR *)neut_str, NULL, 0);
692 len *= 2;
693 changed = TRUE;
694 } else
695 #ifdef WIN_UNICODE_SUPPORT
696 if (localize_needed)
698 wstrlen =
699 utf8_to_ucs2_lf(neut_str, SQL_NTS, lf_conv,
700 NULL, 0);
701 allocbuf =
702 (SQLWCHAR *) malloc(WCLEN * (wstrlen + 1));
703 wstrlen =
704 utf8_to_ucs2_lf(neut_str, SQL_NTS, lf_conv,
705 allocbuf, wstrlen + 1);
706 len =
707 WideCharToMultiByte(CP_ACP, 0,
708 (LPCWSTR) allocbuf,
709 (int) wstrlen, NULL, 0,
710 NULL, NULL);
711 changed = TRUE;
712 } else
713 #endif /* WIN_UNICODE_SUPPORT */
714 /* convert linefeeds to carriage-return/linefeed */
715 len =
716 convert_linefeeds(neut_str, NULL, 0, lf_conv,
717 &changed);
718 if (cbValueMax == 0) /* just returns length
719 * info */
721 result = COPY_RESULT_TRUNCATED;
722 #ifdef WIN_UNICODE_SUPPORT
723 if (allocbuf)
724 free(allocbuf);
725 #endif /* WIN_UNICODE_SUPPORT */
726 break;
728 if (!pgdc->ttlbuf)
729 pgdc->ttlbuflen = 0;
730 needbuflen = len;
731 switch (fCType)
733 #ifdef UNICODE_SUPPORT
734 case SQL_C_WCHAR:
735 needbuflen += WCLEN;
736 break;
737 #endif /* UNICODE_SUPPORT */
738 case SQL_C_BINARY:
739 break;
740 default:
741 needbuflen++;
743 if (changed || needbuflen > cbValueMax)
745 if (needbuflen > (SQLLEN) pgdc->ttlbuflen)
747 pgdc->ttlbuf = (char *)
748 realloc(pgdc->ttlbuf, needbuflen);
749 pgdc->ttlbuflen = needbuflen;
751 #ifdef UNICODE_SUPPORT
752 if (fCType == SQL_C_WCHAR)
754 utf8_to_ucs2_lf(neut_str, SQL_NTS, lf_conv,
755 (SQLWCHAR *) pgdc->ttlbuf,
756 len / WCLEN);
757 } else
758 #endif /* UNICODE_SUPPORT */
759 if (PG_TYPE_BYTEA == field_type)
761 len =
762 convert_from_pgbinary((UCHAR *)neut_str,
763 (UCHAR *)pgdc->ttlbuf,
764 pgdc->ttlbuflen);
765 pg_bin2hex((UCHAR *)pgdc->ttlbuf,
766 (UCHAR *)pgdc->ttlbuf, len);
767 len *= 2;
768 } else
769 #ifdef WIN_UNICODE_SUPPORT
770 if (localize_needed)
772 len =
773 WideCharToMultiByte(CP_ACP, 0, allocbuf,
774 (int) wstrlen,
775 pgdc->ttlbuf,
776 (int) pgdc->ttlbuflen,
777 NULL, NULL);
778 free(allocbuf);
779 allocbuf = NULL;
780 } else
781 #endif /* WIN_UNICODE_SUPPORT */
782 convert_linefeeds(neut_str, pgdc->ttlbuf,
783 pgdc->ttlbuflen, lf_conv,
784 &changed);
785 ptr = pgdc->ttlbuf;
786 pgdc->ttlbufused = len;
787 } else
789 if (pgdc->ttlbuf)
791 free(pgdc->ttlbuf);
792 pgdc->ttlbuf = NULL;
794 ptr = neut_str;
796 } else
798 ptr = pgdc->ttlbuf;
799 len = pgdc->ttlbufused;
802 mylog("DEFAULT: len = %d, ptr = '%.*s'\n", len, len, ptr);
804 if (stmt->current_col >= 0)
806 if (pgdc->data_left > 0)
808 ptr += len - pgdc->data_left;
809 len = pgdc->data_left;
810 needbuflen =
811 len + (pgdc->ttlbuflen - pgdc->ttlbufused);
812 } else
813 pgdc->data_left = len;
816 if (cbValueMax > 0)
818 BOOL already_copied = FALSE;
820 if (fCType == SQL_C_BINARY)
821 copy_len = (len > cbValueMax) ? cbValueMax : len;
822 else
823 copy_len =
824 (len >= cbValueMax) ? (cbValueMax - 1) : len;
825 #ifdef UNICODE_SUPPORT
826 if (fCType == SQL_C_WCHAR)
828 copy_len /= WCLEN;
829 copy_len *= WCLEN;
831 #endif /* UNICODE_SUPPORT */
832 #ifdef HAVE_LOCALE_H
833 switch (field_type)
835 case PG_TYPE_FLOAT4:
836 case PG_TYPE_FLOAT8:
837 case PG_TYPE_NUMERIC:
839 struct lconv *lc;
840 char *new_string;
841 int i, j;
843 new_string = (char *)malloc(cbValueMax);
844 lc = localeconv();
845 for (i = 0, j = 0; ptr[i]; i++)
846 if (ptr[i] == '.')
848 strncpy(&new_string[j],
849 lc->decimal_point,
850 strlen(lc->decimal_point));
851 j += strlen(lc->decimal_point);
852 } else
853 new_string[j++] = ptr[i];
854 new_string[j] = '\0';
855 strncpy_null(rgbValueBindRow, new_string,
856 copy_len + 1);
857 free(new_string);
858 already_copied = TRUE;
859 break;
862 #endif /* HAVE_LOCALE_H */
863 if (!already_copied)
865 /* Copy the data */
866 memcpy(rgbValueBindRow, ptr, copy_len);
867 /* Add null terminator */
868 #ifdef UNICODE_SUPPORT
869 if (fCType == SQL_C_WCHAR)
871 if (copy_len + WCLEN <= cbValueMax)
872 memset(rgbValueBindRow + copy_len, 0,
873 WCLEN);
874 } else
875 #endif /* UNICODE_SUPPORT */
876 if (copy_len < cbValueMax)
877 rgbValueBindRow[copy_len] = '\0';
879 /* Adjust data_left for next time */
880 if (stmt->current_col >= 0)
881 pgdc->data_left -= copy_len;
885 * Finally, check for truncation so that proper status can
886 * be returned
888 if (cbValueMax > 0 && needbuflen > cbValueMax)
889 result = COPY_RESULT_TRUNCATED;
890 else
892 if (pgdc->ttlbuf != NULL)
894 free(pgdc->ttlbuf);
895 pgdc->ttlbuf = NULL;
900 if (SQL_C_WCHAR == fCType)
901 mylog
902 (" SQL_C_WCHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n",
903 len, cbValueMax, rgbValueBindRow);
904 else if (SQL_C_BINARY == fCType)
905 mylog
906 (" SQL_C_BINARY, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%.*s'\n",
907 len, cbValueMax, copy_len, rgbValueBindRow);
908 else
909 mylog
910 (" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n",
911 len, cbValueMax, rgbValueBindRow);
912 break;
914 #ifdef UNICODE_SUPPORT
915 if (SQL_C_WCHAR == fCType && !wconverted)
917 char *str = strdup(rgbValueBindRow);
918 SQLLEN ucount =
919 utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow,
920 cbValueMax / WCLEN);
921 if (cbValueMax < WCLEN * ucount)
922 result = COPY_RESULT_TRUNCATED;
923 len = ucount * WCLEN;
924 free(str);
926 #endif /* UNICODE_SUPPORT */
928 } else
931 * for SQL_C_CHAR, it's probably ok to leave currency symbols in.
932 * But to convert to numeric types, it is necessary to get rid of
933 * those.
935 if (field_type == PG_TYPE_MONEY)
937 if (convert_money
938 (neut_str, midtemp[mtemp_cnt], sizeof(midtemp[0])))
940 neut_str = midtemp[mtemp_cnt];
941 mtemp_cnt++;
942 } else
944 qlog("couldn't convert money type to %d\n", fCType);
945 return COPY_UNSUPPORTED_TYPE;
949 switch (fCType)
951 case SQL_C_DATE:
952 case SQL_C_TYPE_DATE: /* 91 */
953 len = 6;
955 DATE_STRUCT *ds;
957 if (bind_size > 0)
958 ds = (DATE_STRUCT *) rgbValueBindRow;
959 else
960 ds = (DATE_STRUCT *) rgbValue + bind_row;
961 ds->year = std_time.y;
962 ds->month = std_time.m;
963 ds->day = std_time.d;
965 break;
967 case SQL_C_TIME:
968 case SQL_C_TYPE_TIME: /* 92 */
969 len = 6;
971 TIME_STRUCT *ts;
973 if (bind_size > 0)
974 ts = (TIME_STRUCT *) rgbValueBindRow;
975 else
976 ts = (TIME_STRUCT *) rgbValue + bind_row;
977 ts->hour = std_time.hh;
978 ts->minute = std_time.mm;
979 ts->second = std_time.ss;
981 break;
983 case SQL_C_TIMESTAMP:
984 case SQL_C_TYPE_TIMESTAMP: /* 93 */
985 len = 16;
987 TIMESTAMP_STRUCT *ts;
989 if (bind_size > 0)
990 ts = (TIMESTAMP_STRUCT *) rgbValueBindRow;
991 else
992 ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row;
993 ts->year = std_time.y;
994 ts->month = std_time.m;
995 ts->day = std_time.d;
996 ts->hour = std_time.hh;
997 ts->minute = std_time.mm;
998 ts->second = std_time.ss;
999 ts->fraction = std_time.fr;
1001 break;
1003 case SQL_C_BIT:
1004 len = 1;
1005 if (bind_size > 0)
1006 *((UCHAR *) rgbValueBindRow) = atoi(neut_str);
1007 else
1008 *((UCHAR *) rgbValue + bind_row) = atoi(neut_str);
1011 * mylog("SQL_C_BIT: bind_row = %d val = %d, cb = %d,
1012 * rgb=%d\n", bind_row, atoi(neut_str), cbValueMax,
1013 * *((UCHAR *)rgbValue));
1015 break;
1017 case SQL_C_STINYINT:
1018 case SQL_C_TINYINT:
1019 len = 1;
1020 if (bind_size > 0)
1021 *((SCHAR *) rgbValueBindRow) = atoi(neut_str);
1022 else
1023 *((SCHAR *) rgbValue + bind_row) = atoi(neut_str);
1024 break;
1026 case SQL_C_UTINYINT:
1027 len = 1;
1028 if (bind_size > 0)
1029 *((UCHAR *) rgbValueBindRow) = atoi(neut_str);
1030 else
1031 *((UCHAR *) rgbValue + bind_row) = atoi(neut_str);
1032 break;
1034 case SQL_C_FLOAT:
1035 #ifdef HAVE_LOCALE_H
1036 saved_locale = strdup(setlocale(LC_ALL, NULL));
1037 setlocale(LC_ALL, "C");
1038 #endif /* HAVE_LOCALE_H */
1039 len = 4;
1040 if (bind_size > 0)
1041 *((SFLOAT *) rgbValueBindRow) =
1042 (float) get_double_value(neut_str);
1043 else
1044 *((SFLOAT *) rgbValue + bind_row) =
1045 (float) get_double_value(neut_str);
1046 #ifdef HAVE_LOCALE_H
1047 setlocale(LC_ALL, saved_locale);
1048 free(saved_locale);
1049 #endif /* HAVE_LOCALE_H */
1050 break;
1052 case SQL_C_DOUBLE:
1053 #ifdef HAVE_LOCALE_H
1054 saved_locale = strdup(setlocale(LC_ALL, NULL));
1055 setlocale(LC_ALL, "C");
1056 #endif /* HAVE_LOCALE_H */
1057 len = 8;
1058 if (bind_size > 0)
1059 *((SDOUBLE *) rgbValueBindRow) =
1060 get_double_value(neut_str);
1061 else
1062 *((SDOUBLE *) rgbValue + bind_row) =
1063 get_double_value(neut_str);
1064 #ifdef HAVE_LOCALE_H
1065 setlocale(LC_ALL, saved_locale);
1066 free(saved_locale);
1067 #endif /* HAVE_LOCALE_H */
1068 break;
1070 case SQL_C_NUMERIC:
1071 #ifdef HAVE_LOCALE_H
1072 /* strcpy(saved_locale, setlocale(LC_ALL, NULL));
1073 setlocale(LC_ALL, "C"); not needed currently */
1074 #endif /* HAVE_LOCALE_H */
1076 SQL_NUMERIC_STRUCT *ns;
1077 int i, nlen, bit, hval, tv, dig, sta, olen;
1078 char calv[SQL_MAX_NUMERIC_LEN * 3];
1079 const char *wv;
1080 BOOL dot_exist;
1082 len = sizeof(SQL_NUMERIC_STRUCT);
1083 if (bind_size > 0)
1084 ns = (SQL_NUMERIC_STRUCT *) rgbValueBindRow;
1085 else
1086 ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
1087 for (wv = neut_str; *wv && isspace(*wv); wv++)
1089 ns->sign = 1;
1090 if (*wv == '-')
1092 ns->sign = 0;
1093 wv++;
1094 } else if (*wv == '+')
1095 wv++;
1096 while (*wv == '0')
1097 wv++;
1098 ns->precision = 0;
1099 ns->scale = 0;
1100 for (nlen = 0, dot_exist = FALSE;; wv++)
1102 if (*wv == '.')
1104 if (dot_exist)
1105 break;
1106 dot_exist = TRUE;
1107 } else if (!isdigit(*wv))
1108 break;
1109 else
1111 if (dot_exist)
1112 ns->scale++;
1113 ns->precision++;
1114 calv[nlen++] = *wv;
1117 memset(ns->val, 0, sizeof(ns->val));
1118 for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
1120 for (dig = 0, i = sta; i < nlen; i++)
1122 tv = dig * 10 + calv[i] - '0';
1123 dig = tv % 2;
1124 calv[i] = tv / 2 + '0';
1125 if (i == sta && tv < 2)
1126 sta++;
1128 if (dig > 0)
1129 hval |= bit;
1130 bit <<= 1;
1131 if (bit >= (1L << 8))
1133 ns->val[olen++] = hval;
1134 hval = 0;
1135 bit = 1L;
1136 if (olen >= SQL_MAX_NUMERIC_LEN - 1)
1138 ns->scale = sta - ns->precision;
1139 break;
1143 if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
1144 ns->val[olen++] = hval;
1146 #ifdef HAVE_LOCALE_H
1147 /* setlocale(LC_ALL, saved_locale); */
1148 #endif /* HAVE_LOCALE_H */
1149 break;
1151 case SQL_C_SSHORT:
1152 case SQL_C_SHORT:
1153 len = 2;
1154 if (bind_size > 0)
1155 *((SQLSMALLINT *) rgbValueBindRow) = atoi(neut_str);
1156 else
1157 *((SQLSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
1158 break;
1160 case SQL_C_USHORT:
1161 len = 2;
1162 if (bind_size > 0)
1163 *((SQLUSMALLINT *) rgbValueBindRow) = atoi(neut_str);
1164 else
1165 *((SQLUSMALLINT *) rgbValue + bind_row) =
1166 atoi(neut_str);
1167 break;
1169 case SQL_C_SLONG:
1170 case SQL_C_LONG:
1171 len = 4;
1172 if (bind_size > 0)
1173 *((SQLINTEGER *) rgbValueBindRow) = atol(neut_str);
1174 else
1175 *((SQLINTEGER *) rgbValue + bind_row) = atol(neut_str);
1176 break;
1178 case SQL_C_ULONG:
1179 len = 4;
1180 if (bind_size > 0)
1181 *((SQLUINTEGER *) rgbValueBindRow) = ATOI32U(neut_str);
1182 else
1183 *((SQLUINTEGER *) rgbValue + bind_row) =
1184 ATOI32U(neut_str);
1185 break;
1187 case SQL_C_SBIGINT:
1188 len = 8;
1189 if (bind_size > 0)
1190 *((SQLBIGINT *) rgbValueBindRow) = ATOI64(neut_str);
1191 else
1192 *((SQLBIGINT *) rgbValue + bind_row) = ATOI64(neut_str);
1193 break;
1195 case SQL_C_UBIGINT:
1196 len = 8;
1197 if (bind_size > 0)
1198 *((SQLUBIGINT *) rgbValueBindRow) = ATOI64U(neut_str);
1199 else
1200 *((SQLUBIGINT *) rgbValue + bind_row) =
1201 ATOI64U(neut_str);
1202 break;
1204 case SQL_C_BINARY:
1205 if (PG_TYPE_UNKNOWN == field_type ||
1206 PG_TYPE_TEXT == field_type ||
1207 PG_TYPE_VARCHAR == field_type ||
1208 PG_TYPE_BPCHAR == field_type ||
1209 PG_TYPE_TEXTARRAY == field_type ||
1210 PG_TYPE_VARCHARARRAY == field_type ||
1211 PG_TYPE_BPCHARARRAY == field_type)
1213 ssize_t len = SQL_NULL_DATA;
1215 if (neut_str)
1216 len = strlen(neut_str);
1217 if (pcbValue)
1218 *pcbValueBindRow = len;
1219 if (len > 0 && cbValueMax > 0)
1221 memcpy(rgbValueBindRow, neut_str,
1222 len < cbValueMax ? len : cbValueMax);
1223 if (cbValueMax >= len + 1)
1224 rgbValueBindRow[len] = '\0';
1226 if (cbValueMax >= len)
1227 return COPY_OK;
1228 else
1229 return COPY_RESULT_TRUNCATED;
1231 /* The following is for SQL_C_VARBOOKMARK */
1232 else if (PG_TYPE_INT4 == field_type)
1234 UInt4 ival = ATOI32U(neut_str);
1236 inolog("SQL_C_VARBOOKMARK value=%d\n", ival);
1237 if (pcbValue)
1238 *pcbValueBindRow = sizeof(ival);
1239 if (cbValueMax >= sizeof(ival))
1241 memcpy(rgbValueBindRow, &ival, sizeof(ival));
1242 return COPY_OK;
1243 } else
1244 return COPY_RESULT_TRUNCATED;
1245 } else if (PG_TYPE_BYTEA != field_type)
1247 mylog("couldn't convert the type %d to SQL_C_BINARY\n",
1248 field_type);
1249 qlog("couldn't convert the type %d to SQL_C_BINARY\n",
1250 field_type);
1251 return COPY_UNSUPPORTED_TYPE;
1253 /* truncate if necessary */
1254 /* convert octal escapes to bytes */
1256 if (stmt->current_col < 0)
1258 pgdc = &(gdata->fdata);
1259 pgdc->data_left = -1;
1260 } else
1261 pgdc = &gdata->gdata[stmt->current_col];
1262 if (!pgdc->ttlbuf)
1263 pgdc->ttlbuflen = 0;
1264 if (pgdc->data_left < 0)
1266 if (cbValueMax <= 0)
1268 len = convert_from_pgbinary((const UCHAR *)neut_str, NULL, 0);
1269 result = COPY_RESULT_TRUNCATED;
1270 break;
1272 if (len =
1273 strlen(neut_str), len >= (int) pgdc->ttlbuflen)
1275 pgdc->ttlbuf = (char *)realloc(pgdc->ttlbuf, len + 1);
1276 pgdc->ttlbuflen = len + 1;
1278 len =
1279 convert_from_pgbinary((const UCHAR *)neut_str,
1280 (UCHAR *)pgdc->ttlbuf,
1281 pgdc->ttlbuflen);
1282 pgdc->ttlbufused = len;
1283 } else
1284 len = pgdc->ttlbufused;
1285 ptr = pgdc->ttlbuf;
1287 if (stmt->current_col >= 0)
1290 * Second (or more) call to SQLGetData so move the
1291 * pointer
1293 if (pgdc->data_left > 0)
1295 ptr += len - pgdc->data_left;
1296 len = pgdc->data_left;
1299 /* First call to SQLGetData so initialize data_left */
1300 else
1301 pgdc->data_left = len;
1305 if (cbValueMax > 0)
1307 copy_len = (len > cbValueMax) ? cbValueMax : len;
1309 /* Copy the data */
1310 memcpy(rgbValueBindRow, ptr, copy_len);
1312 /* Adjust data_left for next time */
1313 if (stmt->current_col >= 0)
1314 pgdc->data_left -= copy_len;
1318 * Finally, check for truncation so that proper status can
1319 * be returned
1321 if (len > cbValueMax)
1322 result = COPY_RESULT_TRUNCATED;
1323 else if (pgdc->ttlbuf)
1325 free(pgdc->ttlbuf);
1326 pgdc->ttlbuf = NULL;
1328 mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len,
1329 copy_len);
1330 break;
1332 default:
1333 qlog("conversion to the type %d isn't supported\n", fCType);
1334 return COPY_UNSUPPORTED_TYPE;
1338 /* store the length of what was copied, if there's a place for it */
1339 if (pcbValue)
1340 *pcbValueBindRow = len;
1342 if (result == COPY_OK && stmt->current_col >= 0)
1343 gdata->gdata[stmt->current_col].data_left = 0;
1344 return result;
1349 /*--------------------------------------------------------------------
1350 * Functions/Macros to get rid of query size limit.
1352 * I always used the follwoing macros to convert from
1353 * old_statement to new_statement. Please improve it
1354 * if you have a better way. Hiroshi 2001/05/22
1355 *--------------------------------------------------------------------
1358 #define FLGP_PREPARE_DUMMY_CURSOR 1L
1359 #define FLGP_CURSOR_CHECK_OK (1L << 1)
1360 #define FLGP_SELECT_INTO (1L << 2)
1361 #define FLGP_SELECT_FOR_UPDATE (1L << 3)
1362 #define FLGP_BUILDING_PREPARE_STATEMENT (1L << 4)
1363 #define FLGP_MULTIPLE_STATEMENT (1L << 5)
1364 typedef struct _QueryParse {
1365 const char *statement;
1366 int statement_type;
1367 size_t opos;
1368 Int4 from_pos; /* PG comm length restriction */
1369 Int4 where_pos; /* PG comm length restriction */
1370 ssize_t stmt_len;
1371 char in_literal, in_identifier, in_escape, in_dollar_quote;
1372 const char *dollar_tag;
1373 ssize_t taglen;
1374 char token_save[64];
1375 int token_len;
1376 BOOL prev_token_end;
1377 BOOL proc_no_param;
1378 size_t declare_pos;
1379 UInt4 flags;
1380 encoded_str encstr;
1381 } QueryParse;
1383 static ssize_t
1384 QP_initialize(QueryParse * q, const StatementClass * stmt)
1386 q->statement =
1387 stmt->execute_statement ? stmt->execute_statement : stmt->
1388 statement;
1389 q->statement_type = stmt->statement_type;
1390 q->opos = 0;
1391 q->from_pos = -1;
1392 q->where_pos = -1;
1393 q->stmt_len = (q->statement) ? strlen(q->statement) : -1;
1394 q->in_literal = q->in_identifier = q->in_escape =
1395 q->in_dollar_quote = FALSE;
1396 q->dollar_tag = NULL;
1397 q->taglen = -1;
1398 q->token_save[0] = '\0';
1399 q->token_len = 0;
1400 q->prev_token_end = TRUE;
1401 q->proc_no_param = TRUE;
1402 q->declare_pos = 0;
1403 q->flags = 0;
1404 make_encoded_str(&q->encstr, SC_get_conn(stmt), q->statement);
1406 return q->stmt_len;
1409 #define FLGB_PRE_EXECUTING 1L
1410 #define FLGB_BUILDING_PREPARE_STATEMENT (1L << 1)
1411 #define FLGB_BUILDING_BIND_REQUEST (1L << 2)
1412 #define FLGB_EXECUTE_PREPARED (1L << 3)
1414 #define FLGB_INACCURATE_RESULT (1L << 4)
1415 #define FLGB_CREATE_KEYSET (1L << 5)
1416 #define FLGB_KEYSET_DRIVEN (1L << 6)
1417 #define FLGB_CONVERT_LF (1L << 7)
1418 #define FLGB_DISCARD_OUTPUT (1L << 8)
1419 #define FLGB_BINARY_AS_POSSIBLE (1L << 9)
1420 #define FLGB_LITERAL_EXTENSION (1L << 10)
1421 typedef struct _QueryBuild {
1422 char *query_statement;
1423 size_t str_size_limit;
1424 size_t str_alsize;
1425 size_t npos;
1426 SQLLEN current_row;
1427 Int2 param_number;
1428 Int2 dollar_number;
1429 Int2 num_io_params;
1430 Int2 num_output_params;
1431 Int2 num_discard_params;
1432 Int2 proc_return;
1433 APDFields *apdopts;
1434 IPDFields *ipdopts;
1435 size_t load_stmt_len;
1436 UInt4 flags;
1437 int ccsc;
1438 int errornumber;
1439 const char *errormsg;
1441 ConnectionClass *conn; /* mainly needed for LO handling */
1442 StatementClass *stmt; /* needed to set error info in ENLARGE_.. */
1443 } QueryBuild;
1445 #define INIT_MIN_ALLOC 4096
1446 static ssize_t
1447 QB_initialize(QueryBuild * qb, size_t size, StatementClass * stmt,
1448 ConnectionClass * conn)
1450 size_t newsize = 0;
1452 qb->flags = 0;
1453 qb->load_stmt_len = 0;
1454 qb->stmt = stmt;
1455 qb->apdopts = NULL;
1456 qb->ipdopts = NULL;
1457 qb->proc_return = 0;
1458 qb->num_io_params = 0;
1459 qb->num_output_params = 0;
1460 qb->num_discard_params = 0;
1461 if (conn)
1462 qb->conn = conn;
1463 else if (stmt)
1465 Int2 dummy;
1467 qb->apdopts = SC_get_APDF(stmt);
1468 qb->ipdopts = SC_get_IPDF(stmt);
1469 qb->conn = SC_get_conn(stmt);
1470 if (stmt->pre_executing)
1471 qb->flags |= FLGB_PRE_EXECUTING;
1472 if (stmt->discard_output_params)
1473 qb->flags |= FLGB_DISCARD_OUTPUT;
1474 qb->num_io_params =
1475 CountParameters(stmt, NULL, &dummy, &qb->num_output_params);
1476 qb->proc_return = stmt->proc_return;
1477 if (0 != (qb->flags & FLGB_DISCARD_OUTPUT))
1478 qb->num_discard_params = qb->num_output_params;
1479 if (qb->num_discard_params < qb->proc_return)
1480 qb->num_discard_params = qb->proc_return;
1481 } else
1483 qb->conn = NULL;
1484 return -1;
1486 if (qb->conn->connInfo.lf_conversion)
1487 qb->flags |= FLGB_CONVERT_LF;
1488 qb->ccsc = qb->conn->ccsc;
1489 if (CC_get_escape(qb->conn) && PG_VERSION_GE(qb->conn, 8.1))
1490 qb->flags |= FLGB_LITERAL_EXTENSION;
1492 if (stmt)
1493 qb->str_size_limit = stmt->stmt_size_limit;
1494 else
1495 qb->str_size_limit = -1;
1496 if (qb->str_size_limit > 0)
1498 if (size > qb->str_size_limit)
1499 return -1;
1500 newsize = qb->str_size_limit;
1502 else
1504 newsize = INIT_MIN_ALLOC;
1505 while (newsize <= size)
1506 newsize *= 2;
1508 if ((qb->query_statement = (char *)malloc(newsize)) == NULL)
1510 qb->str_alsize = 0;
1511 return -1;
1513 qb->query_statement[0] = '\0';
1514 qb->str_alsize = newsize;
1515 qb->npos = 0;
1516 qb->current_row =
1517 stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
1518 qb->param_number = -1;
1519 qb->dollar_number = 0;
1520 qb->errornumber = 0;
1521 qb->errormsg = NULL;
1523 return newsize;
1526 static int
1527 QB_initialize_copy(QueryBuild * qb_to, const QueryBuild * qb_from,
1528 UInt4 size)
1530 memcpy(qb_to, qb_from, sizeof(QueryBuild));
1532 if (qb_to->str_size_limit > 0)
1534 if (size > qb_to->str_size_limit)
1535 return -1;
1537 if ((qb_to->query_statement = (char *)malloc(size)) == NULL)
1539 qb_to->str_alsize = 0;
1540 return -1;
1542 qb_to->query_statement[0] = '\0';
1543 qb_to->str_alsize = size;
1544 qb_to->npos = 0;
1546 return size;
1549 static void
1550 QB_replace_SC_error(StatementClass * stmt, const QueryBuild * qb,
1551 const char *func)
1553 int number;
1555 if (0 == qb->errornumber)
1556 return;
1557 if ((number = SC_get_errornumber(stmt)) > 0)
1558 return;
1559 if (number < 0 && qb->errornumber < 0)
1560 return;
1561 SC_set_error(stmt, qb->errornumber, qb->errormsg, func);
1564 static void QB_Destructor(QueryBuild * qb)
1566 if (qb->query_statement)
1568 free(qb->query_statement);
1569 qb->query_statement = NULL;
1570 qb->str_alsize = 0;
1575 * New macros (Aceto)
1576 *--------------------
1579 #define F_OldChar(qp) \
1580 qp->statement[qp->opos]
1582 #define F_OldPtr(qp) \
1583 (qp->statement + qp->opos)
1585 #define F_OldNext(qp) \
1586 (++qp->opos)
1588 #define F_OldPrior(qp) \
1589 (--qp->opos)
1591 #define F_OldPos(qp) \
1592 qp->opos
1594 #define F_ExtractOldTo(qp, buf, ch, maxsize) \
1595 do { \
1596 size_t c = 0; \
1597 while (qp->statement[qp->opos] != '\0' && qp->statement[qp->opos] != ch) \
1599 if (c >= maxsize) \
1600 break; \
1601 buf[c++] = qp->statement[qp->opos++]; \
1603 if (qp->statement[qp->opos] == '\0') \
1604 return SQL_ERROR; \
1605 buf[c] = '\0'; \
1606 } while (0)
1608 #define F_NewChar(qb) \
1609 qb->query_statement[qb->npos]
1611 #define F_NewPtr(qb) \
1612 (qb->query_statement + qb->npos)
1614 #define F_NewNext(qb) \
1615 (++qb->npos)
1617 #define F_NewPos(qb) \
1618 (qb->npos)
1621 static size_t
1622 convert_to_pgbinary(const UCHAR * in, char *out, size_t len,
1623 QueryBuild * qb);
1625 static ssize_t enlarge_query_statement(QueryBuild * qb, size_t newsize)
1627 size_t newalsize = INIT_MIN_ALLOC;
1628 CSTR func = "enlarge_statement";
1630 if (qb->str_size_limit > 0 && qb->str_size_limit < (int) newsize)
1632 free(qb->query_statement);
1633 qb->query_statement = NULL;
1634 qb->str_alsize = 0;
1635 if (qb->stmt)
1638 SC_set_error(qb->stmt, STMT_EXEC_ERROR,
1639 "Query buffer overflow in copy_statement_with_parameters",
1640 func);
1641 } else
1643 qb->errormsg =
1644 "Query buffer overflow in copy_statement_with_parameters";
1645 qb->errornumber = STMT_EXEC_ERROR;
1647 return -1;
1649 while (newalsize <= newsize)
1650 newalsize *= 2;
1651 if (!
1652 (qb->query_statement = (char *)realloc(qb->query_statement, newalsize)))
1654 qb->str_alsize = 0;
1655 if (qb->stmt)
1657 SC_set_error(qb->stmt, STMT_EXEC_ERROR,
1658 "Query buffer allocate error in copy_statement_with_parameters",
1659 func);
1660 } else
1662 qb->errormsg =
1663 "Query buffer allocate error in copy_statement_with_parameters";
1664 qb->errornumber = STMT_EXEC_ERROR;
1666 return 0;
1668 qb->str_alsize = newalsize;
1669 return newalsize;
1672 /*----------
1673 * Enlarge stmt_with_params if necessary.
1674 *----------
1676 #define ENLARGE_NEWSTATEMENT(qb, newpos) \
1677 if (newpos >= qb->str_alsize) \
1679 if (enlarge_query_statement(qb, newpos) <= 0) \
1680 return SQL_ERROR; \
1683 /*----------
1684 * Terminate the stmt_with_params string with NULL.
1685 *----------
1687 #define CVT_TERMINATE(qb) \
1688 do { \
1689 qb->query_statement[qb->npos] = '\0'; \
1690 } while (0)
1692 /*----------
1693 * Append a data.
1694 *----------
1696 #define CVT_APPEND_DATA(qb, s, len) \
1697 do { \
1698 size_t newpos = qb->npos + len; \
1699 ENLARGE_NEWSTATEMENT(qb, newpos) \
1700 memcpy(&qb->query_statement[qb->npos], s, len); \
1701 qb->npos = newpos; \
1702 qb->query_statement[newpos] = '\0'; \
1703 } while (0)
1705 /*----------
1706 * Append a string.
1707 *----------
1709 #define CVT_APPEND_STR(qb, s) \
1710 do { \
1711 size_t len = strlen(s); \
1712 CVT_APPEND_DATA(qb, s, len); \
1713 } while (0)
1715 /*----------
1716 * Append a char.
1717 *----------
1719 #define CVT_APPEND_CHAR(qb, c) \
1720 do { \
1721 ENLARGE_NEWSTATEMENT(qb, qb->npos + 1); \
1722 qb->query_statement[qb->npos++] = c; \
1723 } while (0)
1725 /*----------
1726 * Append a binary data.
1727 * Newly reqeuired size may be overestimated currently.
1728 *----------
1730 #define CVT_APPEND_BINARY(qb, buf, used) \
1731 do { \
1732 size_t newlimit = qb->npos + 5 * used; \
1733 ENLARGE_NEWSTATEMENT(qb, newlimit); \
1734 qb->npos += convert_to_pgbinary((const UCHAR *)buf, &qb->query_statement[qb->npos], used, qb); \
1735 } while (0)
1737 /*----------
1739 *----------
1741 #define CVT_SPECIAL_CHARS(qb, buf, used) \
1742 do { \
1743 size_t cnvlen = convert_special_chars(buf, NULL, used, qb->flags, qb->ccsc, CC_get_escape(qb->conn)); \
1744 size_t newlimit = qb->npos + cnvlen; \
1746 ENLARGE_NEWSTATEMENT(qb, newlimit); \
1747 convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->flags, qb->ccsc, CC_get_escape(qb->conn)); \
1748 qb->npos += cnvlen; \
1749 } while (0)
1751 #ifdef NOT_USED
1752 #define CVT_TEXT_FIELD(qb, buf, used) \
1753 do { \
1754 char escape_ch = CC_get_escape(qb->conn); \
1755 int flags = ((0 != qb->flags & FLGB_CONVERT_LF) ? CONVERT_CRLF_TO_LF : 0) | ((0 != qb->flags & FLGB_BUILDING_BIND_REQUEST) ? 0 : DOUBLE_LITERAL_QUOTE | (escape_ch ? DOUBLE_LITERAL_IN_ESCAPE : 0)); \
1756 int cnvlen = (flags & (DOUBLE_LITERAL_QUOTE | DOUBLE_LITERAL_IN_ESCAPE)) != 0 ? used * 2 : used; \
1757 if (used > 0 && qb->npos + cnvlen >= qb->str_alsize) \
1759 cnvlen = convert_text_field(buf, NULL, used, qb->ccsc, escape_ch, &flags); \
1760 size_t newlimit = qb->npos + cnvlen; \
1762 ENLARGE_NEWSTATEMENT(qb, newlimit); \
1764 cnvlen = convert_text_field(buf, &qb->query_statement[qb->npos], used, qb->ccsc, escape_ch, &flags); \
1765 qb->npos += cnvlen; \
1766 } while (0)
1767 #endif /* NOT_USED */
1769 /*----------
1770 * Check if the statement is
1771 * SELECT ... INTO table FROM .....
1772 * This isn't really a strict check but ...
1773 *----------
1775 static BOOL into_table_from(const char *stmt)
1777 if (strnicmp(stmt, "into", 4))
1778 return FALSE;
1779 stmt += 4;
1780 if (!isspace((UCHAR) * stmt))
1781 return FALSE;
1782 while (isspace((UCHAR) * (++stmt)));
1783 switch (*stmt)
1785 case '\0':
1786 case ',':
1787 case LITERAL_QUOTE:
1788 return FALSE;
1789 case IDENTIFIER_QUOTE: /* double quoted table name ? */
1793 while (*(++stmt) != IDENTIFIER_QUOTE && *stmt);
1794 while (*stmt && *(++stmt) == IDENTIFIER_QUOTE);
1795 while (*stmt && !isspace((UCHAR) * stmt)
1796 && *stmt != IDENTIFIER_QUOTE)
1797 stmt++;
1799 while (*stmt == IDENTIFIER_QUOTE);
1800 break;
1801 default:
1802 while (!isspace((UCHAR) * (++stmt)));
1803 break;
1805 if (!*stmt)
1806 return FALSE;
1807 while (isspace((UCHAR) * (++stmt)));
1808 if (strnicmp(stmt, "from", 4))
1809 return FALSE;
1810 return isspace((UCHAR) stmt[4]);
1813 /*----------
1814 * Check if the statement is
1815 * SELECT ... FOR UPDATE .....
1816 * This isn't really a strict check but ...
1817 *----------
1819 static BOOL table_for_update(const char *stmt, int *endpos)
1821 const char *wstmt = stmt;
1823 while (isspace((UCHAR) * (++wstmt)));
1824 if (!*wstmt)
1825 return FALSE;
1826 if (strnicmp(wstmt, "update", 6))
1827 return FALSE;
1828 wstmt += 6;
1829 *endpos = wstmt - stmt;
1830 return !wstmt[0] || isspace((UCHAR) wstmt[0]);
1833 /*----------
1834 * Check if the statement has OUTER JOIN
1835 * This isn't really a strict check but ...
1836 *----------
1838 static BOOL
1839 check_join(StatementClass * stmt, const char *curptr, size_t curpos)
1841 const char *wstmt;
1842 ssize_t stapos, endpos, tokenwd;
1843 const int backstep = 4;
1844 BOOL outerj = TRUE;
1846 for (endpos = curpos, wstmt = curptr;
1847 endpos >= 0 && isspace((UCHAR) * wstmt); endpos--, wstmt--)
1849 if (endpos < 0)
1850 return FALSE;
1851 for (endpos -= backstep, wstmt -= backstep;
1852 endpos >= 0 && isspace((UCHAR) * wstmt); endpos--, wstmt--)
1854 if (endpos < 0)
1855 return FALSE;
1856 for (stapos = endpos; stapos >= 0 && !isspace((UCHAR) * wstmt);
1857 stapos--, wstmt--)
1859 if (stapos < 0)
1860 return FALSE;
1861 wstmt++;
1862 switch (tokenwd = endpos - stapos)
1864 case 4:
1865 if (strnicmp(wstmt, "FULL", tokenwd) == 0 ||
1866 strnicmp(wstmt, "LEFT", tokenwd) == 0)
1867 break;
1868 return FALSE;
1869 case 5:
1870 if (strnicmp(wstmt, "OUTER", tokenwd) == 0 ||
1871 strnicmp(wstmt, "RIGHT", tokenwd) == 0)
1872 break;
1873 if (strnicmp(wstmt, "INNER", tokenwd) == 0 ||
1874 strnicmp(wstmt, "CROSS", tokenwd) == 0)
1876 outerj = FALSE;
1877 break;
1879 return FALSE;
1880 default:
1881 return FALSE;
1883 if (stmt)
1885 if (outerj)
1886 SC_set_outer_join(stmt);
1887 else
1888 SC_set_inner_join(stmt);
1890 return TRUE;
1893 /*----------
1894 * Check if the statement is
1895 * INSERT INTO ... () VALUES ()
1896 * This isn't really a strict check but ...
1897 *----------
1899 static BOOL insert_without_target(const char *stmt, int *endpos)
1901 const char *wstmt = stmt;
1903 while (isspace((UCHAR) * (++wstmt)));
1904 if (!*wstmt)
1905 return FALSE;
1906 if (strnicmp(wstmt, "VALUES", 6))
1907 return FALSE;
1908 wstmt += 6;
1909 if (!wstmt[0] || !isspace((UCHAR) wstmt[0]))
1910 return FALSE;
1911 while (isspace((UCHAR) * (++wstmt)));
1912 if (*wstmt != '(' || *(++wstmt) != ')')
1913 return FALSE;
1914 wstmt++;
1915 *endpos = wstmt - stmt;
1916 return !wstmt[0] || isspace((UCHAR) wstmt[0]) || ';' == wstmt[0];
1919 #define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
1921 static void remove_declare_cursor(QueryBuild * qb, QueryParse * qp)
1923 memmove(qb->query_statement, qb->query_statement + qp->declare_pos,
1924 qb->npos - qp->declare_pos);
1925 qb->npos -= qp->declare_pos;
1926 qp->declare_pos = 0;
1929 Int4 findTag(const char *tag, char dollar_quote, int ccsc)
1931 Int4 taglen = 0;
1932 encoded_str encstr;
1933 char tchar;
1934 const char *sptr;
1936 encoded_str_constr(&encstr, ccsc, tag + 1);
1937 for (sptr = tag + 1; *sptr; sptr++)
1939 tchar = encoded_nextchar(&encstr);
1940 if (ENCODE_STATUS(encstr) != 0)
1941 continue;
1942 if (dollar_quote == tchar)
1944 taglen = sptr - tag + 1;
1945 break;
1947 if (isspace(tchar))
1948 break;
1950 return taglen;
1953 static int inner_process_tokens(QueryParse * qp, QueryBuild * qb)
1955 CSTR func = "inner_process_tokens";
1956 BOOL lf_conv = ((qb->flags & FLGB_CONVERT_LF) != 0);
1957 const char *bestitem = NULL;
1959 RETCODE retval;
1960 char oldchar;
1961 StatementClass *stmt = qb->stmt;
1962 char literal_quote = LITERAL_QUOTE, dollar_quote =
1963 DOLLAR_QUOTE, escape_in_literal = '\0';
1965 if (stmt && stmt->ntab > 0)
1966 bestitem = GET_NAME(stmt->ti[0]->bestitem);
1967 if (qp->from_pos == (Int4) qp->opos)
1969 CVT_APPEND_STR(qb, ", \"ctid");
1970 if (bestitem)
1972 CVT_APPEND_STR(qb, "\", \"");
1973 CVT_APPEND_STR(qb, bestitem);
1975 CVT_APPEND_STR(qb, "\" ");
1976 } else if (qp->where_pos == (Int4) qp->opos)
1978 qb->load_stmt_len = qb->npos;
1979 if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
1981 CVT_APPEND_STR(qb, "where ctid = '(0,0)';select \"ctid");
1982 if (bestitem)
1984 CVT_APPEND_STR(qb, "\", \"");
1985 CVT_APPEND_STR(qb, bestitem);
1987 CVT_APPEND_STR(qb, "\" from ");
1988 CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5,
1989 qp->where_pos - qp->from_pos - 5);
1992 oldchar = encoded_byte_check(&qp->encstr, qp->opos);
1993 if (ENCODE_STATUS(qp->encstr) != 0)
1995 CVT_APPEND_CHAR(qb, oldchar);
1996 return SQL_SUCCESS;
2000 * From here we are guaranteed to handle a 1-byte character.
2002 if (qp->in_escape) /* escape check */
2004 qp->in_escape = FALSE;
2005 CVT_APPEND_CHAR(qb, oldchar);
2006 return SQL_SUCCESS;
2007 } else if (qp->in_dollar_quote) /* dollar quote check */
2009 if (oldchar == dollar_quote)
2011 if (strncmp(F_OldPtr(qp), qp->dollar_tag, qp->taglen) == 0)
2013 CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
2014 qp->opos += (qp->taglen - 1);
2015 qp->in_dollar_quote = FALSE;
2016 qp->in_literal = FALSE;
2017 qp->dollar_tag = NULL;
2018 qp->taglen = -1;
2019 return SQL_SUCCESS;
2022 CVT_APPEND_CHAR(qb, oldchar);
2023 return SQL_SUCCESS;
2024 } else if (qp->in_literal) /* quote check */
2026 if (oldchar == escape_in_literal)
2027 qp->in_escape = TRUE;
2028 else if (oldchar == literal_quote)
2029 qp->in_literal = FALSE;
2030 CVT_APPEND_CHAR(qb, oldchar);
2031 return SQL_SUCCESS;
2032 } else if (qp->in_identifier) /* double quote check */
2034 if (oldchar == IDENTIFIER_QUOTE)
2035 qp->in_identifier = FALSE;
2036 CVT_APPEND_CHAR(qb, oldchar);
2037 return SQL_SUCCESS;
2041 * From here we are guranteed to be in neither a literal_escape,
2042 * a literal_quote nor an idetifier_quote.
2044 /* Squeeze carriage-return/linefeed pairs to linefeed only */
2045 else if (lf_conv &&
2046 PG_CARRIAGE_RETURN == oldchar &&
2047 qp->opos + 1 < qp->stmt_len &&
2048 PG_LINEFEED == qp->statement[qp->opos + 1])
2049 return SQL_SUCCESS;
2052 * Handle literals (date, time, timestamp) and ODBC scalar
2053 * functions
2055 else if (oldchar == '{')
2057 qb->errornumber = STMT_EXEC_ERROR;
2058 qb->errormsg = "ODBC functions not yet supported";
2059 return SQL_ERROR;
2061 /* End of an escape sequence */
2062 else if (oldchar == '}')
2064 if (qp->statement_type == STMT_TYPE_PROCCALL)
2066 if (qp->proc_no_param)
2067 CVT_APPEND_STR(qb, "()");
2068 } else if (!isspace(F_OldPtr(qp)[1]))
2069 CVT_APPEND_CHAR(qb, ' ');
2070 return SQL_SUCCESS;
2071 } else if (oldchar == '@' &&
2072 strnicmp(F_OldPtr(qp), "@@identity", 10) == 0)
2074 ConnectionClass *conn = SC_get_conn(stmt);
2075 BOOL converted = FALSE;
2076 COL_INFO *coli;
2078 if (PG_VERSION_GE(conn, 8.1))
2080 CVT_APPEND_STR(qb, "lastval()");
2081 converted = TRUE;
2082 } else if (NAME_IS_VALID(conn->tableIns))
2084 TABLE_INFO ti, *pti = &ti;
2086 memset(&ti, 0, sizeof(ti));
2087 NAME_TO_NAME(ti.schema_name, conn->schemaIns);
2088 NAME_TO_NAME(ti.table_name, conn->tableIns);
2089 getCOLIfromTI(func, conn, NULL, 0, &pti);
2090 coli = ti.col_info;
2091 NULL_THE_NAME(ti.schema_name);
2092 NULL_THE_NAME(ti.table_name);
2093 if (NULL != coli)
2095 int i, num_fields = QR_NumResultCols(coli->result);
2097 for (i = 0; i < num_fields; i++)
2099 if (*
2100 ((char *)
2101 QR_get_value_backend_text(coli->result, i,
2102 COLUMNS_AUTO_INCREMENT))
2103 == '1')
2105 CVT_APPEND_STR(qb, "curr");
2106 CVT_APPEND_STR(qb,
2107 (char *)
2108 QR_get_value_backend_text(coli->
2109 result,
2111 COLUMNS_COLUMN_DEF)
2112 + 4);
2113 converted = TRUE;
2114 break;
2119 if (!converted)
2120 CVT_APPEND_STR(qb, "NULL");
2121 qp->opos += 10;
2122 return SQL_SUCCESS;
2126 * Can you have parameter markers inside of quotes? I dont think
2127 * so. All the queries I've seen expect the driver to put quotes
2128 * if needed.
2130 else if (oldchar != '?')
2132 if (oldchar == dollar_quote)
2134 qp->taglen =
2135 findTag(F_OldPtr(qp), dollar_quote, qp->encstr.ccsc);
2136 if (qp->taglen > 0)
2138 qp->in_literal = TRUE;
2139 qp->in_dollar_quote = TRUE;
2140 qp->dollar_tag = F_OldPtr(qp);
2141 CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
2142 qp->opos += (qp->taglen - 1);
2143 return SQL_SUCCESS;
2145 } else if (oldchar == literal_quote)
2147 if (!qp->in_identifier)
2149 qp->in_literal = TRUE;
2150 escape_in_literal = CC_get_escape(qb->conn);
2151 if (!escape_in_literal)
2153 if (LITERAL_EXT == F_OldPtr(qp)[-1])
2154 escape_in_literal = ESCAPE_IN_LITERAL;
2157 } else if (oldchar == IDENTIFIER_QUOTE)
2159 if (!qp->in_literal)
2160 qp->in_identifier = TRUE;
2161 } else if (oldchar == ';')
2164 * can't parse multiple statement using protocol V3.
2165 * reset the dollar number here in case it is divided
2166 * to parse.
2168 qb->dollar_number = 0;
2169 if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK))
2171 const char *vp = &(qp->statement[qp->opos + 1]);
2173 while (*vp && isspace(*vp))
2174 vp++;
2175 if (*vp) /* multiple statement */
2177 qp->flags |= FLGP_MULTIPLE_STATEMENT;
2178 qp->flags &= ~FLGP_CURSOR_CHECK_OK;
2179 qb->flags &= ~FLGB_KEYSET_DRIVEN;
2180 remove_declare_cursor(qb, qp);
2183 } else
2185 if (isspace((UCHAR) oldchar))
2187 if (!qp->prev_token_end)
2189 qp->prev_token_end = TRUE;
2190 qp->token_save[qp->token_len] = '\0';
2191 if (qp->token_len == 4)
2193 if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK) &&
2194 into_table_from(&qp->
2195 statement[qp->opos -
2196 qp->token_len]))
2198 qp->flags |= FLGP_SELECT_INTO;
2199 qp->flags &= ~FLGP_CURSOR_CHECK_OK;
2200 qb->flags &= ~FLGB_KEYSET_DRIVEN;
2201 qp->statement_type = STMT_TYPE_CREATE;
2202 remove_declare_cursor(qb, qp);
2203 } else if (stricmp(qp->token_save, "join") == 0)
2205 if (stmt)
2206 check_join(stmt, F_OldPtr(qp),
2207 F_OldPos(qp));
2209 } else if (qp->token_len == 3)
2211 int endpos;
2213 if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK) &&
2214 strnicmp(qp->token_save, "for", 3) == 0 &&
2215 table_for_update(F_OldPtr(qp), &endpos))
2217 qp->flags |= FLGP_SELECT_FOR_UPDATE;
2218 qp->flags &= ~FLGP_CURSOR_CHECK_OK;
2219 if (qp->flags & FLGP_PREPARE_DUMMY_CURSOR)
2221 qb->npos -= 4;
2222 qp->opos += endpos;
2223 } else
2225 remove_declare_cursor(qb, qp);
2228 } else if (qp->token_len == 2)
2230 int endpos;
2232 if (STMT_TYPE_INSERT == qp->statement_type &&
2233 strnicmp(qp->token_save, "()", 2) == 0 &&
2234 insert_without_target(F_OldPtr(qp),
2235 &endpos))
2237 qb->npos -= 2;
2238 CVT_APPEND_STR(qb, "DEFAULT VALUES");
2239 qp->opos += endpos;
2240 return SQL_SUCCESS;
2244 } else if (qp->prev_token_end)
2246 qp->prev_token_end = FALSE;
2247 qp->token_save[0] = oldchar;
2248 qp->token_len = 1;
2249 } else if (qp->token_len + 1 < sizeof(qp->token_save))
2250 qp->token_save[qp->token_len++] = oldchar;
2252 CVT_APPEND_CHAR(qb, oldchar);
2253 return SQL_SUCCESS;
2257 * Its a '?' parameter alright
2259 if (0 == qb->errornumber)
2261 qb->errornumber = STMT_EXEC_ERROR;
2262 qb->errormsg = "SQL bound parameters not yet supported";
2264 mylog("%s convert_escape error\n", func);
2265 return SQL_ERROR;
2268 static BOOL
2269 ResolveNumericParam(const SQL_NUMERIC_STRUCT * ns, char *chrform)
2271 static const int prec[] =
2272 { 1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37,
2275 Int4 i, j, k, ival, vlen, len, newlen;
2276 UCHAR calv[40];
2277 const UCHAR *val = (const UCHAR *) ns->val;
2278 BOOL next_figure;
2280 inolog("C_NUMERIC [prec=%d scale=%d]", ns->precision, ns->scale);
2281 if (0 == ns->precision)
2283 strcpy(chrform, "0");
2284 return TRUE;
2285 } else if (ns->precision < prec[sizeof(Int4)])
2287 for (i = 0, ival = 0;
2288 i < sizeof(Int4) && prec[i] <= ns->precision; i++)
2290 inolog("(%d)", val[i]);
2291 ival += (val[i] << (8 * i)); /* ns->val is little endian */
2293 inolog(" ival=%d,%d", ival,
2294 (val[3] << 24) | (val[2] << 16) | (val[1] << 8) |
2295 val[0]);
2296 if (0 == ns->scale)
2298 if (0 == ns->sign)
2299 ival *= -1;
2300 sprintf(chrform, "%d", ival);
2301 } else if (ns->scale > 0)
2303 Int4 i, div, o1val, o2val;
2305 for (i = 0, div = 1; i < ns->scale; i++)
2306 div *= 10;
2307 o1val = ival / div;
2308 o2val = ival % div;
2309 if (0 == ns->sign)
2310 o1val *= -1;
2311 sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val);
2313 inolog(" convval=%s\n", chrform);
2314 return TRUE;
2317 for (i = 0; i < SQL_MAX_NUMERIC_LEN && prec[i] <= ns->precision;
2318 i++)
2320 vlen = i;
2321 len = 0;
2322 memset(calv, 0, sizeof(calv));
2323 inolog(" len1=%d", vlen);
2324 for (i = vlen - 1; i >= 0; i--)
2326 for (j = len - 1; j >= 0; j--)
2328 if (!calv[j])
2329 continue;
2330 ival = (((Int4) calv[j]) << 8);
2331 calv[j] = (ival % 10);
2332 ival /= 10;
2333 calv[j + 1] += (ival % 10);
2334 ival /= 10;
2335 calv[j + 2] += (ival % 10);
2336 ival /= 10;
2337 calv[j + 3] += ival;
2338 for (k = j;; k++)
2340 next_figure = FALSE;
2341 if (calv[k] > 0)
2343 if (k >= len)
2344 len = k + 1;
2345 while (calv[k] > 9)
2347 calv[k + 1]++;
2348 calv[k] -= 10;
2349 next_figure = TRUE;
2352 if (k >= j + 3 && !next_figure)
2353 break;
2356 ival = val[i];
2357 if (!ival)
2358 continue;
2359 calv[0] += (ival % 10);
2360 ival /= 10;
2361 calv[1] += (ival % 10);
2362 ival /= 10;
2363 calv[2] += ival;
2364 for (j = 0;; j++)
2366 next_figure = FALSE;
2367 if (calv[j] > 0)
2369 if (j >= len)
2370 len = j + 1;
2371 while (calv[j] > 9)
2373 calv[j + 1]++;
2374 calv[j] -= 10;
2375 next_figure = TRUE;
2378 if (j >= 2 && !next_figure)
2379 break;
2382 inolog(" len2=%d", len);
2383 newlen = 0;
2384 if (0 == ns->sign)
2385 chrform[newlen++] = '-';
2386 if (i = len - 1, i < ns->scale)
2387 i = ns->scale;
2388 for (; i >= ns->scale; i--)
2389 chrform[newlen++] = calv[i] + '0';
2390 if (ns->scale > 0)
2392 chrform[newlen++] = '.';
2393 for (; i >= 0; i--)
2394 chrform[newlen++] = calv[i] + '0';
2396 if (0 == len)
2397 chrform[newlen++] = '0';
2398 chrform[newlen] = '\0';
2399 inolog(" convval(2) len=%d %s\n", newlen, chrform);
2400 return TRUE;
2404 BOOL convert_money(const char *s, char *sout, size_t soutmax)
2406 size_t i = 0, out = 0;
2408 for (i = 0; s[i]; i++)
2410 if (s[i] == '$' || s[i] == ',' || s[i] == ')')
2411 ; /* skip these characters */
2412 else
2414 if (out + 1 >= soutmax)
2415 return FALSE; /* sout is too short */
2416 if (s[i] == '(')
2417 sout[out++] = '-';
2418 else
2419 sout[out++] = s[i];
2422 sout[out] = '\0';
2423 return TRUE;
2428 * This function parses a character string for date/time info and fills in SIMPLE_TIME
2429 * It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
2431 char parse_datetime(const char *buf, SIMPLE_TIME * st)
2433 int y, m, d, hh, mm, ss;
2434 int nf;
2436 y = m = d = hh = mm = ss = 0;
2437 st->fr = 0;
2438 st->infinity = 0;
2440 /* escape sequence ? */
2441 if (buf[0] == '{')
2443 while (*(++buf) && *buf != LITERAL_QUOTE);
2444 if (!(*buf))
2445 return FALSE;
2446 buf++;
2448 if (buf[4] == '-') /* year first */
2449 nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh,
2450 &mm, &ss);
2451 else
2452 nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh,
2453 &mm, &ss);
2455 if (nf == 5 || nf == 6)
2457 st->y = y;
2458 st->m = m;
2459 st->d = d;
2460 st->hh = hh;
2461 st->mm = mm;
2462 st->ss = ss;
2464 return TRUE;
2467 if (buf[4] == '-') /* year first */
2468 nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
2469 else
2470 nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);
2472 if (nf == 3)
2474 st->y = y;
2475 st->m = m;
2476 st->d = d;
2478 return TRUE;
2481 nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
2482 if (nf == 2 || nf == 3)
2484 st->hh = hh;
2485 st->mm = mm;
2486 st->ss = ss;
2488 return TRUE;
2491 return FALSE;
2495 /* Change linefeed to carriage-return/linefeed */
2496 size_t
2497 convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf,
2498 BOOL * changed)
2500 size_t i = 0, out = 0;
2502 if (max == 0)
2503 max = 0xffffffff;
2504 *changed = FALSE;
2505 for (i = 0; si[i] && out < max - 1; i++)
2507 if (convlf && si[i] == '\n')
2509 /* Only add the carriage-return if needed */
2510 if (i > 0 && PG_CARRIAGE_RETURN == si[i - 1])
2512 if (dst)
2513 dst[out++] = si[i];
2514 else
2515 out++;
2516 continue;
2518 *changed = TRUE;
2520 if (dst)
2522 dst[out++] = PG_CARRIAGE_RETURN;
2523 dst[out++] = '\n';
2524 } else
2525 out += 2;
2526 } else
2528 if (dst)
2529 dst[out++] = si[i];
2530 else
2531 out++;
2534 if (dst)
2535 dst[out] = '\0';
2536 return out;
2541 * Change carriage-return/linefeed to just linefeed
2542 * Plus, escape any special characters.
2544 size_t
2545 convert_special_chars(const char *si, char *dst, SQLLEN used,
2546 UInt4 flags, int ccsc, int escape_in_literal)
2548 size_t i = 0, out = 0, max;
2549 char *p = NULL, literal_quote = LITERAL_QUOTE, tchar;
2550 encoded_str encstr;
2551 BOOL convlf = (0 != (flags & FLGB_CONVERT_LF)),
2552 double_special = (0 == (flags & FLGB_BUILDING_BIND_REQUEST));
2554 if (used == SQL_NTS)
2555 max = strlen(si);
2556 else
2557 max = used;
2558 if (dst)
2560 p = dst;
2561 p[0] = '\0';
2563 encoded_str_constr(&encstr, ccsc, si);
2565 for (i = 0; i < max && si[i]; i++)
2567 tchar = encoded_nextchar(&encstr);
2568 if (ENCODE_STATUS(encstr) != 0)
2570 if (p)
2571 p[out] = tchar;
2572 out++;
2573 continue;
2575 if (convlf && /* CR/LF -> LF */
2576 PG_CARRIAGE_RETURN == tchar && PG_LINEFEED == si[i + 1])
2577 continue;
2578 else if (double_special && /* double special chars ? */
2579 (tchar == literal_quote || tchar == escape_in_literal))
2581 if (p)
2582 p[out++] = tchar;
2583 else
2584 out++;
2586 if (p)
2587 p[out++] = tchar;
2588 else
2589 out++;
2591 if (p)
2592 p[out] = '\0';
2593 return out;
2596 #ifdef NOT_USED
2597 #define CVT_CRLF_TO_LF 1L
2598 #define DOUBLE_LITERAL_QUOTE (1L << 1)
2599 #define DOUBLE_ESCAPE_IN_LITERAL (1L << 2)
2600 static int
2601 convert_text_field(const char *si, char *dst, int used, int ccsc,
2602 int escape_in_literal, UInt4 * flags)
2604 size_t i = 0, out = 0, max;
2605 UInt4 iflags = *flags;
2606 char *p = NULL, literal_quote = LITERAL_QUOTE, tchar;
2607 encoded_str encstr;
2608 BOOL convlf = (0 != (iflags & CVT_CRLF_TO_LF)),
2609 double_literal_quote = (0 != (iflags & DOUBLE_LITERAL_QUOTE)),
2610 double_escape_in_literal =
2611 (0 != (iflags & DOUBLE_ESCAPE_IN_LITERAL));
2613 if (SQL_NTS == used)
2614 max = strlen(si);
2615 else
2616 max = used;
2617 if (0 == iflags)
2619 if (dst)
2620 strncpy_null(dst, si, max + 1);
2621 else
2622 return max;
2624 if (dst)
2626 p = dst;
2627 p[0] = '\0';
2629 encoded_str_constr(&encstr, ccsc, si);
2631 *flags = 0;
2632 for (i = 0; i < max && si[i]; i++)
2634 tchar = encoded_nextchar(&encstr);
2635 if (ENCODE_STATUS(encstr) != 0)
2637 if (p)
2638 p[out] = tchar;
2639 out++;
2640 continue;
2642 if (convlf && /* CR/LF -> LF */
2643 PG_CARRIAGE_RETURN == tchar && PG_LINEFEED == si[i + 1])
2645 *flags |= CVT_CRLF_TO_LF;
2646 continue;
2647 } else if (double_literal_quote && /* double literal quote ? */
2648 tchar == literal_quote)
2650 if (p)
2651 p[out] = tchar;
2652 out++;
2653 *flags |= DOUBLE_LITERAL_QUOTE;
2654 } else if (double_escape_in_literal && /* double escape ? */
2655 tchar == escape_in_literal)
2657 if (p)
2658 p[out] = tchar;
2659 out++;
2660 *flags |= DOUBLE_ESCAPE_IN_LITERAL;
2662 if (p)
2663 p[out] = tchar;
2664 out++;
2666 if (p)
2667 p[out] = '\0';
2668 return out;
2670 #endif /* NOT_USED */
2673 /* !!! Need to implement this function !!! */
2675 convert_pgbinary_to_char(const char *value, char *rgbValue,
2676 ssize_t cbValueMax)
2678 mylog("convert_pgbinary_to_char: value = '%s'\n", value);
2680 strncpy_null(rgbValue, value, cbValueMax);
2681 return 0;
2685 static int conv_from_octal(const UCHAR * s)
2687 ssize_t i;
2688 int y = 0;
2690 for (i = 1; i <= 3; i++)
2691 y += (s[i] - '0') << (3 * (3 - i));
2693 return y;
2697 /* convert octal escapes to bytes */
2698 size_t
2699 convert_from_pgbinary(const UCHAR * value, UCHAR * rgbValue,
2700 SQLLEN cbValueMax)
2702 size_t i, ilen = strlen((const char *)value);
2703 size_t o = 0;
2706 for (i = 0; i < ilen;)
2708 if (value[i] == BYTEA_ESCAPE_CHAR)
2710 if (value[i + 1] == BYTEA_ESCAPE_CHAR)
2712 if (rgbValue)
2713 rgbValue[o] = value[i];
2714 i += 2;
2715 } else
2717 if (rgbValue)
2718 rgbValue[o] = conv_from_octal(&value[i]);
2719 i += 4;
2721 } else
2723 if (rgbValue)
2724 rgbValue[o] = value[i];
2725 i++;
2727 /** if (rgbValue)
2728 mylog("convert_from_pgbinary: i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]); ***/
2729 o++;
2732 if (rgbValue)
2733 rgbValue[o] = '\0'; /* extra protection */
2735 mylog("convert_from_pgbinary: in=%d, out = %d\n", ilen, o);
2737 return o;
2741 static UInt2 conv_to_octal(UCHAR val, char *octal, char escape_ch)
2743 int i, pos = 0, len;
2745 if (escape_ch)
2746 octal[pos++] = escape_ch;
2747 octal[pos] = BYTEA_ESCAPE_CHAR;
2748 len = 4 + pos;
2749 octal[len] = '\0';
2751 for (i = len - 1; i > pos; i--)
2753 octal[i] = (val & 7) + '0';
2754 val >>= 3;
2757 return (UInt2) len;
2761 static char *conv_to_octal2(UCHAR val, char *octal)
2763 int i;
2765 octal[0] = BYTEA_ESCAPE_CHAR;
2766 octal[4] = '\0';
2768 for (i = 3; i > 0; i--)
2770 octal[i] = (val & 7) + '0';
2771 val >>= 3;
2774 return octal;
2778 /* convert non-ascii bytes to octal escape sequences */
2779 static size_t
2780 convert_to_pgbinary(const UCHAR * in, char *out, size_t len,
2781 QueryBuild * qb)
2783 CSTR func = "convert_to_pgbinary";
2784 UCHAR inc;
2785 size_t i, o = 0;
2786 char escape_in_literal = CC_get_escape(qb->conn);
2787 BOOL esc_double = (0 == (qb->flags & FLGB_BUILDING_BIND_REQUEST)
2788 && 0 != escape_in_literal);
2790 for (i = 0; i < len; i++)
2792 inc = in[i];
2793 mylog("%s: in[%d] = %d, %c\n", func, i, inc, inc);
2794 if (inc < 128 && (isalnum(inc) || inc == ' '))
2795 out[o++] = inc;
2796 else
2798 if (esc_double)
2800 o += conv_to_octal(inc, &out[o], escape_in_literal);
2801 } else
2803 conv_to_octal2(inc, &out[o]);
2804 o += 4;
2809 mylog("%s: returning %d, out='%.*s'\n", func, o, o, out);
2811 return o;
2815 static const char *hextbl = "0123456789ABCDEF";
2816 static SQLLEN pg_bin2hex(UCHAR * src, UCHAR * dst, SQLLEN length)
2818 UCHAR chr, *src_wk, *dst_wk;
2819 BOOL backwards;
2820 int i;
2822 backwards = FALSE;
2823 if (dst < src)
2825 if (dst + length > src + 1)
2826 return -1;
2827 } else if (dst < src + length)
2828 backwards = TRUE;
2829 if (backwards)
2831 for (i = 0, src_wk = src + length - 1, dst_wk =
2832 dst + 2 * length - 1; i < length; i++, src_wk--)
2834 chr = *src_wk;
2835 *dst_wk-- = hextbl[chr % 16];
2836 *dst_wk-- = hextbl[chr >> 4];
2838 } else
2840 for (i = 0, src_wk = src, dst_wk = dst; i < length;
2841 i++, src_wk++)
2843 chr = *src_wk;
2844 *dst_wk++ = hextbl[chr >> 4];
2845 *dst_wk++ = hextbl[chr % 16];
2848 dst[2 * length] = '\0';
2849 return length;
2852 SQLLEN pg_hex2bin(const UCHAR * src, UCHAR * dst, SQLLEN length)
2854 UCHAR chr;
2855 const UCHAR *src_wk;
2856 UCHAR *dst_wk;
2857 SQLLEN i;
2858 int val;
2859 BOOL HByte = TRUE;
2861 for (i = 0, src_wk = src, dst_wk = dst; i < length; i++, src_wk++)
2863 chr = *src_wk;
2864 if (!chr)
2865 break;
2866 if (chr >= 'a' && chr <= 'f')
2867 val = chr - 'a' + 10;
2868 else if (chr >= 'A' && chr <= 'F')
2869 val = chr - 'A' + 10;
2870 else
2871 val = chr - '0';
2872 if (HByte)
2873 *dst_wk = (val << 4);
2874 else
2876 *dst_wk += val;
2877 dst_wk++;
2879 HByte = !HByte;
2881 *dst_wk = '\0';
2882 return length;