1 /*-------
2  * Module:				 convert.c
3  *
4  * Description:    This module contains routines related to
5  *				   converting parameters and columns into requested data types.
6  *				   Parameters are converted from their SQL_C data types into
7  *				   the appropriate postgres type.  Columns are converted from
8  *				   their postgres type (SQL type) into the appropriate SQL_C
9  *				   data type.
10  *
11  * Classes:		   n/a
12  *
13  * API functions:  none
14  *
15  * Comments:	   See "readme.txt" for copyright and license information.
16  *-------
17  */
18 /* Multibyte support  Eiji Tokuya	2001-03-15	*/
19 
20 #include "convert.h"
21 #include "unicode_support.h"
22 #include "misc.h"
23 #ifdef	WIN32
24 #include <float.h>
25 #define	HAVE_LOCALE_H
26 #endif /* WIN32 */
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 
32 #include "multibyte.h"
33 
34 #include <time.h>
35 #ifdef HAVE_LOCALE_H
36 #include <locale.h>
37 #endif
38 #include <math.h>
39 #include <stdlib.h>
40 #include <limits.h>
41 #include "statement.h"
42 #include "qresult.h"
43 #include "bind.h"
44 #include "pgtypes.h"
45 #include "lobj.h"
46 #include "connection.h"
47 #include "catfunc.h"
48 #include "pgapifunc.h"
49 
50 CSTR	NAN_STRING = "NaN";
51 CSTR	INFINITY_STRING = "Infinity";
52 CSTR	MINFINITY_STRING = "-Infinity";
53 
54 #if	defined(WIN32) || defined(__CYGWIN__)
55 #define TIMEZONE_GLOBAL _timezone
56 #define TZNAME_GLOBAL _tzname
57 #define DAYLIGHT_GLOBAL _daylight
58 #elif	defined(HAVE_INT_TIMEZONE)
59 #define TIMEZONE_GLOBAL timezone
60 #define TZNAME_GLOBAL tzname
61 #define DAYLIGHT_GLOBAL daylight
62 #endif
63 
64 /*
65  *	How to map ODBC scalar functions {fn func(args)} to Postgres.
66  *	This is just a simple substitution.  List augmented from:
67  *	http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
68  *	- thomas 2000-04-03
69  */
70 static const struct
71 {
72 	/*
73 	 * There's a horrible hack in odbc_name field: if it begins with a %,
74 	 * the digit after the % indicates the number of arguments. Otherwise,
75 	 * the entry matches any number of args.
76 	 */
77 	char *odbc_name;
78 	char *pgsql_name;
79 } mapFuncs[] = {
80 /*	{ "ASCII",		 "ascii"	  }, built_in */
81 	{"CHAR", "chr($*)" },
82 	{"CONCAT", "concat($1::text, $2::text)" },
83 /*	{ "DIFFERENCE", "difference" }, how to ? */
84 	{"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" },
85 	{"LCASE", "lower($*)" },
86 /*	{"LEFT",		 "left"		  }, built_in */
87 	{"%2LOCATE", "strpos($2,  $1)" },	/* 2 parameters */
88 	{"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" },	/* 3 parameters */
89 	{"LENGTH", "char_length($*)"},
90 /*	{ "LTRIM",		 "ltrim"	  }, built_in */
91 /*	{"RIGHT",		 "right"	  }, built_in */
92 	{"SPACE", "repeat(' ', $1)" },
93 /*	{ "REPEAT",		 "repeat"	  }, built_in */
94 /*	{ "REPLACE", "replace" }, ??? */
95 /*	{ "RTRIM",		 "rtrim"	  }, built_in */
96 /*	{ "SOUNDEX", "soundex" }, how to ? */
97 	{"SUBSTRING", "substr($*)" },
98 	{"UCASE", "upper($*)" },
99 
100 /*	{ "ABS",		 "abs"		  }, built_in */
101 /*	{ "ACOS",		 "acos"		  }, built_in */
102 /*	{ "ASIN",		 "asin"		  }, built_in */
103 /*	{ "ATAN",		 "atan"		  }, built_in */
104 /*	{ "ATAN2",		 "atan2"	  }, built_in */
105 	{"CEILING", "ceil($*)" },
106 /*	{ "COS",		 "cos" 		  }, built_in */
107 /*	{ "COT",		 "cot" 		  }, built_in */
108 /*	{ "DEGREES",		 "degrees" 	  }, built_in */
109 /*	{ "EXP",		 "exp" 		  }, built_in */
110 /*	{ "FLOOR",		 "floor" 	  }, built_in */
111 	{"LOG", "ln($*)" },
112 	{"LOG10", "log($*)" },
113 /*	{ "MOD",		 "mod" 		  }, built_in */
114 /*	{ "PI",			 "pi" 		  }, built_in */
115 /*	{"POWER", 		 "power"	  }, built_in */
116 /*	{ "RADIANS",		 "radians"	  }, built_in */
117 	{"%0RAND", "random()" },	/* 0 parameters */
118 	{"%1RAND", "(setseed($1) * .0 + random())" },	/* 1 parameters */
119 /*	{ "ROUND",		 "round"	  }, built_in */
120 /*	{ "SIGN",		 "sign"		  }, built_in */
121 /*	{ "SIN",		 "sin"		  }, built_in */
122 /*	{ "SQRT",		 "sqrt"		  }, built_in */
123 /*	{ "TAN",		 "tan"		  }, built_in */
124 	{"TRUNCATE", "trunc($*)" },
125 
126 	{"CURRENT_DATE", "current_date" },
127 	{"CURRENT_TIME", "current_time" },
128 	{"CURRENT_TIMESTAMP", "current_timestamp" },
129 	{"LOCALTIME", "localtime" },
130 	{"LOCALTIMESTAMP", "localtimestamp" },
131 	{"CURRENT_USER", "cast(current_user as text)" },
132 	{"SESSION_USER", "cast(session_user as text)" },
133 	{"CURDATE",	 "current_date" },
134 	{"CURTIME",	 "current_time" },
135 	{"DAYNAME",	 "to_char($1, 'Day')" },
136 	{"DAYOFMONTH",  "cast(extract(day from $1) as integer)" },
137 	{"DAYOFWEEK",	 "(cast(extract(dow from $1) as integer) + 1)" },
138 	{"DAYOFYEAR",	 "cast(extract(doy from $1) as integer)" },
139 	{"HOUR",	 "cast(extract(hour from $1) as integer)" },
140 	{"MINUTE",	"cast(extract(minute from $1) as integer)" },
141 	{"MONTH",	"cast(extract(month from $1) as integer)" },
142 	{"MONTHNAME",	 " to_char($1, 'Month')" },
143 /*	{ "NOW",		 "now"		  }, built_in */
144 	{"QUARTER",	 "cast(extract(quarter from $1) as integer)" },
145 	{"SECOND",	"cast(extract(second from $1) as integer)" },
146 	{"WEEK",	"cast(extract(week from $1) as integer)" },
147 	{"YEAR",	"cast(extract(year from $1) as integer)" },
148 	// TIMESTAMPADD()
149 	{"TIMESTAMPADD(SQL_TSI_YEAR", "($3+make_interval(years := $2))" },
150 	{"TIMESTAMPADD(SQL_TSI_MONTH", "($3+make_interval(months := $2))" },
151 	{"TIMESTAMPADD(SQL_TSI_WEEK", "($3+make_interval(weeks := $2))" },
152 	{"TIMESTAMPADD(SQL_TSI_DAY", "($3+make_interval(days := $2))" },
153 	{"TIMESTAMPADD(SQL_TSI_HOUR", "($3+make_interval(hours := $2))" },
154 	{"TIMESTAMPADD(SQL_TSI_MINUTE", "($3+make_interval(mins := $2))" },
155 	{"TIMESTAMPADD(SQL_TSI_SECOND", "($3+make_interval(secs := $2))" },
156 	{"TIMESTAMPADD(SQL_TSI_FRAC_SECOND", "($3+make_interval(secs := $2::float / 1000000))" },
157 	// TIMESTAMPDIFF()
158 /* doesn't work properly?
159 {"TIMESTAMPDIFF(SQL_TSI_YEAR", "cast(extract(year from ($3 - $2)) as integer)" },
160 {"TIMESTAMPDIFF(SQL_TSI_MONTH", "cast(extract(month from ($3 - $2)) as integer)" },
161 {"TIMESTAMPDIFF(SQL_TSI_QUARTER", "cast(extract(quarter from ($3 - $2)) as integer)" },
162 {"TIMESTAMPDIFF(SQL_TSI_WEEK", "cast(extract(week from ($3 - $2)) as integer)" },
163 */
164 	/*
165 	{"TIMESTAMPDIFF(SQL_TSI_DAY", "cast(extract(day from ($3 - $2)) as integer)" },
166 	{"TIMESTAMPDIFF(SQL_TSI_HOUR", "cast(extract(hour from ($3 - $2)) as integer)" },
167 	{"TIMESTAMPDIFF(SQL_TSI_HOUR", "(extract(epoch from $3) - extract(epoch from $2)) / 3600" },
168 	{"TIMESTAMPDIFF(SQL_TSI_MINUTE", "cast(extract(minute from ($3 - $2)) as integer)" },
169 	{"TIMESTAMPDIFF(SQL_TSI_SECOND", "cast(extract(second from ($3 - $2)) as integer)" },
170 	*/
171 	{"TIMESTAMPDIFF(SQL_TSI_DAY", "cast((extract(epoch from $3) - extract(epoch from $2)) / (24*60*60) as int)" },
172 	{"TIMESTAMPDIFF(SQL_TSI_HOUR", "cast((extract(epoch from $3) - extract(epoch from $2)) / 3600 as int)" },
173 	{"TIMESTAMPDIFF(SQL_TSI_MINUTE", "cast((extract(epoch from $3) - extract(epoch from $2)) / 60 as int)" },
174 	{"TIMESTAMPDIFF(SQL_TSI_SECOND", "cast((extract(epoch from $3) - extract(epoch from $2)) as int)" },
175 	{"TIMESTAMPDIFF(SQL_TSI_FRAC_SECOND", "mod(cast(extract(second from ($3 - $2)) as numeric), 1.0) * 1000000" },
176 
177 /*	{ "EXTRACT",		 "extract"		  }, built_in */
178 
179 /*	{ "DATABASE",	 "database"   }, */
180 	{"IFNULL", "coalesce($*)" },
181 	{"USER", "cast(current_user as text)" },
182 
183 	{0, 0}
184 };
185 
186 typedef struct
187 {
188 	int		infinity;
189 	int			m;
190 	int			d;
191 	int			y;
192 	int			hh;
193 	int			mm;
194 	int			ss;
195 	int			fr;
196 } SIMPLE_TIME;
197 
198 static const char *mapFunction(const char *func, int param_count, const char * keyword);
199 static BOOL convert_money(const char *s, char *sout, size_t soutmax);
200 static char parse_datetime(const char *buf, SIMPLE_TIME *st);
201 size_t convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed);
202 static size_t convert_from_pgbinary(const char *value, char *rgbValue, SQLLEN cbValueMax);
203 static int convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType,
204 	 PTR rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue);
205 static int conv_from_octal(const char *s);
206 static SQLLEN pg_bin2hex(const char *src, char *dst, SQLLEN length);
207 #ifdef	UNICODE_SUPPORT
208 static SQLLEN pg_bin2whex(const char *src, SQLWCHAR *dst, SQLLEN length);
209 #endif /* UNICODE_SUPPORT */
210 
211 /*---------
212  *			A Guide for date/time/timestamp conversions
213  *
214  *			field_type		fCType				Output
215  *			----------		------				----------
216  *			PG_TYPE_DATE	SQL_C_DEFAULT		SQL_C_DATE
217  *			PG_TYPE_DATE	SQL_C_DATE			SQL_C_DATE
218  *			PG_TYPE_DATE	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(time = 0 (midnight))
219  *			PG_TYPE_TIME	SQL_C_DEFAULT		SQL_C_TIME
220  *			PG_TYPE_TIME	SQL_C_TIME			SQL_C_TIME
221  *			PG_TYPE_TIME	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(date = current date)
222  *			PG_TYPE_ABSTIME SQL_C_DEFAULT		SQL_C_TIMESTAMP
223  *			PG_TYPE_ABSTIME SQL_C_DATE			SQL_C_DATE			(time is truncated)
224  *			PG_TYPE_ABSTIME SQL_C_TIME			SQL_C_TIME			(date is truncated)
225  *			PG_TYPE_ABSTIME SQL_C_TIMESTAMP		SQL_C_TIMESTAMP
226  *---------
227  */
228 
229 
230 /*
231  *	Macros for unsigned long handling.
232  */
233 #ifdef	WIN32
234 #define	ATOI32U(val)	strtoul(val, NULL, 10)
235 #elif	defined(HAVE_STRTOUL)
236 #define	ATOI32U(val)	strtoul(val, NULL, 10)
237 #else /* HAVE_STRTOUL */
238 #define	ATOI32U	atol
239 #endif /* WIN32 */
240 
241 /*
242  *	Macros for BIGINT handling.
243  */
244 #ifdef	ODBCINT64
245 #ifdef	WIN32
246 #define	ATOI64(val)	_strtoi64(val, NULL, 10)
247 #define	ATOI64U(val)	_strtoui64(val, NULL, 10)
248 #elif	(SIZEOF_LONG == 8)
249 #define	ATOI64(val)	strtol(val, NULL, 10)
250 #define	ATOI64U(val)	strtoul(val, NULL, 10)
251 #else
252 #if	defined(HAVE_STRTOLL)
253 #define	ATOI64(val)	strtoll(val, NULL, 10)
254 #define	ATOI64U(val)	strtoull(val, NULL, 10)
255 #else
ATOI64(const char * val)256 static ODBCINT64 ATOI64(const char *val)
257 {
258 	ODBCINT64 ll;
259 	sscanf(val, "%lld", &ll);
260 	return ll;
261 }
ATOI64U(const char * val)262 static unsigned ODBCINT64 ATOI64U(const char *val)
263 {
264 	unsigned ODBCINT64 ll;
265 	sscanf(val, "%llu", &ll);
266 	return ll;
267 }
268 #endif /* HAVE_STRTOLL */
269 #endif /* WIN32 */
270 #endif /* ODBCINT64 */
271 
272 static void ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform);
273 static void parse_to_numeric_struct(const char *wv, SQL_NUMERIC_STRUCT *ns, BOOL *overflow);
274 
275 /*
276  *	TIMESTAMP <-----> SIMPLE_TIME
277  *		precision support since 7.2.
278  *		time zone support is unavailable(the stuff is unreliable)
279  */
280 static BOOL
timestamp2stime(const char * str,SIMPLE_TIME * st,BOOL * bZone,int * zone)281 timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
282 {
283 	char		rest[64], bc[16],
284 			   *ptr;
285 	int			scnt,
286 				i;
287 	int			y, m, d, hh, mm, ss;
288 #ifdef	TIMEZONE_GLOBAL
289 	long		timediff;
290 #endif
291 	BOOL		withZone = *bZone;
292 
293 	*bZone = FALSE;
294 	*zone = 0;
295 	st->fr = 0;
296 	st->infinity = 0;
297 	rest[0] = '\0';
298 	bc[0] = '\0';
299 	if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%31s %15s", &y, &m, &d, &hh, &mm, &ss, rest, bc)) < 6)
300 	{
301 		if (scnt == 3) /* date */
302 		{
303 			st->y  = y;
304 			st->m  = m;
305 			st->d  = d;
306 			st->hh = 0;
307 			st->mm = 0;
308 			st->ss = 0;
309 			return TRUE;
310 		}
311 		if ((scnt = sscanf(str, "%2d:%2d:%2d%31s %15s", &hh, &mm, &ss, rest, bc)) < 3)
312 			return FALSE;
313 		else
314 		{
315 			st->hh = hh;
316 			st->mm = mm;
317 			st->ss = ss;
318 			if (scnt == 3) /* time */
319 				return TRUE;
320 		}
321 	}
322 	else
323 	{
324 		st->y  = y;
325 		st->m  = m;
326 		st->d  = d;
327 		st->hh = hh;
328 		st->mm = mm;
329 		st->ss = ss;
330 		if (scnt == 6)
331 			return TRUE;
332 	}
333 	switch (rest[0])
334 	{
335 		case '+':
336 			*bZone = TRUE;
337 			*zone = atoi(&rest[1]);
338 			break;
339 		case '-':
340 			*bZone = TRUE;
341 			*zone = -atoi(&rest[1]);
342 			break;
343 		case '.':
344 			if ((ptr = strchr(rest, '+')) != NULL)
345 			{
346 				*bZone = TRUE;
347 				*zone = atoi(&ptr[1]);
348 				*ptr = '\0';
349 			}
350 			else if ((ptr = strchr(rest, '-')) != NULL)
351 			{
352 				*bZone = TRUE;
353 				*zone = -atoi(&ptr[1]);
354 				*ptr = '\0';
355 			}
356 			for (i = 1; i < 10; i++)
357 			{
358 				if (!isdigit((UCHAR) rest[i]))
359 					break;
360 			}
361 			for (; i < 10; i++)
362 				rest[i] = '0';
363 			rest[i] = '\0';
364 			st->fr = atoi(&rest[1]);
365 			break;
366 		case 'B':
367 			if (stricmp(rest, "BC") == 0)
368 				st->y *= -1;
369 			return TRUE;
370 		default:
371 			return TRUE;
372 	}
373 	if (stricmp(bc, "BC") == 0)
374 	{
375 		st->y *= -1;
376 	}
377 	if (!withZone || !*bZone || st->y < 1970)
378 		return TRUE;
379 #ifdef	TIMEZONE_GLOBAL
380 	if (!TZNAME_GLOBAL[0] || !TZNAME_GLOBAL[0][0])
381 	{
382 		*bZone = FALSE;
383 		return TRUE;
384 	}
385 	timediff = TIMEZONE_GLOBAL + (*zone) * 3600;
386 	if (!DAYLIGHT_GLOBAL && timediff == 0)		/* the same timezone */
387 		return TRUE;
388 	else
389 	{
390 		struct tm	tm,
391 				   *tm2;
392 		time_t		time0;
393 
394 		*bZone = FALSE;
395 		tm.tm_year = st->y - 1900;
396 		tm.tm_mon = st->m - 1;
397 		tm.tm_mday = st->d;
398 		tm.tm_hour = st->hh;
399 		tm.tm_min = st->mm;
400 		tm.tm_sec = st->ss;
401 		tm.tm_isdst = -1;
402 		time0 = mktime(&tm);
403 		if (time0 < 0)
404 			return TRUE;
405 		if (tm.tm_isdst > 0)
406 			timediff -= 3600;
407 		if (timediff == 0)		/* the same time zone */
408 			return TRUE;
409 		time0 -= timediff;
410 #ifdef	HAVE_LOCALTIME_R
411 		if (time0 >= 0 && (tm2 = localtime_r(&time0, &tm)) != NULL)
412 #else
413 		if (time0 >= 0 && (tm2 = localtime(&time0)) != NULL)
414 #endif /* HAVE_LOCALTIME_R */
415 		{
416 			st->y = tm2->tm_year + 1900;
417 			st->m = tm2->tm_mon + 1;
418 			st->d = tm2->tm_mday;
419 			st->hh = tm2->tm_hour;
420 			st->mm = tm2->tm_min;
421 			st->ss = tm2->tm_sec;
422 			*bZone = TRUE;
423 		}
424 	}
425 #endif /* TIMEZONE_GLOBAL */
426 	return TRUE;
427 }
428 
429 static int
stime2timestamp(const SIMPLE_TIME * st,char * str,size_t bufsize,BOOL bZone,int precision)430 stime2timestamp(const SIMPLE_TIME *st, char *str, size_t bufsize, BOOL bZone,
431 				int precision)
432 {
433 	char		precstr[16],
434 				zonestr[16];
435 	int			i;
436 
437 	precstr[0] = '\0';
438 	if (st->infinity > 0)
439 	{
440 		return snprintf(str, bufsize, "%s", INFINITY_STRING);
441 	}
442 	else if (st->infinity < 0)
443 	{
444 		return snprintf(str, bufsize, "%s", MINFINITY_STRING);
445 	}
446 	if (precision > 0 && st->fr)
447 	{
448 		SPRINTF_FIXED(precstr, ".%09d", st->fr);
449 		if (precision < 9)
450 			precstr[precision + 1] = '\0';
451 		else if (precision > 9)
452 			precision = 9;
453 		for (i = precision; i > 0; i--)
454 		{
455 			if (precstr[i] != '0')
456 				break;
457 			precstr[i] = '\0';
458 		}
459 		if (i == 0)
460 			precstr[i] = '\0';
461 	}
462 	zonestr[0] = '\0';
463 #ifdef	TIMEZONE_GLOBAL
464 	if (bZone && TZNAME_GLOBAL[0] && TZNAME_GLOBAL[0][0] && st->y >= 1970)
465 	{
466 		long		zoneint;
467 		struct tm	tm;
468 		time_t		time0;
469 
470 		zoneint = TIMEZONE_GLOBAL;
471 		if (DAYLIGHT_GLOBAL && st->y >= 1900)
472 		{
473 			tm.tm_year = st->y - 1900;
474 			tm.tm_mon = st->m - 1;
475 			tm.tm_mday = st->d;
476 			tm.tm_hour = st->hh;
477 			tm.tm_min = st->mm;
478 			tm.tm_sec = st->ss;
479 			tm.tm_isdst = -1;
480 			time0 = mktime(&tm);
481 			if (time0 >= 0 && tm.tm_isdst > 0)
482 				zoneint -= 3600;
483 		}
484 		if (zoneint > 0)
485 			SPRINTF_FIXED(zonestr, "-%02d", (int) zoneint / 3600);
486 		else
487 			SPRINTF_FIXED(zonestr, "+%02d", -(int) zoneint / 3600);
488 	}
489 #endif /* TIMEZONE_GLOBAL */
490 	if (st->y < 0)
491 		return snprintf(str, bufsize, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s BC", -st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr);
492 	else
493 		return snprintf(str, bufsize, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr);
494 }
495 
496 static
interval2itype(SQLSMALLINT ctype)497 SQLINTERVAL	interval2itype(SQLSMALLINT ctype)
498 {
499 	SQLINTERVAL	sqlitv = 0;
500 
501 	switch (ctype)
502 	{
503 		case SQL_C_INTERVAL_YEAR:
504 			sqlitv = SQL_IS_YEAR;
505 			break;
506 		case SQL_C_INTERVAL_MONTH:
507 			sqlitv = SQL_IS_MONTH;
508 			break;
509 		case SQL_C_INTERVAL_YEAR_TO_MONTH:
510 			sqlitv = SQL_IS_YEAR_TO_MONTH;
511 			break;
512 		case SQL_C_INTERVAL_DAY:
513 			sqlitv = SQL_IS_DAY;
514 			break;
515 		case SQL_C_INTERVAL_HOUR:
516 			sqlitv = SQL_IS_HOUR;
517 			break;
518 		case SQL_C_INTERVAL_DAY_TO_HOUR:
519 			sqlitv = SQL_IS_DAY_TO_HOUR;
520 			break;
521 		case SQL_C_INTERVAL_MINUTE:
522 			sqlitv = SQL_IS_MINUTE;
523 			break;
524 		case SQL_C_INTERVAL_DAY_TO_MINUTE:
525 			sqlitv = SQL_IS_DAY_TO_MINUTE;
526 			break;
527 		case SQL_C_INTERVAL_HOUR_TO_MINUTE:
528 			sqlitv = SQL_IS_HOUR_TO_MINUTE;
529 			break;
530 		case SQL_C_INTERVAL_SECOND:
531 			sqlitv = SQL_IS_SECOND;
532 			break;
533 		case SQL_C_INTERVAL_DAY_TO_SECOND:
534 			sqlitv = SQL_IS_DAY_TO_SECOND;
535 			break;
536 		case SQL_C_INTERVAL_HOUR_TO_SECOND:
537 			sqlitv = SQL_IS_HOUR_TO_SECOND;
538 			break;
539 		case SQL_C_INTERVAL_MINUTE_TO_SECOND:
540 			sqlitv = SQL_IS_MINUTE_TO_SECOND;
541 			break;
542 	}
543 	return sqlitv;
544 }
545 
546 /*
547  *	Interval data <-----> SQL_INTERVAL_STRUCT
548  */
549 
getPrecisionPart(int precision,const char * precPart)550 static int getPrecisionPart(int precision, const char * precPart)
551 {
552 	char	fraction[] = "000000000";
553 	int		fracs = sizeof(fraction) - 1;
554 	size_t	cpys;
555 
556 	if (precision < 0)
557 		precision = 6; /* default */
558 	if (precision == 0)
559 		return 0;
560 	cpys = strlen(precPart);
561 	if (cpys > fracs)
562 		cpys = fracs;
563 	memcpy(fraction, precPart, cpys);
564 	fraction[precision] = '\0';
565 
566 	return atoi(fraction);
567 }
568 
569 static BOOL
interval2istruct(SQLSMALLINT ctype,int precision,const char * str,SQL_INTERVAL_STRUCT * st)570 interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL_STRUCT *st)
571 {
572 	char	lit1[64], lit2[64];
573 	int	scnt, years, mons, days, hours, minutes, seconds;
574 	BOOL	sign;
575 	SQLINTERVAL	itype = interval2itype(ctype);
576 
577 	memset(st, 0, sizeof(SQL_INTERVAL_STRUCT));
578 	if ((scnt = sscanf(str, "%d-%d", &years, &mons)) >=2)
579 	{
580 		if (SQL_IS_YEAR_TO_MONTH == itype)
581 		{
582 			sign = years < 0 ? SQL_TRUE : SQL_FALSE;
583 			st->interval_type = itype;
584 			st->interval_sign = sign;
585 			st->intval.year_month.year = sign ? (-years) : years;
586 			st->intval.year_month.month = mons;
587 			return TRUE;
588 		}
589 		return FALSE;
590 	}
591 	else if (scnt = sscanf(str, "%d %02d:%02d:%02d.%09s", &days, &hours, &minutes, &seconds, lit2), 5 == scnt || 4 == scnt)
592 	{
593 		sign = days < 0 ? SQL_TRUE : SQL_FALSE;
594 		st->interval_type = itype;
595 		st->interval_sign = sign;
596 		st->intval.day_second.day = sign ? (-days) : days;
597 		st->intval.day_second.hour = hours;
598 		st->intval.day_second.minute = minutes;
599 		st->intval.day_second.second = seconds;
600 		if (scnt > 4)
601 			st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
602 		return TRUE;
603 	}
604 	else if ((scnt = sscanf(str, "%d %10s %d %10s", &years, lit1, &mons, lit2)) >=4)
605 	{
606 		if (strnicmp(lit1, "year", 4) == 0 &&
607 		    strnicmp(lit2, "mon", 2) == 0 &&
608 		    (SQL_IS_MONTH == itype ||
609 		     SQL_IS_YEAR_TO_MONTH == itype))
610 		{
611 			sign = years < 0 ? SQL_TRUE : SQL_FALSE;
612 			st->interval_type = itype;
613 			st->interval_sign = sign;
614 			st->intval.year_month.year = sign ? (-years) : years;
615 			st->intval.year_month.month = sign ? (-mons) : mons;
616 			return TRUE;
617 		}
618 		return FALSE;
619 	}
620 	if ((scnt = sscanf(str, "%d %10s %d", &years, lit1, &days)) == 2)
621 	{
622 		sign = years < 0 ? SQL_TRUE : SQL_FALSE;
623 		if (SQL_IS_YEAR == itype &&
624 		    (stricmp(lit1, "year") == 0 ||
625 		     stricmp(lit1, "years") == 0))
626 		{
627 			st->interval_type = itype;
628 			st->interval_sign = sign;
629 			st->intval.year_month.year = sign ? (-years) : years;
630 			return TRUE;
631 		}
632 		if (SQL_IS_MONTH == itype &&
633 		    (stricmp(lit1, "mon") == 0 ||
634 		     stricmp(lit1, "mons") == 0))
635 		{
636 			st->interval_type = itype;
637 			st->interval_sign = sign;
638 			st->intval.year_month.month = sign ? (-years) : years;
639 			return TRUE;
640 		}
641 		if (SQL_IS_DAY == itype &&
642 		    (stricmp(lit1, "day") == 0 ||
643 		     stricmp(lit1, "days") == 0))
644 		{
645 			st->interval_type = itype;
646 			st->interval_sign = sign;
647 			st->intval.day_second.day = sign ? (-years) : years;
648 			return TRUE;
649 		}
650 		return FALSE;
651 	}
652 	if (itype == SQL_IS_YEAR || itype == SQL_IS_MONTH || itype == SQL_IS_YEAR_TO_MONTH)
653 	{
654 		/* these formats should've been handled above already */
655 		return FALSE;
656 	}
657 	scnt = sscanf(str, "%d %10s %02d:%02d:%02d.%09s", &days, lit1, &hours, &minutes, &seconds, lit2);
658 	if (scnt == 5 || scnt == 6)
659 	{
660 		if (strnicmp(lit1, "day", 3) != 0)
661 			return FALSE;
662 		sign = days < 0 ? SQL_TRUE : SQL_FALSE;
663 
664 		st->interval_type = itype;
665 		st->interval_sign = sign;
666 		st->intval.day_second.day = sign ? (-days) : days;
667 		st->intval.day_second.hour = sign ? (-hours) : hours;
668 		st->intval.day_second.minute = minutes;
669 		st->intval.day_second.second = seconds;
670 		if (scnt > 5)
671 			st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
672 		return TRUE;
673 	}
674 	scnt = sscanf(str, "%02d:%02d:%02d.%09s", &hours, &minutes, &seconds, lit2);
675 	if (scnt == 3 || scnt == 4)
676 	{
677 		sign = hours < 0 ? SQL_TRUE : SQL_FALSE;
678 
679 		st->interval_type = itype;
680 		st->interval_sign = sign;
681 		st->intval.day_second.hour = sign ? (-hours) : hours;
682 		st->intval.day_second.minute = minutes;
683 		st->intval.day_second.second = seconds;
684 		if (scnt > 3)
685 			st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
686 		return TRUE;
687 	}
688 
689 	return FALSE;
690 }
691 
692 
693 #ifdef	HAVE_LOCALE_H
694 /*
695  * Get the decimal point of the current locale.
696  *
697  * XXX: This isn't thread-safe, if another thread changes the locale with
698  * setlocale() concurrently. There are two problems with that:
699  *
700  * 1. The pointer returned by localeconv(), or the lc->decimal_point string,
701  * might be invalidated by calls in other threads. Until someone comes up
702  * with a thread-safe version of localeconv(), there isn't much we can do
703  * about that. (libc implementations that return a static buffer (like glibc)
704  * happen to be safe from the lconv struct being invalidated, but the
705  * decimal_point string might still not point to a static buffer).
706  *
707  * 2. The between the call to sprintf() and get_current_decimal_point(), the
708  * decimal point might change. That would cause set_server_decimal_point()
709  * to fail to recognize a decimal separator, and we might send a numeric
710  * string to the server that the server won't recognize. This would cause
711  * the query to fail in the server.
712  *
713  * XXX: we only take into account the first byte of the decimal separator.
714  */
get_current_decimal_point(void)715 static char get_current_decimal_point(void)
716 {
717 	struct lconv	*lc = localeconv();
718 
719 	return lc->decimal_point[0];
720 }
721 
722 /*
723  * Modify the string representation of a numeric/float value, converting the
724  * decimal point from '.' to the correct decimal separator of the current
725  * locale.
726  */
set_server_decimal_point(char * num,SQLLEN len)727 static void set_server_decimal_point(char *num, SQLLEN len)
728 {
729 	char current_decimal_point = get_current_decimal_point();
730 	char *str;
731 	SQLLEN i;
732 
733 	if ('.' == current_decimal_point)
734 		return;
735 	i = 0;
736 	for (str = num; '\0' != *str; str++)
737 	{
738 		if (*str == current_decimal_point)
739 		{
740 			*str = '.';
741 			break;
742 		}
743 
744 		if (len != SQL_NTS && i++ >= len)
745 			break;
746 	}
747 }
748 
749 /*
750  * Inverse of set_server_decimal_point.
751  */
set_client_decimal_point(char * num)752 static void set_client_decimal_point(char *num)
753 {
754 	char current_decimal_point = get_current_decimal_point();
755 	char *str;
756 
757 	if ('.' == current_decimal_point)
758 		return;
759 	for (str = num; '\0' != *str; str++)
760 	{
761 		if (*str == '.')
762 		{
763 			*str = current_decimal_point;
764 			break;
765 		}
766 	}
767 }
768 #else
set_server_decimal_point(char * num)769 static void set_server_decimal_point(char *num) {}
set_client_decimal_point(char * num,BOOL)770 static void set_client_decimal_point(char *num, BOOL) {}
771 #endif /* HAVE_LOCALE_H */
772 
773 /*	This is called by SQLFetch() */
774 int
copy_and_convert_field_bindinfo(StatementClass * stmt,OID field_type,int atttypmod,void * value,int col)775 copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, int atttypmod, void *value, int col)
776 {
777 	ARDFields *opts = SC_get_ARDF(stmt);
778 	BindInfoClass *bic;
779 	SQLULEN	offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
780 
781 	if (opts->allocated <= col)
782 		extend_column_bindings(opts, col + 1);
783 	bic = &(opts->bindings[col]);
784 	SC_set_current_col(stmt, -1);
785 	return copy_and_convert_field(stmt, field_type, atttypmod, value,
786 		bic->returntype, bic->precision,
787 		(PTR) (bic->buffer + offset), bic->buflen,
788 		LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset));
789 }
790 
791 /*
792  * Is 'str' a valid integer literal, consisting only of ASCII characters
793  * 0-9 ?
794  *
795  * Also, *negative is set to TRUE if the value was negative.
796  *
797  * We don't check for overflow here. This is just to decide if we need to
798  * quote the value.
799  */
800 static BOOL
valid_int_literal(const char * str,SQLLEN len,BOOL * negative)801 valid_int_literal(const char *str, SQLLEN len, BOOL *negative)
802 {
803 	SQLLEN i = 0;
804 
805 	/* Check there is a minus sign in front */
806 	if ((len == SQL_NTS || len > 0) && str[0] == '-')
807 	{
808 		i++;
809 		*negative = TRUE;
810 	}
811 	else
812 		*negative = FALSE;
813 
814 	/*
815 	 * Must begin with a digit. This also rejects empty strings and '-'.
816 	 */
817 	if (i == len || !(str[i] >= '0' && str[i] <= '9'))
818 		return FALSE;
819 
820 	for (; str[i] && (len == SQL_NTS || i < len); i++)
821 	{
822 		if (!(str[i] >= '0' && str[i] <= '9'))
823 			return FALSE;
824 	}
825 
826 	return TRUE;
827 }
828 
get_double_value(const char * str)829 static double get_double_value(const char *str)
830 {
831 	if (stricmp(str, NAN_STRING) == 0)
832 #ifdef	NAN
833 		return (double) NAN;
834 #else
835 	{
836 		double	a = .0;
837 		return .0 / a;
838 	}
839 #endif /* NAN */
840 	else if (stricmp(str, INFINITY_STRING) == 0)
841 #ifdef	INFINITY
842 		return (double) INFINITY;
843 #else
844 		return (double) (HUGE_VAL * HUGE_VAL);
845 #endif /* INFINITY */
846 	else if (stricmp(str, MINFINITY_STRING) == 0)
847 #ifdef	INFINITY
848 		return (double) -INFINITY;
849 #else
850 		return (double) -(HUGE_VAL * HUGE_VAL);
851 #endif /* INFINITY */
852 	return atof(str);
853 }
854 
char2guid(const char * str,SQLGUID * g)855 static int char2guid(const char *str, SQLGUID *g)
856 {
857 	/*
858 	 * SQLGUID.Data1 is an "unsigned long" on some platforms, and
859 	 * "unsigned int" on others. For format "%08X", it should be an
860 	 * "unsigned int", so use a temporary variable for it.
861 	 */
862 	unsigned int Data1;
863 	if (sscanf(str,
864 		"%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
865 		&Data1,
866 		&g->Data2, &g->Data3,
867 		&g->Data4[0], &g->Data4[1], &g->Data4[2], &g->Data4[3],
868 		&g->Data4[4], &g->Data4[5], &g->Data4[6], &g->Data4[7]) < 11)
869 		return COPY_GENERAL_ERROR;
870 	g->Data1 = Data1;
871 	return COPY_OK;
872 }
873 
effective_fraction(int fraction,int * width)874 static int	effective_fraction(int fraction, int *width)
875 {
876 	for (*width = 9; fraction % 10 == 0; (*width)--, fraction /= 10)
877 		;
878 	return fraction;
879 }
880 
881 
882 static int
get_terminator_len(SQLSMALLINT fCType)883 get_terminator_len(SQLSMALLINT fCType)
884 {
885 	switch (fCType)
886 	{
887 #ifdef	UNICODE_SUPPORT
888 		case SQL_C_WCHAR:
889 			return WCLEN;
890 #endif /* UNICODE_SUPPORT */
891 		case SQL_C_BINARY:
892 			return 0;
893 	}
894 
895 	/* SQL_C_CHAR or INTERNAL_ASIS_TYPE */
896 	return 1;
897 }
898 
899 static SQLLEN
get_adjust_len(SQLSMALLINT fCType,SQLLEN len)900 get_adjust_len(SQLSMALLINT fCType, SQLLEN len)
901 {
902 	switch (fCType)
903 	{
904 #ifdef	UNICODE_SUPPORT
905 		case SQL_C_WCHAR:
906 			return (len / WCLEN) * WCLEN;
907 #endif /* UNICODE_SUPPORT */
908 	}
909 
910 	return len;
911 }
912 
913 #define	BYTEA_PROCESS_ESCAPE	1
914 #define	BYTEA_PROCESS_BINARY	2
915 
916 static int
setup_getdataclass(SQLLEN * const length_return,const char ** const ptr_return,int * needbuflen_return,GetDataClass * const pgdc,const char * neut_str,const OID field_type,const SQLSMALLINT fCType,const SQLLEN cbValueMax,const ConnectionClass * const conn)917 setup_getdataclass(SQLLEN * const length_return, const char ** const ptr_return,
918 	int *needbuflen_return, GetDataClass * const pgdc, const char *neut_str,
919 	const OID field_type, const SQLSMALLINT fCType,
920 	const SQLLEN cbValueMax, const ConnectionClass * const conn)
921 {
922 	SQLLEN len = (-2);
923 	const char *ptr = NULL;
924 	int	needbuflen = 0;
925 	int	result = COPY_OK;
926 
927 	BOOL	lf_conv = conn->connInfo.lf_conversion;
928 	int	bytea_process_kind = 0;
929 	BOOL	already_processed = FALSE;
930 	BOOL	changed = FALSE;
931 	int	len_for_wcs_term = 0;
932 
933 #ifdef	UNICODE_SUPPORT
934 	char	*allocbuf = NULL;
935 	int	unicode_count = -1;
936 	BOOL	localize_needed = FALSE;
937 	BOOL	hybrid = FALSE;
938 #endif /* UNICODE_SUPPORT */
939 
940 	if (PG_TYPE_BYTEA == field_type)
941 	{
942 		if (SQL_C_BINARY == fCType)
943 			bytea_process_kind = BYTEA_PROCESS_BINARY;
944 		else if (0 == strnicmp(neut_str, "\\x", 2)) /* hex format */
945 			neut_str += 2;
946 		else
947 			bytea_process_kind = BYTEA_PROCESS_ESCAPE;
948 	}
949 
950 #ifdef	UNICODE_SUPPORT
951 	if (0 == bytea_process_kind)
952 	{
953 		if (get_convtype() > 0) /* coversion between the current locale is available */
954 		{
955 			BOOL	wcs_debug = conn->connInfo.wcs_debug;
956 			BOOL	same_encoding = (conn->ccsc == pg_CS_code(conn->locale_encoding));
957 			BOOL	is_utf8 = (UTF8 == conn->ccsc);
958 
959 			switch (field_type)
960 			{
961 				case PG_TYPE_UNKNOWN:
962 				case PG_TYPE_BPCHAR:
963 				case PG_TYPE_VARCHAR:
964 				case PG_TYPE_TEXT:
965 				case PG_TYPE_BPCHARARRAY:
966 				case PG_TYPE_VARCHARARRAY:
967 				case PG_TYPE_TEXTARRAY:
968 					if (SQL_C_CHAR == fCType || SQL_C_BINARY == fCType)
969 						localize_needed = (!same_encoding || wcs_debug);
970 					if (SQL_C_WCHAR == fCType)
971 						hybrid = (!is_utf8 || (same_encoding && wcs_debug));
972 			}
973 			MYLOG(0, "localize=%d hybrid=%d is_utf8=%d same_encoding=%d wcs_debug=%d\n", localize_needed, hybrid, is_utf8, same_encoding, wcs_debug);
974 		}
975 	}
976 	if (fCType == SQL_C_WCHAR)
977 	{
978 		if (BYTEA_PROCESS_ESCAPE == bytea_process_kind)
979 			unicode_count = convert_from_pgbinary(neut_str, NULL, 0) * 2;
980 		else if (hybrid)
981 		{
982 			MYLOG(0, "hybrid estimate\n");
983 			if ((unicode_count = bindcol_hybrid_estimate(neut_str, lf_conv, &allocbuf)) < 0)
984 			{
985 				result = COPY_INVALID_STRING_CONVERSION;
986 				goto cleanup;
987 			}
988 		}
989 		else	/* normally */
990 		{
991 			unicode_count = utf8_to_ucs2_lf(neut_str, SQL_NTS, lf_conv, NULL, 0, FALSE);
992 		}
993 		len = WCLEN * unicode_count;
994 		already_processed = changed = TRUE;
995 	}
996 	else if (localize_needed)
997 	{
998 		if ((len = bindcol_localize_estimate(neut_str, lf_conv, &allocbuf)) < 0)
999 		{
1000 			result = COPY_INVALID_STRING_CONVERSION;
1001 			goto cleanup;
1002 		}
1003 		already_processed = changed = TRUE;
1004 	}
1005 #endif /* UNICODE_SUPPORT */
1006 
1007 	if (already_processed)	/* skip */
1008 		;
1009 	else if (0 != bytea_process_kind)
1010 	{
1011 		len = convert_from_pgbinary(neut_str, NULL, 0);
1012 		if (BYTEA_PROCESS_BINARY != bytea_process_kind)
1013 			len *= 2;
1014 		changed = TRUE;
1015 	}
1016 	else
1017 		/* convert linefeeds to carriage-return/linefeed */
1018 		len = convert_linefeeds(neut_str, NULL, 0, lf_conv, &changed);
1019 
1020 	/* just returns length info */
1021 	if (cbValueMax == 0)
1022 	{
1023 		result = COPY_RESULT_TRUNCATED;
1024 		goto cleanup;
1025 	}
1026 
1027 	if (!pgdc->ttlbuf)
1028 		pgdc->ttlbuflen = 0;
1029 	needbuflen = len + get_terminator_len(fCType);
1030 	if (SQL_C_BINARY == fCType)
1031 	{
1032 		/*
1033 		 * Though Binary doesn't have NULL terminator,
1034 		 * bindcol_localize_exec() needs output buffer
1035 		 * for NULL terminator.
1036 		 */
1037 		len_for_wcs_term = 1;
1038 	}
1039 	if (changed || needbuflen > cbValueMax)
1040 	{
1041 		if (needbuflen > (SQLLEN) pgdc->ttlbuflen)
1042 		{
1043 			pgdc->ttlbuf = realloc(pgdc->ttlbuf, needbuflen + len_for_wcs_term);
1044 			pgdc->ttlbuflen = needbuflen;
1045 		}
1046 
1047 		already_processed = FALSE;
1048 #ifdef	UNICODE_SUPPORT
1049 		if (fCType == SQL_C_WCHAR)
1050 		{
1051 			if (BYTEA_PROCESS_ESCAPE == bytea_process_kind)
1052 			{
1053 				len = convert_from_pgbinary(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen);
1054 				len = pg_bin2whex(pgdc->ttlbuf, (SQLWCHAR *) pgdc->ttlbuf, len);
1055 			}
1056 			else
1057 			{
1058 				if (!hybrid)	/* normally */
1059 					utf8_to_ucs2_lf(neut_str, SQL_NTS, lf_conv, (SQLWCHAR *) pgdc->ttlbuf, unicode_count, FALSE);
1060 				else /* hybrid */
1061 				{
1062 					MYLOG(0, "hybrid convert\n");
1063 					if (bindcol_hybrid_exec((SQLWCHAR *) pgdc->ttlbuf, neut_str, unicode_count + 1, lf_conv, &allocbuf) < 0)
1064 					{
1065 						result = COPY_INVALID_STRING_CONVERSION;
1066 						goto cleanup;
1067 					}
1068 				}
1069 			}
1070 			already_processed = TRUE;
1071 		}
1072 		else if (localize_needed)
1073 		{
1074 			if (bindcol_localize_exec(pgdc->ttlbuf, len + 1, lf_conv, &allocbuf) < 0)
1075 			{
1076 				result = COPY_INVALID_STRING_CONVERSION;
1077 				goto cleanup;
1078 			}
1079 			already_processed = TRUE;
1080 		}
1081 #endif /* UNICODE_SUPPORT */
1082 
1083 		if (already_processed)
1084 			;
1085 		else if (0 != bytea_process_kind)
1086 		{
1087 			len = convert_from_pgbinary(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen);
1088 			if (BYTEA_PROCESS_ESCAPE == bytea_process_kind)
1089 				len = pg_bin2hex(pgdc->ttlbuf, pgdc->ttlbuf, len);
1090 		}
1091 		else
1092 			convert_linefeeds(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen, lf_conv, &changed);
1093 		ptr = pgdc->ttlbuf;
1094 		pgdc->ttlbufused = len;
1095 	}
1096 	else
1097 	{
1098 		if (pgdc->ttlbuf)
1099 		{
1100 			free(pgdc->ttlbuf);
1101 			pgdc->ttlbuf = NULL;
1102 		}
1103 		ptr = neut_str;
1104 	}
1105 cleanup:
1106 #ifdef	UNICODE_SUPPORT
1107 	if (allocbuf)
1108 		free(allocbuf);
1109 #endif /* UNICODE_SUPPORT */
1110 
1111 	*length_return = len;
1112 	*ptr_return = ptr;
1113 	*needbuflen_return = needbuflen;
1114 
1115 	return result;
1116 }
1117 
1118 /*
1119 	gdata		SC_get_GDTI(stmt)
1120 	current_col	stmt->current_col
1121  */
1122 
1123 /*
1124  *	fCType treated in the following function is
1125  *
1126  *	SQL_C_CHAR, SQL_C_BINARY, SQL_C_WCHAR or INTERNAL_ASIS_TYPE
1127  */
1128 static int
convert_text_field_to_sql_c(GetDataInfo * const gdata,const int current_col,const char * const neut_str,const OID field_type,const SQLSMALLINT fCType,char * const rgbValueBindRow,const SQLLEN cbValueMax,const ConnectionClass * const conn,SQLLEN * const length_return)1129 convert_text_field_to_sql_c(GetDataInfo * const gdata, const int current_col,
1130 	const char * const neut_str, const OID field_type,
1131 	const SQLSMALLINT fCType, char * const rgbValueBindRow,
1132 	const SQLLEN cbValueMax, const ConnectionClass * const conn,
1133 	SQLLEN * const length_return)
1134 {
1135 	int	result = COPY_OK;
1136 	SQLLEN	len = (-2);
1137 	GetDataClass *pgdc;
1138 	int	copy_len = 0, needbuflen = 0, i;
1139 	const char	*ptr;
1140 
1141 	MYLOG(0, "field_type=%u type=%d\n", field_type, fCType);
1142 
1143 	switch (field_type)
1144 	{
1145 		case PG_TYPE_FLOAT4:
1146 		case PG_TYPE_FLOAT8:
1147 		case PG_TYPE_NUMERIC:
1148 			set_client_decimal_point((char *) neut_str);
1149 			break;
1150 	}
1151 
1152 	if (current_col < 0)
1153 	{
1154 		pgdc = &(gdata->fdata);
1155 		pgdc->data_left = -1;
1156 	}
1157 	else
1158 		pgdc = &gdata->gdata[current_col];
1159 	if (pgdc->data_left < 0)
1160 	{
1161 		if (COPY_OK != (result = setup_getdataclass(&len, &ptr,
1162 				&needbuflen, pgdc, neut_str, field_type,
1163 				fCType, cbValueMax, conn)))
1164 			goto cleanup;
1165 	}
1166 	else
1167 	{
1168 		ptr = pgdc->ttlbuf;
1169 		len = pgdc->ttlbufused;
1170 	}
1171 
1172 	MYLOG(0, "DEFAULT: len = " FORMAT_LEN ", ptr = '%.*s'\n", len, (int) len, ptr);
1173 
1174 	if (current_col >= 0)
1175 	{
1176 		if (pgdc->data_left > 0)
1177 		{
1178 			ptr += (len - pgdc->data_left);
1179 			len = pgdc->data_left;
1180 			needbuflen = len + (pgdc->ttlbuflen - pgdc->ttlbufused);
1181 		}
1182 		else
1183 			pgdc->data_left = len;
1184 	}
1185 
1186 	if (cbValueMax > 0)
1187 	{
1188 		BOOL	already_copied = FALSE;
1189 		int		terminatorlen;
1190 
1191 		terminatorlen = get_terminator_len(fCType);
1192 		if (terminatorlen >= cbValueMax)
1193 			copy_len = 0;
1194 		else if (len + terminatorlen > cbValueMax)
1195 			copy_len = get_adjust_len(fCType, cbValueMax - terminatorlen);
1196 		else
1197 			copy_len = len;
1198 
1199 		if (!already_copied)
1200 		{
1201 			/* Copy the data */
1202 			if (copy_len > 0)
1203 				memcpy(rgbValueBindRow, ptr, copy_len);
1204 			/* Add null terminator */
1205 			for (i = 0; i < terminatorlen && copy_len + i < cbValueMax; i++)
1206 				rgbValueBindRow[copy_len + i] = '\0';
1207 		}
1208 		/* Adjust data_left for next time */
1209 		if (current_col >= 0)
1210 			pgdc->data_left -= copy_len;
1211 	}
1212 
1213 	/*
1214 	 * Finally, check for truncation so that proper status can
1215 	 * be returned
1216 	 */
1217 	if (cbValueMax > 0 && needbuflen > cbValueMax)
1218 		result = COPY_RESULT_TRUNCATED;
1219 	else
1220 	{
1221 		if (pgdc->ttlbuf != NULL)
1222 		{
1223 			free(pgdc->ttlbuf);
1224 			pgdc->ttlbuf = NULL;
1225 		}
1226 	}
1227 
1228 #ifdef	UNICODE_SUPPORT
1229 	if (SQL_C_WCHAR == fCType)
1230 		MYLOG(0, "    SQL_C_WCHAR, default: len = " FORMAT_LEN ", cbValueMax = " FORMAT_LEN ", rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
1231 	else
1232 #endif /* UNICODE_SUPPORT */
1233 	if (SQL_C_BINARY == fCType)
1234 		MYLOG(0, "    SQL_C_BINARY, default: len = " FORMAT_LEN ", cbValueMax = " FORMAT_LEN ", rgbValueBindRow = '%.*s'\n", len, cbValueMax, copy_len, rgbValueBindRow);
1235 	else
1236 		MYLOG(0, "    SQL_C_CHAR, default: len = " FORMAT_LEN ", cbValueMax = " FORMAT_LEN ", rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
1237 
1238 cleanup:
1239 	*length_return = len;
1240 
1241 	return result;
1242 }
1243 
1244 /*	This is called by SQLGetData() */
1245 int
copy_and_convert_field(StatementClass * stmt,OID field_type,int atttypmod,void * valuei,SQLSMALLINT fCType,int precision,PTR rgbValue,SQLLEN cbValueMax,SQLLEN * pcbValue,SQLLEN * pIndicator)1246 copy_and_convert_field(StatementClass *stmt,
1247 		OID field_type, int atttypmod,
1248 		void *valuei,
1249 		SQLSMALLINT fCType, int precision,
1250 		PTR rgbValue, SQLLEN cbValueMax,
1251 		SQLLEN *pcbValue, SQLLEN *pIndicator)
1252 {
1253 	CSTR func = "copy_and_convert_field";
1254 	const char *value = valuei;
1255 	ARDFields	*opts = SC_get_ARDF(stmt);
1256 	GetDataInfo	*gdata = SC_get_GDTI(stmt);
1257 	SQLLEN		len = 0;
1258 	SIMPLE_TIME std_time;
1259 #ifdef	HAVE_LOCALTIME_R
1260 	struct tm  tm;
1261 #endif /* HAVE_LOCALTIME_R */
1262 	SQLLEN			pcbValueOffset,
1263 				rgbValueOffset;
1264 	char	   *rgbValueBindRow = NULL;
1265 	SQLLEN		*pcbValueBindRow = NULL, *pIndicatorBindRow = NULL;
1266 	SQLSETPOSIROW		bind_row = stmt->bind_row;
1267 	int			bind_size = opts->bind_size;
1268 	int			result = COPY_OK;
1269 	const ConnectionClass	*conn = SC_get_conn(stmt);
1270 	BOOL	text_bin_handling;
1271 	const char *neut_str = value;
1272 	char		booltemp[3];
1273 	char		midtemp[64];
1274 	GetDataClass *pgdc;
1275 
1276 	if (stmt->current_col >= 0)
1277 	{
1278 		if (stmt->current_col >= opts->allocated)
1279 		{
1280 			return SQL_ERROR;
1281 		}
1282 		if (gdata->allocated != opts->allocated)
1283 			extend_getdata_info(gdata, opts->allocated, TRUE);
1284 		pgdc = &gdata->gdata[stmt->current_col];
1285 		if (pgdc->data_left == -2)
1286 			pgdc->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *
1287 						 * needed by ADO ? */
1288 		if (pgdc->data_left == 0)
1289 		{
1290 			if (pgdc->ttlbuf != NULL)
1291 			{
1292 				free(pgdc->ttlbuf);
1293 				pgdc->ttlbuf = NULL;
1294 				pgdc->ttlbuflen = 0;
1295 			}
1296 			pgdc->data_left = -2;		/* needed by ADO ? */
1297 			return COPY_NO_DATA_FOUND;
1298 		}
1299 	}
1300 	/*---------
1301 	 *	rgbValueOffset is *ONLY* for character and binary data.
1302 	 *	pcbValueOffset is for computing any pcbValue location
1303 	 *---------
1304 	 */
1305 
1306 	if (bind_size > 0)
1307 		pcbValueOffset = rgbValueOffset = (bind_size * bind_row);
1308 	else
1309 	{
1310 		pcbValueOffset = bind_row * sizeof(SQLLEN);
1311 		rgbValueOffset = bind_row * cbValueMax;
1312 	}
1313 	/*
1314 	 *	The following is applicable in case bind_size > 0
1315 	 *	or the fCType is of variable length.
1316 	 */
1317 	if (rgbValue)
1318 		rgbValueBindRow = (char *) rgbValue + rgbValueOffset;
1319 	if (pcbValue)
1320 		pcbValueBindRow = LENADDR_SHIFT(pcbValue, pcbValueOffset);
1321 	if (pIndicator)
1322 	{
1323 		pIndicatorBindRow = LENADDR_SHIFT(pIndicator, pcbValueOffset);
1324 		*pIndicatorBindRow = 0;
1325 	}
1326 
1327 	memset(&std_time, 0, sizeof(SIMPLE_TIME));
1328 
1329 	MYLOG(0, "field_type = %d, fctype = %d, value = '%s', cbValueMax=" FORMAT_LEN "\n", field_type, fCType, (value == NULL) ? "<NULL>" : value, cbValueMax);
1330 
1331 	if (!value)
1332 	{
1333 MYLOG(0, "null_cvt_date_string=%d\n", conn->connInfo.cvt_null_date_string);
1334 		/* a speicial handling for FOXPRO NULL -> NULL_STRING */
1335 		if (conn->connInfo.cvt_null_date_string > 0 &&
1336 		    (PG_TYPE_DATE == field_type ||
1337 		     PG_TYPE_DATETIME == field_type ||
1338 		     PG_TYPE_TIMESTAMP_NO_TMZONE == field_type) &&
1339 		    (SQL_C_CHAR == fCType ||
1340 #ifdef	UNICODE_SUPPORT
1341 		     SQL_C_WCHAR == fCType ||
1342 #endif	/* UNICODE_SUPPORT */
1343 		     SQL_C_DATE == fCType ||
1344 		     SQL_C_TYPE_DATE == fCType ||
1345 		     SQL_C_DEFAULT == fCType))
1346 		{
1347 			if (pcbValueBindRow)
1348 				*pcbValueBindRow = 0;
1349 			switch (fCType)
1350 			{
1351 				case SQL_C_CHAR:
1352 					if (rgbValueBindRow && cbValueMax > 0)
1353 						*rgbValueBindRow = '\0';
1354 					else
1355 						result = COPY_RESULT_TRUNCATED;
1356 					break;
1357 				case SQL_C_DATE:
1358 				case SQL_C_TYPE_DATE:
1359 				case SQL_C_DEFAULT:
1360 					if (rgbValueBindRow && cbValueMax >= sizeof(DATE_STRUCT))
1361 					{
1362 						memset(rgbValueBindRow, 0, cbValueMax);
1363 						if (pcbValueBindRow)
1364 							*pcbValueBindRow = sizeof(DATE_STRUCT);
1365 					}
1366 					else
1367 						result = COPY_RESULT_TRUNCATED;
1368 					break;
1369 #ifdef	UNICODE_SUPPORT
1370 				case SQL_C_WCHAR:
1371 					if (rgbValueBindRow && cbValueMax >= WCLEN)
1372 						memset(rgbValueBindRow, 0, WCLEN);
1373 					else
1374 						result = COPY_RESULT_TRUNCATED;
1375 					break;
1376 #endif /* UNICODE_SUPPORT */
1377 			}
1378 			return result;
1379 		}
1380 		/*
1381 		 * handle a null just by returning SQL_NULL_DATA in pcbValue, and
1382 		 * doing nothing to the buffer.
1383 		 */
1384 		else if (pIndicator)
1385 		{
1386 			*pIndicatorBindRow = SQL_NULL_DATA;
1387 			return COPY_OK;
1388 		}
1389 		else
1390 		{
1391 			SC_set_error(stmt, STMT_RETURN_NULL_WITHOUT_INDICATOR, "StrLen_or_IndPtr was a null pointer and NULL data was retrieved", func);
1392 			return	SQL_ERROR;
1393 		}
1394 	}
1395 
1396 	if (stmt->hdbc->DataSourceToDriver != NULL)
1397 	{
1398 		size_t			length = strlen(value);
1399 
1400 		stmt->hdbc->DataSourceToDriver(stmt->hdbc->translation_option,
1401 						SQL_CHAR, valuei, (SDWORD) length,
1402 						valuei, (SDWORD) length, NULL,
1403 						NULL, 0, NULL);
1404 	}
1405 
1406 	/*
1407 	 * First convert any specific postgres types into more useable data.
1408 	 *
1409 	 * NOTE: Conversions from PG char/varchar of a date/time/timestamp value
1410 	 * to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
1411 	 */
1412 	switch (field_type)
1413 	{
1414 			/*
1415 			 * $$$ need to add parsing for date/time/timestamp strings in
1416 			 * PG_TYPE_CHAR,VARCHAR $$$
1417 			 */
1418 		case PG_TYPE_DATE:
1419 			sscanf(value, "%4d-%2d-%2d", &std_time.y, &std_time.m, &std_time.d);
1420 			break;
1421 
1422 		case PG_TYPE_TIME:
1423 			{
1424 
1425 				BOOL	bZone = FALSE;	/* time zone stuff is unreliable */
1426 				int	zone;
1427 				timestamp2stime(value, &std_time, &bZone, &zone);
1428 			}
1429 			break;
1430 
1431 		case PG_TYPE_ABSTIME:
1432 		case PG_TYPE_DATETIME:
1433 		case PG_TYPE_TIMESTAMP_NO_TMZONE:
1434 		case PG_TYPE_TIMESTAMP:
1435 			std_time.fr = 0;
1436 			std_time.infinity = 0;
1437 			if (strnicmp(value, INFINITY_STRING, 8) == 0)
1438 			{
1439 				std_time.infinity = 1;
1440 				std_time.m = 12;
1441 				std_time.d = 31;
1442 				std_time.y = 9999;
1443 				std_time.hh = 23;
1444 				std_time.mm = 59;
1445 				std_time.ss = 59;
1446 			}
1447 			if (strnicmp(value, MINFINITY_STRING, 9) == 0)
1448 			{
1449 				std_time.infinity = -1;
1450 				std_time.m = 1;
1451 				std_time.d = 1;
1452 				// std_time.y = -4713;
1453 				std_time.y = -9999;
1454 				std_time.hh = 0;
1455 				std_time.mm = 0;
1456 				std_time.ss = 0;
1457 			}
1458 			if (strnicmp(value, "invalid", 7) != 0)
1459 			{
1460 				BOOL		bZone = field_type != PG_TYPE_TIMESTAMP_NO_TMZONE;
1461 				int			zone;
1462 
1463 				/*
1464 				 * sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &std_time.y, &std_time.m,
1465 				 * &std_time.d, &std_time.hh, &std_time.mm, &std_time.ss);
1466 				 */
1467 				bZone = FALSE;	/* time zone stuff is unreliable */
1468 				timestamp2stime(value, &std_time, &bZone, &zone);
1469 MYLOG(DETAIL_LOG_LEVEL, "2stime fr=%d\n", std_time.fr);
1470 			}
1471 			else
1472 			{
1473 				/*
1474 				 * The timestamp is invalid so set something conspicuous,
1475 				 * like the epoch
1476 				 */
1477 				struct tm  *tim;
1478 				time_t	t = 0;
1479 #ifdef	HAVE_LOCALTIME_R
1480 				tim = localtime_r(&t, &tm);
1481 #else
1482 				tim = localtime(&t);
1483 #endif /* HAVE_LOCALTIME_R */
1484 				std_time.m = tim->tm_mon + 1;
1485 				std_time.d = tim->tm_mday;
1486 				std_time.y = tim->tm_year + 1900;
1487 				std_time.hh = tim->tm_hour;
1488 				std_time.mm = tim->tm_min;
1489 				std_time.ss = tim->tm_sec;
1490 			}
1491 			break;
1492 
1493 		case PG_TYPE_BOOL:
1494 			{					/* change T/F to 1/0 */
1495 				const ConnInfo *ci = &(conn->connInfo);
1496 
1497 				switch (((char *)value)[0])
1498 				{
1499 					case 'f':
1500 					case 'F':
1501 					case 'n':
1502 					case 'N':
1503 					case '0':
1504 						STRCPY_FIXED(booltemp, "0");
1505 						break;
1506 					default:
1507 						if (ci->true_is_minus1)
1508 							STRCPY_FIXED(booltemp, "-1");
1509 						else
1510 							STRCPY_FIXED(booltemp, "1");
1511 				}
1512 				neut_str = booltemp;
1513 			}
1514 			break;
1515 
1516 			/* This is for internal use by SQLStatistics() */
1517 		case PG_TYPE_INT2VECTOR:
1518 			if (SQL_C_DEFAULT == fCType)
1519 			{
1520 				int	i, nval, maxc;
1521 				const char *vp;
1522 				/* this is an array of eight integers */
1523 				short	   *short_array = (short *) rgbValueBindRow, shortv;
1524 
1525 				maxc = 0;
1526 				if (NULL != short_array)
1527 					maxc = (int) cbValueMax / sizeof(short);
1528 				vp = value;
1529 				nval = 0;
1530 				MYLOG(0, "index=(");
1531 				for (i = 0;; i++)
1532 				{
1533 					if (sscanf(vp, "%hi", &shortv) != 1)
1534 						break;
1535 					MYPRINTF(0, " %hi", shortv);
1536 					nval++;
1537 					if (nval < maxc)
1538 						short_array[i + 1] = shortv;
1539 
1540 					/* skip the current token */
1541 					while (IS_NOT_SPACE(*vp))
1542 						vp++;
1543 					/* and skip the space to the next token */
1544 					while ((*vp != '\0') && (isspace(*vp)))
1545 						vp++;
1546 					if (*vp == '\0')
1547 						break;
1548 				}
1549 				MYPRINTF(0, ") nval = %i\n", nval);
1550 				if (maxc > 0)
1551 					short_array[0] = nval;
1552 
1553 				/* There is no corresponding fCType for this. */
1554 				len = (nval + 1) * sizeof(short);
1555 				if (pcbValue)
1556 					*pcbValueBindRow = len;
1557 
1558 				if (len <= cbValueMax)
1559 					return COPY_OK; /* dont go any further or the data will be
1560 								 * trashed */
1561 				else
1562 					return COPY_RESULT_TRUNCATED;
1563 			}
1564 			break;
1565 
1566 			/*
1567 			 * This is a large object OID, which is used to store
1568 			 * LONGVARBINARY objects.
1569 			 */
1570 		case PG_TYPE_LO_UNDEFINED:
1571 
1572 			return convert_lo(stmt, value, fCType, rgbValueBindRow, cbValueMax, pcbValueBindRow);
1573 
1574 		case 0:
1575 			break;
1576 
1577 		default:
1578 
1579 			if (field_type == stmt->hdbc->lobj_type	/* hack until permanent type available */
1580 			   || (PG_TYPE_OID == field_type && SQL_C_BINARY == fCType && conn->lo_is_domain)
1581 			   )
1582 				return convert_lo(stmt, value, fCType, rgbValueBindRow, cbValueMax, pcbValueBindRow);
1583 	}
1584 
1585 	/* Change default into something useable */
1586 	if (fCType == SQL_C_DEFAULT)
1587 	{
1588 		fCType = pgtype_attr_to_ctype(conn, field_type, atttypmod);
1589 #ifdef	UNICODE_SUPPORT
1590 		if (fCType == SQL_C_WCHAR
1591 		    && CC_default_is_c(conn))
1592 			fCType = SQL_C_CHAR;
1593 #endif
1594 
1595 		MYLOG(0, ", SQL_C_DEFAULT: fCType = %d\n", fCType);
1596 	}
1597 
1598 	text_bin_handling = FALSE;
1599 	switch (fCType)
1600 	{
1601 		case INTERNAL_ASIS_TYPE:
1602 #ifdef	UNICODE_SUPPORT
1603 		case SQL_C_WCHAR:
1604 #endif /* UNICODE_SUPPORT */
1605 		case SQL_C_CHAR:
1606 			text_bin_handling = TRUE;
1607 			break;
1608 		case SQL_C_BINARY:
1609 			switch (field_type)
1610 			{
1611 				case PG_TYPE_UNKNOWN:
1612 				case PG_TYPE_BPCHAR:
1613 				case PG_TYPE_VARCHAR:
1614 				case PG_TYPE_TEXT:
1615 				case PG_TYPE_XML:
1616 				case PG_TYPE_BPCHARARRAY:
1617 				case PG_TYPE_VARCHARARRAY:
1618 				case PG_TYPE_TEXTARRAY:
1619 				case PG_TYPE_XMLARRAY:
1620 				case PG_TYPE_BYTEA:
1621 					text_bin_handling = TRUE;
1622 					break;
1623 			}
1624 			break;
1625 	}
1626 
1627 	if (text_bin_handling)
1628 	{
1629 		BOOL	pre_convert = TRUE;
1630 		int	midsize = sizeof(midtemp);
1631 		int	i;
1632 
1633 		/* Special character formatting as required */
1634 
1635 		/*
1636 		 * These really should return error if cbValueMax is not big
1637 		 * enough.
1638 		 */
1639 		switch (field_type)
1640 		{
1641 			case PG_TYPE_DATE:
1642 				len = SPRINTF_FIXED(midtemp, "%.4d-%.2d-%.2d", std_time.y, std_time.m, std_time.d);
1643 				break;
1644 
1645 			case PG_TYPE_TIME:
1646 				len = SPRINTF_FIXED(midtemp, "%.2d:%.2d:%.2d", std_time.hh, std_time.mm, std_time.ss);
1647 				if (std_time.fr > 0)
1648 				{
1649 					int	wdt;
1650 					int	fr = effective_fraction(std_time.fr, &wdt);
1651 
1652 					len = SPRINTFCAT_FIXED(midtemp, ".%0*d", wdt, fr);
1653 				}
1654 				break;
1655 
1656 			case PG_TYPE_ABSTIME:
1657 			case PG_TYPE_DATETIME:
1658 			case PG_TYPE_TIMESTAMP_NO_TMZONE:
1659 			case PG_TYPE_TIMESTAMP:
1660 				len = stime2timestamp(&std_time, midtemp, midsize, FALSE,
1661 									  (int) (midsize - 19 - 2) );
1662 				break;
1663 
1664 			case PG_TYPE_UUID:
1665 				len = strlen(neut_str);
1666 				for (i = 0; i < len && i < midsize - 2; i++)
1667 					midtemp[i] = toupper((UCHAR) neut_str[i]);
1668 				midtemp[i] = '\0';
1669 				MYLOG(0, "PG_TYPE_UUID: rgbValueBindRow = '%s'\n", rgbValueBindRow);
1670 				break;
1671 
1672 				/*
1673 				 * Currently, data is SILENTLY TRUNCATED for BYTEA and
1674 				 * character data types if there is not enough room in
1675 				 * cbValueMax because the driver can't handle multiple
1676 				 * calls to SQLGetData for these, yet.	Most likely, the
1677 				 * buffer passed in will be big enough to handle the
1678 				 * maximum limit of postgres, anyway.
1679 				 *
1680 				 * LongVarBinary types are handled correctly above, observing
1681 				 * truncation and all that stuff since there is
1682 				 * essentially no limit on the large object used to store
1683 				 * those.
1684 				 */
1685 			case PG_TYPE_BYTEA:/* convert binary data to hex strings
1686 								 * (i.e, 255 = "FF") */
1687 
1688 			default:
1689 				pre_convert = FALSE;
1690 		}
1691 		if (pre_convert)
1692 			neut_str = midtemp;
1693 		result = convert_text_field_to_sql_c(gdata, stmt->current_col, neut_str, field_type, fCType, rgbValueBindRow, cbValueMax, conn, &len);
1694 	}
1695 	else
1696 	{
1697 		SQLGUID g;
1698 
1699 		/*
1700 		 * for SQL_C_CHAR, it's probably ok to leave currency symbols in.
1701 		 * But to convert to numeric types, it is necessary to get rid of
1702 		 * those.
1703 		 */
1704 		if (field_type == PG_TYPE_MONEY)
1705 		{
1706 			if (convert_money(neut_str, midtemp, sizeof(midtemp)))
1707 				neut_str = midtemp;
1708 			else
1709 			{
1710 				MYLOG(0, "couldn't convert money type to %d\n", fCType);
1711 				return COPY_UNSUPPORTED_TYPE;
1712 			}
1713 		}
1714 
1715 		switch (fCType)
1716 		{
1717 			case SQL_C_DATE:
1718 			case SQL_C_TYPE_DATE:		/* 91 */
1719 				len = 6;
1720 				{
1721 					DATE_STRUCT *ds;
1722 					struct tm  *tim;
1723 
1724 					if (bind_size > 0)
1725 						ds = (DATE_STRUCT *) rgbValueBindRow;
1726 					else
1727 						ds = (DATE_STRUCT *) rgbValue + bind_row;
1728 
1729 					/*
1730 					 * Initialize date in case conversion destination
1731 					 * expects date part from this source time data.
1732 					 * A value may be partially set here, so do some
1733 					 * sanity checks on the existing values before
1734 					 * setting them.
1735 					 */
1736 					tim = SC_get_localtime(stmt);
1737 					if (std_time.m == 0)
1738 						std_time.m = tim->tm_mon + 1;
1739 					if (std_time.d == 0)
1740 						std_time.d = tim->tm_mday;
1741 					if (std_time.y == 0)
1742 						std_time.y = tim->tm_year + 1900;
1743 					ds->year = std_time.y;
1744 					ds->month = std_time.m;
1745 					ds->day = std_time.d;
1746 				}
1747 				break;
1748 
1749 			case SQL_C_TIME:
1750 			case SQL_C_TYPE_TIME:		/* 92 */
1751 				len = 6;
1752 				{
1753 					TIME_STRUCT *ts;
1754 
1755 					if (bind_size > 0)
1756 						ts = (TIME_STRUCT *) rgbValueBindRow;
1757 					else
1758 						ts = (TIME_STRUCT *) rgbValue + bind_row;
1759 					ts->hour = std_time.hh;
1760 					ts->minute = std_time.mm;
1761 					ts->second = std_time.ss;
1762 				}
1763 				break;
1764 
1765 			case SQL_C_TIMESTAMP:
1766 			case SQL_C_TYPE_TIMESTAMP:	/* 93 */
1767 				len = 16;
1768 				{
1769 					struct tm  *tim;
1770 					TIMESTAMP_STRUCT *ts;
1771 
1772 					if (bind_size > 0)
1773 						ts = (TIMESTAMP_STRUCT *) rgbValueBindRow;
1774 					else
1775 						ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row;
1776 
1777 					/*
1778 					 * Initialize date in case conversion destination
1779 					 * expects date part from this source time data.
1780 					 * A value may be partially set here, so do some
1781 					 * sanity checks on the existing values before
1782 					 * setting them.
1783 					 */
1784 					tim = SC_get_localtime(stmt);
1785 					if (std_time.m == 0)
1786 						std_time.m = tim->tm_mon + 1;
1787 					if (std_time.d == 0)
1788 						std_time.d = tim->tm_mday;
1789 					if (std_time.y == 0)
1790 						std_time.y = tim->tm_year + 1900;
1791 
1792 					ts->year = std_time.y;
1793 					ts->month = std_time.m;
1794 					ts->day = std_time.d;
1795 					ts->hour = std_time.hh;
1796 					ts->minute = std_time.mm;
1797 					ts->second = std_time.ss;
1798 					ts->fraction = std_time.fr;
1799 				}
1800 				break;
1801 
1802 			case SQL_C_BIT:
1803 				len = 1;
1804 				if (bind_size > 0)
1805 					*((UCHAR *) rgbValueBindRow) = atoi(neut_str);
1806 				else
1807 					*((UCHAR *) rgbValue + bind_row) = atoi(neut_str);
1808 
1809 				 MYLOG(99, "SQL_C_BIT: bind_row = " FORMAT_POSIROW " val = %d, cb = " FORMAT_LEN ", rgb=%d\n",
1810 					bind_row, atoi(neut_str), cbValueMax, *((UCHAR *)rgbValue));
1811 				break;
1812 
1813 			case SQL_C_STINYINT:
1814 			case SQL_C_TINYINT:
1815 				len = 1;
1816 				if (bind_size > 0)
1817 					*((SCHAR *) rgbValueBindRow) = atoi(neut_str);
1818 				else
1819 					*((SCHAR *) rgbValue + bind_row) = atoi(neut_str);
1820 				break;
1821 
1822 			case SQL_C_UTINYINT:
1823 				len = 1;
1824 				if (bind_size > 0)
1825 					*((UCHAR *) rgbValueBindRow) = atoi(neut_str);
1826 				else
1827 					*((UCHAR *) rgbValue + bind_row) = atoi(neut_str);
1828 				break;
1829 
1830 			case SQL_C_FLOAT:
1831 				set_client_decimal_point((char *) neut_str);
1832 				len = 4;
1833 				if (bind_size > 0)
1834 					*((SFLOAT *) rgbValueBindRow) = (float) get_double_value(neut_str);
1835 				else
1836 					*((SFLOAT *) rgbValue + bind_row) = (float) get_double_value(neut_str);
1837 				break;
1838 
1839 			case SQL_C_DOUBLE:
1840 				set_client_decimal_point((char *) neut_str);
1841 				len = 8;
1842 				if (bind_size > 0)
1843 					*((SDOUBLE *) rgbValueBindRow) = get_double_value(neut_str);
1844 				else
1845 					*((SDOUBLE *) rgbValue + bind_row) = get_double_value(neut_str);
1846 				break;
1847 
1848 			case SQL_C_NUMERIC:
1849 				{
1850 					SQL_NUMERIC_STRUCT      *ns;
1851 					BOOL	overflowed;
1852 
1853 					if (bind_size > 0)
1854 						ns = (SQL_NUMERIC_STRUCT *) rgbValueBindRow;
1855 					else
1856 						ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
1857 
1858 					parse_to_numeric_struct(neut_str, ns, &overflowed);
1859 					if (overflowed)
1860 						result = COPY_RESULT_TRUNCATED;
1861 				}
1862 				break;
1863 
1864 			case SQL_C_SSHORT:
1865 			case SQL_C_SHORT:
1866 				len = 2;
1867 				if (bind_size > 0)
1868 					*((SQLSMALLINT *) rgbValueBindRow) = atoi(neut_str);
1869 				else
1870 					*((SQLSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
1871 				break;
1872 
1873 			case SQL_C_USHORT:
1874 				len = 2;
1875 				if (bind_size > 0)
1876 					*((SQLUSMALLINT *) rgbValueBindRow) = atoi(neut_str);
1877 				else
1878 					*((SQLUSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
1879 				break;
1880 
1881 			case SQL_C_SLONG:
1882 			case SQL_C_LONG:
1883 				len = 4;
1884 				if (bind_size > 0)
1885 					*((SQLINTEGER *) rgbValueBindRow) = atol(neut_str);
1886 				else
1887 					*((SQLINTEGER *) rgbValue + bind_row) = atol(neut_str);
1888 				break;
1889 
1890 			case SQL_C_ULONG:
1891 				len = 4;
1892 				if (bind_size > 0)
1893 					*((SQLUINTEGER *) rgbValueBindRow) = ATOI32U(neut_str);
1894 				else
1895 					*((SQLUINTEGER *) rgbValue + bind_row) = ATOI32U(neut_str);
1896 				break;
1897 
1898 #ifdef ODBCINT64
1899 			case SQL_C_SBIGINT:
1900 				len = 8;
1901 				if (bind_size > 0)
1902 					*((SQLBIGINT *) rgbValueBindRow) = ATOI64(neut_str);
1903 				else
1904 					*((SQLBIGINT *) rgbValue + bind_row) = ATOI64(neut_str);
1905 				break;
1906 
1907 			case SQL_C_UBIGINT:
1908 				len = 8;
1909 				if (bind_size > 0)
1910 					*((SQLUBIGINT *) rgbValueBindRow) = ATOI64U(neut_str);
1911 				else
1912 					*((SQLUBIGINT *) rgbValue + bind_row) = ATOI64U(neut_str);
1913 				break;
1914 
1915 #endif /* ODBCINT64 */
1916 			case SQL_C_BINARY:
1917 				/* The following is for SQL_C_VARBOOKMARK */
1918 				if (PG_TYPE_INT4 == field_type)
1919 				{
1920 					UInt4	ival = ATOI32U(neut_str);
1921 
1922 MYLOG(DETAIL_LOG_LEVEL, "SQL_C_VARBOOKMARK value=%d\n", ival);
1923 					if (pcbValue)
1924 						*pcbValueBindRow = sizeof(ival);
1925 					if (cbValueMax >= sizeof(ival))
1926 					{
1927 						memcpy(rgbValueBindRow, &ival, sizeof(ival));
1928 						return COPY_OK;
1929 					}
1930 					else
1931 						return COPY_RESULT_TRUNCATED;
1932 				}
1933 				else if (PG_TYPE_UUID == field_type)
1934 				{
1935 					int rtn = char2guid(neut_str, &g);
1936 
1937 					if (COPY_OK != rtn)
1938 						return rtn;
1939 					if (pcbValue)
1940 						*pcbValueBindRow = sizeof(g);
1941 					if (cbValueMax >= sizeof(g))
1942 					{
1943 						memcpy(rgbValueBindRow, &g, sizeof(g));
1944 						return COPY_OK;
1945 					}
1946 					else
1947 						return COPY_RESULT_TRUNCATED;
1948 				}
1949 				else
1950 				{
1951 					MYLOG(0, "couldn't convert the type %d to SQL_C_BINARY\n", field_type);
1952 					return COPY_UNSUPPORTED_TYPE;
1953 				}
1954 				break;
1955 			case SQL_C_GUID:
1956 
1957 				result = char2guid(neut_str, &g);
1958 				if (COPY_OK != result)
1959 				{
1960 					MYLOG(0, "Could not convert to SQL_C_GUID\n");
1961 					return	COPY_UNSUPPORTED_TYPE;
1962 				}
1963 				len = sizeof(g);
1964 				if (bind_size > 0)
1965 					*((SQLGUID *) rgbValueBindRow) = g;
1966 				else
1967 					*((SQLGUID *) rgbValue + bind_row) = g;
1968 				break;
1969 			case SQL_C_INTERVAL_YEAR:
1970 			case SQL_C_INTERVAL_MONTH:
1971 			case SQL_C_INTERVAL_YEAR_TO_MONTH:
1972 			case SQL_C_INTERVAL_DAY:
1973 			case SQL_C_INTERVAL_HOUR:
1974 			case SQL_C_INTERVAL_DAY_TO_HOUR:
1975 			case SQL_C_INTERVAL_MINUTE:
1976 			case SQL_C_INTERVAL_HOUR_TO_MINUTE:
1977 			case SQL_C_INTERVAL_SECOND:
1978 			case SQL_C_INTERVAL_DAY_TO_SECOND:
1979 			case SQL_C_INTERVAL_HOUR_TO_SECOND:
1980 			case SQL_C_INTERVAL_MINUTE_TO_SECOND:
1981 				interval2istruct(fCType, precision, neut_str, bind_size > 0 ? (SQL_INTERVAL_STRUCT *) rgbValueBindRow : (SQL_INTERVAL_STRUCT *) rgbValue + bind_row);
1982 				break;
1983 
1984 			default:
1985 				MYLOG(0, "conversion to the type %d isn't supported\n", fCType);
1986 				return COPY_UNSUPPORTED_TYPE;
1987 		}
1988 	}
1989 
1990 	/* store the length of what was copied, if there's a place for it */
1991 	if (pcbValue)
1992 		*pcbValueBindRow = len;
1993 
1994 	if (result == COPY_OK && stmt->current_col >= 0)
1995 		gdata->gdata[stmt->current_col].data_left = 0;
1996 	return result;
1997 
1998 }
1999 
2000 
2001 /*--------------------------------------------------------------------
2002  *	Functions/Macros to get rid of query size limit.
2003  *
2004  *	I always used the follwoing macros to convert from
2005  *	old_statement to new_statement.  Please improve it
2006  *	if you have a better way.	Hiroshi 2001/05/22
2007  *--------------------------------------------------------------------
2008  */
2009 
2010 #define	FLGP_USING_CURSOR	(1L << 1)
2011 #define	FLGP_SELECT_INTO		(1L << 2)
2012 #define	FLGP_SELECT_FOR_UPDATE_OR_SHARE	(1L << 3)
2013 #define	FLGP_MULTIPLE_STATEMENT	(1L << 5)
2014 #define	FLGP_SELECT_FOR_READONLY	(1L << 6)
2015 typedef struct _QueryParse {
2016 	const char	*statement;
2017 	int		statement_type;
2018 	size_t		opos;
2019 	ssize_t		from_pos;
2020 	ssize_t		where_pos;
2021 	ssize_t		stmt_len;
2022 	int		in_status;
2023 	char		escape_in_literal, prev_token_end;
2024 	const	char *dollar_tag;
2025 	ssize_t		taglen;
2026 	char		token_curr[64];
2027 	int		token_len;
2028 	size_t		declare_pos;
2029 	UInt4		flags, comment_level;
2030 	encoded_str	encstr;
2031 }	QueryParse;
2032 
2033 static void
QP_initialize(QueryParse * q,const StatementClass * stmt)2034 QP_initialize(QueryParse *q, const StatementClass *stmt)
2035 {
2036 	q->statement = stmt->statement;
2037 	q->statement_type = stmt->statement_type;
2038 	q->opos = 0;
2039 	q->from_pos = -1;
2040 	q->where_pos = -1;
2041 	q->stmt_len = (q->statement) ? strlen(q->statement) : -1;
2042 	q->in_status = 0;
2043 	q->escape_in_literal = '\0';
2044 	q->dollar_tag = NULL;
2045 	q->taglen = -1;
2046 	q->token_curr[0] = '\0';
2047 	q->token_len = 0;
2048 	q->prev_token_end = TRUE;
2049 	q->declare_pos = 0;
2050 	q->flags = 0;
2051 	q->comment_level = 0;
2052 	make_encoded_str(&q->encstr, SC_get_conn(stmt), q->statement);
2053 }
2054 
2055 enum {
2056 	QP_IN_IDENT_KEYWORD = 1L	/* identifier or keyword */
2057 	, QP_IN_DQUOTE_IDENTIFIER = (1L << 1) /* "" */
2058 	, QP_IN_LITERAL = (1L << 2)	/* '' */
2059 	, QP_IN_ESCAPE = (1L << 3)	/* \ in literal */
2060 	, QP_IN_DOLLAR_QUOTE = (1L << 4) /* $...$    $...$ */
2061 	, QP_IN_COMMENT_BLOCK = (1L << 5)	 /* slash asterisk */
2062 	, QP_IN_LINE_COMMENT = (1L << 6) /* -- */
2063 };
2064 
2065 #define	QP_in_idle_status(qp)	((qp)->in_status == 0)
2066 
2067 #define	QP_is_in(qp, status)	(((qp)->in_status & status) != 0)
2068 #define	QP_enter(qp, status)	((qp)->in_status |= status)
2069 #define	QP_exit(qp, status)	((qp)->in_status &= (~status))
2070 
2071 /*
2072  * ResolveOneParam can be work in these four modes:
2073  *
2074  * RPM_REPLACE_PARAMS
2075  *      Replace parameter markers with their values.
2076  *
2077  * RPM_FAKE_PARAMS
2078  *      The query is going to be sent to the server only to be able to
2079  *      Describe the result set. Parameter markers are replaced with NULL
2080  *      literals if we don't know their real values yet.
2081  *
2082  * RPM_BUILDING_PREPARE_STATEMENT
2083  *      Building a query suitable for PREPARE statement, or server-side Parse.
2084  *      Parameter markers are replaced with $n-style parameter markers.
2085  *
2086  * RPM_BUILDING_BIND_REQUEST
2087  *      Building the actual parameter values to send to the server in a Bind
2088  *      request. Return an unescaped value that will be accepted by the
2089  *      server's input function.
2090  */
2091 typedef enum
2092 {
2093 	RPM_REPLACE_PARAMS,
2094 	RPM_FAKE_PARAMS,
2095 	RPM_BUILDING_PREPARE_STATEMENT,
2096 	RPM_BUILDING_BIND_REQUEST
2097 } ResolveParamMode;
2098 
2099 #define	FLGB_INACCURATE_RESULT	(1L << 4)
2100 #define	FLGB_CREATE_KEYSET	(1L << 5)
2101 #define	FLGB_KEYSET_DRIVEN	(1L << 6)
2102 #define	FLGB_CONVERT_LF		(1L << 7)
2103 #define	FLGB_DISCARD_OUTPUT	(1L << 8)
2104 #define	FLGB_BINARY_AS_POSSIBLE	(1L << 9)
2105 #define	FLGB_LITERAL_EXTENSION	(1L << 10)
2106 #define	FLGB_HEX_BIN_FORMAT	(1L << 11)
2107 #define	FLGB_PARAM_CAST		(1L << 12)
2108 typedef struct _QueryBuild {
2109 	char   *query_statement;
2110 	size_t	str_alsize;
2111 	size_t	npos;
2112 	SQLLEN	current_row;
2113 	Int2	param_number;
2114 	Int2	dollar_number;
2115 	Int2	num_io_params;
2116 	Int2	num_output_params;
2117 	Int2	num_discard_params;
2118 	Int2	proc_return;
2119 	Int2	brace_level;
2120 	char	parenthesize_the_first;
2121 	APDFields *apdopts;
2122 	IPDFields *ipdopts;
2123 	PutDataInfo *pdata;
2124 	size_t	load_stmt_len;
2125 	size_t	load_from_pos;
2126 	ResolveParamMode param_mode;
2127 	UInt4	flags;
2128 	int	ccsc;
2129 	int	errornumber;
2130 	const char *errormsg;
2131 
2132 	ConnectionClass	*conn; /* mainly needed for LO handling */
2133 	StatementClass	*stmt; /* needed to set error info in ENLARGE_.. */
2134 }	QueryBuild;
2135 
2136 #define INIT_MIN_ALLOC	4096
2137 static ssize_t
QB_initialize(QueryBuild * qb,size_t size,StatementClass * stmt,ResolveParamMode param_mode)2138 QB_initialize(QueryBuild *qb, size_t size, StatementClass *stmt, ResolveParamMode param_mode)
2139 {
2140 	size_t	newsize = 0;
2141 
2142 	qb->param_mode = param_mode;
2143 	qb->flags = 0;
2144 	qb->load_stmt_len = 0;
2145 	qb->load_from_pos = 0;
2146 	qb->stmt = stmt;
2147 	qb->apdopts = NULL;
2148 	qb->ipdopts = NULL;
2149 	qb->pdata = NULL;
2150 	qb->proc_return = 0;
2151 	qb->num_io_params = 0;
2152 	qb->num_output_params = 0;
2153 	qb->num_discard_params = 0;
2154 	qb->brace_level = 0;
2155 	qb->parenthesize_the_first = FALSE;
2156 
2157 	/* Copy options from statement */
2158 	qb->apdopts = SC_get_APDF(stmt);
2159 	qb->ipdopts = SC_get_IPDF(stmt);
2160 	qb->pdata = SC_get_PDTI(stmt);
2161 	qb->conn = SC_get_conn(stmt);
2162 	if (stmt->discard_output_params)
2163 		qb->flags |= FLGB_DISCARD_OUTPUT;
2164 	qb->num_io_params = CountParameters(stmt, NULL, NULL, &qb->num_output_params);
2165 	qb->proc_return = stmt->proc_return;
2166 	if (0 != (qb->flags & FLGB_DISCARD_OUTPUT))
2167 		qb->num_discard_params = qb->num_output_params;
2168 	if (qb->num_discard_params < qb->proc_return)
2169 		qb->num_discard_params = qb->proc_return;
2170 
2171 	/* Copy options from connection */
2172 	if (qb->conn->connInfo.lf_conversion)
2173 		qb->flags |= FLGB_CONVERT_LF;
2174 	qb->ccsc = qb->conn->ccsc;
2175 	if (CC_get_escape(qb->conn) &&
2176 	    PG_VERSION_GE(qb->conn, 8.1))
2177 		qb->flags |= FLGB_LITERAL_EXTENSION;
2178 	if (PG_VERSION_GE(qb->conn, 9.0))
2179 		qb->flags |= FLGB_HEX_BIN_FORMAT;
2180 
2181 	newsize = INIT_MIN_ALLOC;
2182 	while (newsize <= size)
2183 		newsize *= 2;
2184 
2185 	if ((qb->query_statement = malloc(newsize)) == NULL)
2186 	{
2187 		qb->str_alsize = 0;
2188 		return -1;
2189 	}
2190 	qb->query_statement[0] = '\0';
2191 	qb->str_alsize = newsize;
2192 	qb->npos = 0;
2193 	qb->current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
2194 	qb->param_number = -1;
2195 	qb->dollar_number = 0;
2196 	qb->errornumber = 0;
2197 	qb->errormsg = NULL;
2198 
2199 	return newsize;
2200 }
2201 
2202 static int
QB_initialize_copy(QueryBuild * qb_to,const QueryBuild * qb_from,UInt4 size)2203 QB_initialize_copy(QueryBuild *qb_to, const QueryBuild *qb_from, UInt4 size)
2204 {
2205 	memcpy(qb_to, qb_from, sizeof(QueryBuild));
2206 
2207 	if ((qb_to->query_statement = malloc(size)) == NULL)
2208 	{
2209 		qb_to->str_alsize = 0;
2210 		return -1;
2211 	}
2212 	qb_to->query_statement[0] = '\0';
2213 	qb_to->str_alsize = size;
2214 	qb_to->npos = 0;
2215 
2216 	return size;
2217 }
2218 
2219 static void
QB_replace_SC_error(StatementClass * stmt,const QueryBuild * qb,const char * func)2220 QB_replace_SC_error(StatementClass *stmt, const QueryBuild *qb, const char *func)
2221 {
2222 	int	number;
2223 
2224 	if (0 == qb->errornumber)	return;
2225 	if ((number = SC_get_errornumber(stmt)) > 0) return;
2226 	if (number < 0 && qb->errornumber < 0)	return;
2227 	SC_set_error(stmt, qb->errornumber, qb->errormsg, func);
2228 }
2229 
2230 static void
QB_Destructor(QueryBuild * qb)2231 QB_Destructor(QueryBuild *qb)
2232 {
2233 	if (qb->query_statement)
2234 	{
2235 		free(qb->query_statement);
2236 		qb->query_statement = NULL;
2237 		qb->str_alsize = 0;
2238 	}
2239 }
2240 
2241 /*
2242  * New macros (Aceto)
2243  *--------------------
2244  */
2245 
2246 #define F_OldChar(qp) ((qp)->statement[(qp)->opos])
2247 
2248 #define F_OldPtr(qp) ((qp)->statement + (qp)->opos)
2249 
2250 #define F_OldNext(qp) (++(qp)->opos)
2251 
2252 #define F_OldPrior(qp) (--(qp)->opos)
2253 
2254 #define F_OldPos(qp) (qp)->opos
2255 
2256 #define F_ExtractOldTo(qp, buf, ch, maxsize) \
2257 do { \
2258 	size_t	c = 0; \
2259 	while ((qp)->statement[qp->opos] != '\0' && (qp)->statement[qp->opos] != ch) \
2260 	{ \
2261 		if (c >= maxsize) \
2262 			break; \
2263 		buf[c++] = (qp)->statement[qp->opos++];	\
2264 	} \
2265 	if ((qp)->statement[qp->opos] == '\0')	\
2266 		{retval = SQL_ERROR; goto cleanup;} \
2267 	buf[c] = '\0'; \
2268 } while (0)
2269 
2270 #define F_NewChar(qb) (qb->query_statement[(qb)->npos])
2271 
2272 #define F_NewPtr(qb) ((qb)->query_statement + (qb)->npos)
2273 
2274 #define F_NewNext(qb) (++(qb)->npos)
2275 
2276 #define F_NewPos(qb) ((qb)->npos)
2277 
2278 
2279 static int
2280 convert_escape(QueryParse *qp, QueryBuild *qb);
2281 static int
2282 inner_process_tokens(QueryParse *qp, QueryBuild *qb);
2283 static int
2284 ResolveOneParam(QueryBuild *qb, QueryParse *qp, BOOL *isnull, BOOL *usebinary,
2285 				Oid *pgType);
2286 static int
2287 processParameters(QueryParse *qp, QueryBuild *qb,
2288 	size_t *output_count, SQLLEN param_pos[][2]);
2289 static size_t
2290 convert_to_pgbinary(const char *in, char *out, size_t len, QueryBuild *qb);
2291 static BOOL convert_special_chars(QueryBuild *qb, const char *si, size_t used);
2292 
2293 /*
2294  * Enlarge qb->query_statement buffer so that it is at least newsize + 1
2295  * in size.
2296  */
2297 static ssize_t
enlarge_query_statement(QueryBuild * qb,size_t newsize)2298 enlarge_query_statement(QueryBuild *qb, size_t newsize)
2299 {
2300 	size_t	newalsize = INIT_MIN_ALLOC;
2301 	CSTR func = "enlarge_statement";
2302 
2303 	while (newalsize <= newsize)
2304 		newalsize *= 2;
2305 	if (!(qb->query_statement = realloc(qb->query_statement, newalsize)))
2306 	{
2307 		qb->str_alsize = 0;
2308 		if (qb->stmt)
2309 		{
2310 			SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer allocate error in copy_statement_with_parameters", func);
2311 		}
2312 		else
2313 		{
2314 			qb->errormsg = "Query buffer allocate error in copy_statement_with_parameters";
2315 			qb->errornumber = STMT_EXEC_ERROR;
2316 		}
2317 		return 0;
2318 	}
2319 	qb->str_alsize = newalsize;
2320 	return newalsize;
2321 }
2322 
2323 /*----------
2324  *	Enlarge stmt_with_params if necessary.
2325  *----------
2326  */
2327 #define ENLARGE_NEWSTATEMENT(qb, newpos)					\
2328 	do {													\
2329 		if ((newpos) >= (qb)->str_alsize)					\
2330 		{													\
2331 			if (enlarge_query_statement(qb, newpos) <= 0)	\
2332 			{												\
2333 				retval = SQL_ERROR;							\
2334 				goto cleanup;								\
2335 			}												\
2336 		}													\
2337 	} while(0)
2338 
2339 /*----------
2340  *	Terminate the stmt_with_params string with NULL.
2341  *----------
2342  */
2343 #define CVT_TERMINATE(qb) 									\
2344 	do {													\
2345 		if (NULL == (qb)->query_statement)					\
2346 		{													\
2347 			retval = SQL_ERROR;								\
2348 			goto cleanup;									\
2349 		}													\
2350 		(qb)->query_statement[(qb)->npos] = '\0';			\
2351 	} while (0)
2352 
2353 /*----------
2354  *	Append a data.
2355  *----------
2356  */
2357 #define CVT_APPEND_DATA(qb, s, len)							\
2358 	do {													\
2359 		size_t	newpos = (qb)->npos + len;					\
2360 		ENLARGE_NEWSTATEMENT((qb), newpos);					\
2361 		memcpy(&(qb)->query_statement[(qb)->npos], s, len);	\
2362 		(qb)->npos = newpos;								\
2363 		(qb)->query_statement[newpos] = '\0';				\
2364 	} while (0)
2365 
2366 /*----------
2367  *	Append a string.
2368  *----------
2369  */
2370 #define CVT_APPEND_STR(qb, s)								\
2371 	do {													\
2372 		size_t	len = strlen(s);							\
2373 		CVT_APPEND_DATA(qb, s, len);						\
2374 	} while (0)
2375 
2376 /*----------
2377  *	Append a char.
2378  *----------
2379  */
2380 #define CVT_APPEND_CHAR(qb, c)								\
2381 	do {													\
2382 		ENLARGE_NEWSTATEMENT(qb, (qb)->npos + 1);			\
2383 		(qb)->query_statement[(qb)->npos++] = c;			\
2384 	} while (0)
2385 
2386 /*----------
2387  *	Append a binary data.
2388  *	Newly required size may be overestimated currently.
2389  *----------
2390  */
2391 #define CVT_APPEND_BINARY(qb, buf, used)					\
2392 	do {													\
2393 		size_t	newlimit;									\
2394 															\
2395 		newlimit = (qb)->npos;								\
2396 		if (qb->flags & FLGB_HEX_BIN_FORMAT)				\
2397 			newlimit += 2 * used + 4;						\
2398 		else												\
2399 			newlimit += 5 * used;							\
2400 		ENLARGE_NEWSTATEMENT(qb, newlimit);					\
2401 		(qb)->npos += convert_to_pgbinary(buf,				\
2402 										  &qb->query_statement[(qb)->npos], \
2403 										  used, qb);		\
2404 	} while (0)
2405 
2406 /*----------
2407  *
2408  *----------
2409  */
2410 #define CVT_SPECIAL_CHARS(qb, buf, used)					\
2411 	do {													\
2412 		if (!convert_special_chars(qb, buf, used))			\
2413 		{													\
2414 			retval = SQL_ERROR;								\
2415 			goto cleanup;									\
2416 		}													\
2417 	} while (0)
2418 
2419 
2420 static RETCODE
QB_start_brace(QueryBuild * qb)2421 QB_start_brace(QueryBuild *qb)
2422 {
2423 	BOOL	replace_by_parenthesis = TRUE;
2424 	RETCODE	retval = SQL_ERROR;
2425 
2426 	if (0 == qb->brace_level)
2427 	{
2428 		if (0 == F_NewPos(qb))
2429 		{
2430 			qb->parenthesize_the_first = FALSE;
2431 			replace_by_parenthesis = FALSE;
2432 		}
2433 		else
2434 			qb->parenthesize_the_first = TRUE;
2435 	}
2436 	if (replace_by_parenthesis)
2437 		CVT_APPEND_CHAR(qb, '(');
2438 	qb->brace_level++;
2439 	retval = SQL_SUCCESS;
2440 cleanup:
2441 	return retval;
2442 }
2443 
2444 static RETCODE
QB_end_brace(QueryBuild * qb)2445 QB_end_brace(QueryBuild *qb)
2446 {
2447 	BOOL	replace_by_parenthesis = TRUE;
2448 	RETCODE	retval = SQL_ERROR;
2449 
2450 	if (qb->brace_level <= 1 &&
2451 	    !qb->parenthesize_the_first)
2452 		replace_by_parenthesis = FALSE;
2453 	if (replace_by_parenthesis)
2454 		CVT_APPEND_CHAR(qb, ')');
2455 	qb->brace_level--;
2456 	retval = SQL_SUCCESS;
2457 cleanup:
2458 	return retval;
2459 }
2460 
QB_append_space_to_separate_identifiers(QueryBuild * qb,const QueryParse * qp)2461 static RETCODE QB_append_space_to_separate_identifiers(QueryBuild *qb, const QueryParse *qp)
2462 {
2463 	unsigned char	tchar = F_OldChar(qp);
2464 	encoded_str	encstr;
2465 	BOOL		add_space = FALSE;
2466 	RETCODE		retval = SQL_ERROR;
2467 
2468 	if (ODBC_ESCAPE_END != tchar)
2469 		return SQL_SUCCESS;
2470 	encoded_str_constr(&encstr, qb->ccsc, F_OldPtr(qp) + 1);
2471 	tchar = encoded_nextchar(&encstr);
2472 	if (MBCS_NON_ASCII(encstr))
2473 		add_space = TRUE;
2474 	else
2475 	{
2476 		if (isalnum(tchar))
2477 			add_space = TRUE;
2478 		else
2479 		{
2480 			switch (tchar)
2481 			{
2482 				case '_':
2483 				case '$':
2484 					add_space = TRUE;
2485 			}
2486 		}
2487 	}
2488 	if (add_space)
2489 		CVT_APPEND_CHAR(qb, ' ');
2490 	retval = SQL_SUCCESS;
2491 cleanup:
2492 
2493 	return retval;
2494 }
2495 
2496 /*----------
2497  *	Check if the statement is
2498  *	SELECT ... INTO table FROM .....
2499  *	This isn't really a strict check but ...
2500  *----------
2501  */
2502 static BOOL
into_table_from(const char * stmt)2503 into_table_from(const char *stmt)
2504 {
2505 	if (strnicmp(stmt, "into", 4))
2506 		return FALSE;
2507 	stmt += 4;
2508 	while (isspace((UCHAR) *stmt)) stmt++;
2509 	switch (*stmt)
2510 	{
2511 		case '\0':
2512 		case ',':
2513 		case LITERAL_QUOTE:
2514 		case DOLLAR_QUOTE:
2515 			return FALSE;
2516 		case '-':
2517 		case '/':
2518 			return TRUE;
2519 		case IDENTIFIER_QUOTE:	/* double quoted table name ? */
2520 			do
2521 			{
2522 				do {
2523 					++stmt;
2524 				} while (*stmt != IDENTIFIER_QUOTE && *stmt);
2525 				if (*stmt)
2526 					stmt++;
2527 			}
2528 			while (*stmt == IDENTIFIER_QUOTE);
2529 			break;
2530 		default:
2531 			while (IS_NOT_SPACE(*stmt)) stmt++;
2532 			break;
2533 	}
2534 	if (!*stmt)
2535 		return FALSE;
2536 	while (isspace((UCHAR) *stmt)) stmt++;
2537 	if ('/' == *stmt ||
2538 	    '-' == *stmt)
2539 		return TRUE;
2540 	if (strnicmp(stmt, "from", 4))
2541 		return FALSE;
2542 	return TRUE;
2543 }
2544 
2545 /*----------
2546  *	Check if the statement is
2547  *	SELECT ... FOR UPDATE .....
2548  *	This isn't really a strict check but ...
2549  *----------
2550  */
2551 static UInt4
table_for_update_or_share(const char * stmt,size_t * endpos)2552 table_for_update_or_share(const char *stmt, size_t *endpos)
2553 {
2554 	const char *wstmt = stmt;
2555 	int	advance;
2556 	UInt4	flag = 0, zeroflag = 0;
2557 
2558 	while (isspace((UCHAR) *wstmt)) wstmt++;
2559 	if (!*wstmt)
2560 		return 0;
2561 	if (0 == strnicmp(wstmt, "update", advance = 6))
2562 		flag |= FLGP_SELECT_FOR_UPDATE_OR_SHARE;
2563 	else if (0 == strnicmp(wstmt, "share", advance = 5))
2564 		flag |= FLGP_SELECT_FOR_UPDATE_OR_SHARE;
2565 	else if (0 == strnicmp(wstmt, "read", advance = 4))
2566 		flag |= FLGP_SELECT_FOR_READONLY;
2567 	else
2568 	{
2569 		flag |= FLGP_SELECT_FOR_UPDATE_OR_SHARE; /* maybe */
2570 		return flag;
2571 	}
2572 	zeroflag = flag; /* returns flag anyway */
2573 	wstmt += advance;
2574 	if (IS_NOT_SPACE(wstmt[0]))
2575 		return zeroflag;
2576 	else if (0 != (flag & FLGP_SELECT_FOR_READONLY))
2577 	{
2578 		if (IS_NOT_SPACE(wstmt[0]))
2579 			return zeroflag;
2580 		while (isspace((UCHAR) *wstmt)) wstmt++;
2581 		if (!*wstmt)
2582 			return zeroflag;
2583 		if (0 != strnicmp(wstmt, "only", advance = 4))
2584 			return zeroflag;
2585 		wstmt += advance;
2586 	}
2587 	if (IS_NOT_SPACE(wstmt[0]))
2588 		return zeroflag;
2589 	*endpos = wstmt - stmt;
2590 	return flag;
2591 }
2592 
2593 /*----------
2594  *	Check if the statement has OUTER JOIN
2595  *	This isn't really a strict check but ...
2596  *----------
2597  */
2598 static BOOL
check_join(StatementClass * stmt,const char * curptr,size_t curpos)2599 check_join(StatementClass *stmt, const char *curptr, size_t curpos)
2600 {
2601 	const char *wstmt;
2602 	ssize_t	stapos, endpos, tokenwd;
2603 	const int	backstep = 4;
2604 	BOOL	outerj = TRUE;
2605 
2606 	for (endpos = curpos, wstmt = curptr; endpos >= 0 && isspace((UCHAR) *wstmt); endpos--, wstmt--)
2607 		;
2608 	if (endpos < 0)
2609 		return FALSE;
2610 	for (endpos -= backstep, wstmt -= backstep; endpos >= 0 && isspace((UCHAR) *wstmt); endpos--, wstmt--)
2611 		;
2612 	if (endpos < 0)
2613 		return FALSE;
2614 	for (stapos = endpos; stapos >= 0 && IS_NOT_SPACE(*wstmt); stapos--, wstmt--)
2615 		;
2616 	if (stapos < 0 || 0 == *wstmt)
2617 		return FALSE;
2618 	wstmt++;
2619 	switch (tokenwd = endpos - stapos)
2620 	{
2621 		case 4:
2622 			if (strnicmp(wstmt, "FULL", tokenwd) == 0 ||
2623 			    strnicmp(wstmt, "LEFT", tokenwd) == 0)
2624 				break;
2625 			return FALSE;
2626 		case 5:
2627 			if (strnicmp(wstmt, "OUTER", tokenwd) == 0 ||
2628 			    strnicmp(wstmt, "RIGHT", tokenwd) == 0)
2629 				break;
2630 			if (strnicmp(wstmt, "INNER", tokenwd) == 0 ||
2631 			    strnicmp(wstmt, "CROSS", tokenwd) == 0)
2632 			{
2633 				outerj = FALSE;
2634 				break;
2635 			}
2636 			return FALSE;
2637 		default:
2638 			return FALSE;
2639 	}
2640 	if (stmt)
2641 	{
2642 		if (outerj)
2643 			SC_set_outer_join(stmt);
2644 		else
2645 			SC_set_inner_join(stmt);
2646 	}
2647 	return TRUE;
2648 }
2649 
2650 /*----------
2651  *	Check if the statement is
2652  *	INSERT INTO ... () VALUES ()
2653  *	This isn't really a strict check but ...
2654  *----------
2655  */
2656 static BOOL
insert_without_target(const char * stmt,size_t * endpos)2657 insert_without_target(const char *stmt, size_t *endpos)
2658 {
2659 	const char *wstmt = stmt;
2660 
2661 	while (isspace((UCHAR) *wstmt)) wstmt++;
2662 	if (!*wstmt)
2663 		return FALSE;
2664 	if (strnicmp(wstmt, "VALUES", 6))
2665 		return FALSE;
2666 	wstmt += 6;
2667 	if (!wstmt[0] || IS_NOT_SPACE(wstmt[0]))
2668 		return FALSE;
2669 	while (isspace((UCHAR) *wstmt)) wstmt++;
2670 	if (*wstmt != '(' || *(++wstmt) != ')')
2671 		return FALSE;
2672 	wstmt++;
2673 	*endpos = wstmt - stmt;
2674 	return !wstmt[0] || isspace((UCHAR) wstmt[0])
2675 		|| ';' == wstmt[0];
2676 }
2677 
2678 static ProcessedStmt *
buildProcessedStmt(const char * srvquery,ssize_t endp,int num_params)2679 buildProcessedStmt(const char *srvquery, ssize_t endp, int num_params)
2680 {
2681 	ProcessedStmt *pstmt;
2682 	size_t		qlen;
2683 
2684 	qlen = (endp == SQL_NTS) ? strlen(srvquery) : endp;
2685 
2686 	pstmt = malloc(sizeof(ProcessedStmt));
2687 	if (!pstmt)
2688 		return NULL;
2689 
2690 	pstmt->next = NULL;
2691 	pstmt->query = malloc(qlen + 1);
2692 	if (!pstmt->query)
2693 	{
2694 		free(pstmt);
2695 		return NULL;
2696 	}
2697 	memcpy(pstmt->query, srvquery, qlen);
2698 	pstmt->query[qlen] = '\0';
2699 	pstmt->num_params = num_params;
2700 
2701 	return pstmt;
2702 }
2703 
2704 /*
2705  * Process the original SQL query for execution using server-side prepared
2706  * statements.
2707  *
2708  * Split a possible multi-statement query into parts, and replace ?-style
2709  * parameter markers with $n. The resulting queries are stored in a linked
2710  * list in stmt->processed_statements.
2711  *
2712  * If 'fake_params' is true, we will replace ?-style parameter markers with
2713  * fake parameter values instead. This is used when a query's result columns
2714  * have to be described (SQLPrepare+SQLDescribeCol) before executing the
2715  * query, in UseServerSidePrepare=0 mode.
2716  */
2717 RETCODE
prepareParametersNoDesc(StatementClass * stmt,BOOL fake_params,BOOL param_cast)2718 prepareParametersNoDesc(StatementClass *stmt, BOOL fake_params, BOOL param_cast)
2719 {
2720 	CSTR		func = "process_statements";
2721 	RETCODE		retval;
2722 	ConnectionClass *conn = SC_get_conn(stmt);
2723 	char		plan_name[32];
2724 	po_ind_t	multi;
2725 	const char	*orgquery = NULL, *srvquery = NULL;
2726 	ssize_t		endp1, endp2;
2727 	SQLSMALLINT	num_pa = 0, num_p1, num_p2;
2728 	ProcessedStmt *pstmt;
2729 	ProcessedStmt *last_pstmt;
2730 	QueryParse	query_org, *qp;
2731 	QueryBuild	query_crt, *qb;
2732 
2733 MYLOG(DETAIL_LOG_LEVEL, "entering\n");
2734 	qp = &query_org;
2735 	QP_initialize(qp, stmt);
2736 	qb = &query_crt;
2737 	if (QB_initialize(qb, qp->stmt_len, stmt,
2738 					  fake_params ? RPM_FAKE_PARAMS : RPM_BUILDING_PREPARE_STATEMENT) < 0)
2739 	{
2740 		SC_set_errornumber(stmt, STMT_NO_MEMORY_ERROR);
2741 		return SQL_ERROR;
2742 	}
2743 	if (param_cast)
2744 		qb->flags |= FLGB_PARAM_CAST;
2745 
2746 	for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
2747 	{
2748 		retval = inner_process_tokens(qp, qb);
2749 		if (SQL_ERROR == retval)
2750 		{
2751 			QB_replace_SC_error(stmt, qb, func);
2752 			QB_Destructor(qb);
2753 			return retval;
2754 		}
2755 	}
2756 	CVT_TERMINATE(qb);
2757 
2758 	retval = SQL_ERROR;
2759 #define	return	DONT_CALL_RETURN_FROM_HERE???
2760 	if (NAMED_PARSE_REQUEST == SC_get_prepare_method(stmt))
2761 		SPRINTF_FIXED(plan_name, "_PLAN%p", stmt);
2762 	else
2763 		plan_name[0] = '\0';
2764 
2765 	stmt->current_exec_param = 0;
2766 	multi = stmt->multi_statement;
2767 	orgquery = stmt->statement;
2768 	srvquery = qb->query_statement;
2769 
2770 	SC_scanQueryAndCountParams(orgquery, conn, &endp1, &num_p1, &multi, NULL);
2771 	SC_scanQueryAndCountParams(srvquery, conn, &endp2, NULL, NULL, NULL);
2772 	MYLOG(0, "parsed for the first command length=" FORMAT_SSIZE_T "(" FORMAT_SSIZE_T ") num_p=%d\n", endp2, endp1, num_p1);
2773 	pstmt = buildProcessedStmt(srvquery,
2774 							   endp2 < 0 ? SQL_NTS : endp2,
2775 							   fake_params ? 0 : num_p1);
2776 	if (!pstmt)
2777 	{
2778 		SC_set_errornumber(stmt, STMT_NO_MEMORY_ERROR);
2779 		goto cleanup;
2780 	}
2781 	stmt->processed_statements = last_pstmt = pstmt;
2782 	while (multi > 0)
2783 	{
2784 		orgquery += (endp1 + 1);
2785 		srvquery += (endp2 + 1);
2786 		num_pa += num_p1;
2787 		SC_scanQueryAndCountParams(orgquery, conn, &endp1, &num_p1, &multi, NULL);
2788 		SC_scanQueryAndCountParams(srvquery, conn, &endp2, &num_p2, NULL, NULL);
2789 		MYLOG(0, "parsed for the subsequent command length=" FORMAT_SSIZE_T "(" FORMAT_SSIZE_T ") num_p=%d\n", endp2, endp1, num_p1);
2790 		pstmt = buildProcessedStmt(srvquery,
2791 								   endp2 < 0 ? SQL_NTS : endp2,
2792 								   fake_params ? 0 : num_p1);
2793 		if (!pstmt)
2794 		{
2795 			SC_set_errornumber(stmt, STMT_NO_MEMORY_ERROR);
2796 			goto cleanup;
2797 		}
2798 		last_pstmt->next = pstmt;
2799 		last_pstmt = pstmt;
2800 	}
2801 
2802 	SC_set_planname(stmt, plan_name);
2803 	SC_set_prepared(stmt, plan_name[0] ? PREPARING_PERMANENTLY : PREPARING_TEMPORARILY);
2804 
2805 	retval = SQL_SUCCESS;
2806 cleanup:
2807 #undef	return
2808 	stmt->current_exec_param = -1;
2809 	QB_Destructor(qb);
2810 	return retval;
2811 }
2812 
2813 /*
2814  * Describe the parameters and portal for given query.
2815  */
2816 static RETCODE
desc_params_and_sync(StatementClass * stmt)2817 desc_params_and_sync(StatementClass *stmt)
2818 {
2819 	CSTR		func = "desc_params_and_sync";
2820 	RETCODE		retval;
2821 	ConnectionClass *conn = SC_get_conn(stmt);
2822 	QResultClass	*res;
2823 	char	   *plan_name;
2824 	int		func_cs_count = 0;
2825 	SQLSMALLINT	num_pa = 0;
2826 	ProcessedStmt *pstmt;
2827 
2828 MYLOG(DETAIL_LOG_LEVEL, "entering\n");
2829 
2830 	retval = SQL_ERROR;
2831 #define	return	DONT_CALL_RETURN_FROM_HERE???
2832 	ENTER_INNER_CONN_CS(conn, func_cs_count);
2833 
2834 	plan_name = stmt->plan_name ? stmt->plan_name : "";
2835 
2836 	pstmt = stmt->processed_statements;
2837 
2838 	stmt->current_exec_param = 0;
2839 	res = ParseAndDescribeWithLibpq(stmt, plan_name, pstmt->query, pstmt->num_params, "prepare_and_describe", NULL);
2840 	if (res == NULL)
2841 		goto cleanup;
2842 	// SC_set_Result(stmt, res);
2843 	QR_Destructor(stmt->parsed);
2844 	stmt->parsed = res;
2845 	if (!QR_command_maybe_successful(res))
2846 	{
2847 		SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func);
2848 		goto cleanup;
2849 	}
2850 	num_pa = pstmt->num_params;
2851 	for (pstmt = pstmt->next; pstmt; pstmt = pstmt->next)
2852 	{
2853 		if (pstmt->num_params > 0)
2854 		{
2855 			stmt->current_exec_param = num_pa;
2856 
2857 			res = ParseAndDescribeWithLibpq(stmt, plan_name, pstmt->query, pstmt->num_params, "prepare_and_describe", NULL);
2858 			if (res == NULL)
2859 				goto cleanup;
2860 			QR_Destructor(res);
2861 			num_pa += pstmt->num_params;
2862 		}
2863 	}
2864 	retval = SQL_SUCCESS;
2865 cleanup:
2866 #undef	return
2867 	CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
2868 	stmt->current_exec_param = -1;
2869 	return retval;
2870 }
2871 
2872 /*
2873  * Process the original SQL query, and and ask the server describe the
2874  * parameters.
2875  */
prepareParameters(StatementClass * stmt,BOOL fake_params)2876 RETCODE	prepareParameters(StatementClass *stmt, BOOL fake_params)
2877 {
2878 	ConnectionClass *conn = SC_get_conn(stmt);
2879 
2880 	switch (stmt->prepared)
2881 	{
2882 		case PREPARED_TEMPORARILY:
2883 			if (conn->unnamed_prepared_stmt == stmt)
2884 				return SQL_SUCCESS;
2885 			else
2886 				break;
2887 		case NOT_YET_PREPARED:
2888 		case PREPARING_PERMANENTLY:
2889 		case PREPARING_TEMPORARILY:
2890 			break;
2891 		default:
2892 			return SQL_SUCCESS;
2893 	}
2894 
2895 MYLOG(DETAIL_LOG_LEVEL, "calling prepareParameters\n");
2896 
2897 	if (prepareParametersNoDesc(stmt, fake_params, PARSE_PARAM_CAST) == SQL_ERROR)
2898 		return SQL_ERROR;
2899 	return desc_params_and_sync(stmt);
2900 }
2901 
2902 /*
2903  *	This function inserts parameters into an SQL statements.
2904  *	It will also modify a SELECT statement for use with declare/fetch cursors.
2905  *	This function does a dynamic memory allocation to get rid of query size limit!
2906  */
2907 int
copy_statement_with_parameters(StatementClass * stmt,BOOL buildPrepareStatement)2908 copy_statement_with_parameters(StatementClass *stmt, BOOL buildPrepareStatement)
2909 {
2910 	CSTR		func = "copy_statement_with_parameters";
2911 	RETCODE		retval;
2912 	QueryParse	query_org, *qp;
2913 	QueryBuild	query_crt, *qb;
2914 
2915 	char	   *new_statement;
2916 
2917 	ConnectionClass *conn = SC_get_conn(stmt);
2918 	ConnInfo   *ci = &(conn->connInfo);
2919 	const		char *bestitem = NULL;
2920 
2921 MYLOG(DETAIL_LOG_LEVEL, "entering prepared=%d\n", stmt->prepared);
2922 	if (!stmt->statement)
2923 	{
2924 		SC_set_error(stmt, STMT_INTERNAL_ERROR, "No statement string", func);
2925 		return SQL_ERROR;
2926 	}
2927 
2928 	qp = &query_org;
2929 	QP_initialize(qp, stmt);
2930 
2931 	if (stmt->statement_type != STMT_TYPE_SELECT)
2932 	{
2933 		stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
2934 		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2935 	}
2936 	else if (stmt->options.cursor_type == SQL_CURSOR_FORWARD_ONLY)
2937 		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2938 	else if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
2939 	{
2940 		if (SQL_CURSOR_DYNAMIC == stmt->options.cursor_type &&
2941 		    0 == (ci->updatable_cursors & ALLOW_DYNAMIC_CURSORS))
2942 			stmt->options.cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
2943 		if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
2944 		    0 == (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
2945 			stmt->options.cursor_type = SQL_CURSOR_STATIC;
2946 		switch (stmt->options.cursor_type)
2947 		{
2948 			case SQL_CURSOR_DYNAMIC:
2949 			case SQL_CURSOR_KEYSET_DRIVEN:
2950 				if (SC_update_not_ready(stmt))
2951 					parse_statement(stmt, TRUE);
2952 				if (SC_is_updatable(stmt) && stmt->ntab > 0)
2953 				{
2954 					if (bestitem = GET_NAME(stmt->ti[0]->bestitem), NULL == bestitem)
2955 						stmt->options.cursor_type = SQL_CURSOR_STATIC;
2956 				}
2957 				break;
2958 		}
2959 		if (SQL_CURSOR_STATIC == stmt->options.cursor_type)
2960 		{
2961 			if (0 == (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
2962 				stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2963 			else if (SC_update_not_ready(stmt))
2964 				parse_statement(stmt, TRUE);
2965 		}
2966 		if (SC_parsed_status(stmt) == STMT_PARSE_FATAL)
2967 		{
2968 			stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2969 			if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
2970 				stmt->options.cursor_type = SQL_CURSOR_STATIC;
2971 		}
2972 		else if (!stmt->updatable)
2973 		{
2974 			stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2975 			stmt->options.cursor_type = SQL_CURSOR_STATIC;
2976 		}
2977 		else
2978 		{
2979 			qp->from_pos = stmt->from_pos;
2980 			qp->where_pos = stmt->where_pos;
2981 		}
2982 MYLOG(DETAIL_LOG_LEVEL, "type=" FORMAT_UINTEGER " concur=" FORMAT_UINTEGER "\n", stmt->options.cursor_type, stmt->options.scroll_concurrency);
2983 	}
2984 
2985 	SC_miscinfo_clear(stmt);
2986 	/* If the application hasn't set a cursor name, then generate one */
2987 	if (!SC_cursor_is_valid(stmt))
2988 	{
2989 		char	curname[32];
2990 
2991 		SPRINTF_FIXED(curname, "SQL_CUR%p", stmt);
2992 		STRX_TO_NAME(stmt->cursor_name, curname);
2993 	}
2994 	if (stmt->stmt_with_params)
2995 	{
2996 		free(stmt->stmt_with_params);
2997 		stmt->stmt_with_params = NULL;
2998 	}
2999 
3000 	SC_no_fetchcursor(stmt);
3001 	qb = &query_crt;
3002 	qb->query_statement = NULL;
3003 	if (PREPARED_PERMANENTLY == stmt->prepared)
3004 	{
3005 		/* already prepared */
3006 		retval = SQL_SUCCESS;
3007 		goto cleanup;
3008 	}
3009 
3010 	/*
3011 	 * If it's a simple read-only cursor, we use extended query protocol to
3012 	 * Parse it.
3013 	 */
3014 	if (buildPrepareStatement &&
3015 		 SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency)
3016 	{
3017 		/* Nothing to do here. It will be prepared before execution. */
3018 		char		plan_name[32];
3019 		if (NAMED_PARSE_REQUEST == SC_get_prepare_method(stmt))
3020 			SPRINTF_FIXED(plan_name, "_PLAN%p", stmt);
3021 		else
3022 			plan_name[0] = '\0';
3023 
3024 		SC_set_planname(stmt, plan_name);
3025 		SC_set_prepared(stmt, plan_name[0] ? PREPARING_PERMANENTLY : PREPARING_TEMPORARILY);
3026 
3027 		retval = SQL_SUCCESS;
3028 
3029 		goto cleanup;
3030 	}
3031 
3032 	/* Otherwise... */
3033 	if (QB_initialize(qb, qp->stmt_len, stmt, RPM_REPLACE_PARAMS) < 0)
3034 	{
3035 		retval = SQL_ERROR;
3036 		goto cleanup;
3037 	}
3038 	if (SIMPLE_PARAM_CAST)
3039 		qb->flags |= FLGB_PARAM_CAST;
3040 	new_statement = qb->query_statement;
3041 
3042 	/* For selects, prepend a declare cursor to the statement */
3043 	if (SC_may_use_cursor(stmt) && stmt->external)
3044 	{
3045 		const char *opt_scroll = NULL_STRING, *opt_hold = NULL_STRING;
3046 
3047 		if (ci->drivers.use_declarefetch
3048 			 /** && SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency **/
3049 			)
3050 		{
3051 			SC_set_fetchcursor(stmt);
3052 			if (SC_is_with_hold(stmt))
3053 				opt_hold = " with hold";
3054 			if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
3055 				opt_scroll = " scroll";
3056 		}
3057 		if (SC_is_fetchcursor(stmt))
3058 		{
3059 			snprintfcat(new_statement, qb->str_alsize,
3060 				"declare \"%s\"%s cursor%s for ",
3061 				SC_cursor_name(stmt), opt_scroll, opt_hold);
3062 			qb->npos = strlen(new_statement);
3063 			qp->flags |= FLGP_USING_CURSOR;
3064 			qp->declare_pos = qb->npos;
3065 		}
3066 		if (SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
3067 		{
3068 			qb->flags |= FLGB_CREATE_KEYSET;
3069 			if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
3070 				qb->flags |= FLGB_KEYSET_DRIVEN;
3071 		}
3072 	}
3073 
3074 	for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
3075 	{
3076 		retval = inner_process_tokens(qp, qb);
3077 		if (SQL_ERROR == retval)
3078 		{
3079 			QB_replace_SC_error(stmt, qb, func);
3080 			QB_Destructor(qb);
3081 			return retval;
3082 		}
3083 	}
3084 	/* make sure new_statement is always null-terminated */
3085 	CVT_TERMINATE(qb);
3086 
3087 	new_statement = qb->query_statement;
3088 	stmt->statement_type = qp->statement_type;
3089 	if (0 == (qp->flags & FLGP_USING_CURSOR))
3090 		SC_no_fetchcursor(stmt);
3091 #ifdef NOT_USED	/* this seems problematic */
3092 	else if (0 == (qp->flags & (FLGP_SELECT_FOR_UPDATE_OR_SHARE | FLGP_SELECT_FOR_READONLY)) &&
3093 		 0 == stmt->multi_statement &&
3094 		 PG_VERSION_GE(conn, 8.3))
3095 	{
3096 		BOOL	semi_colon_found = FALSE;
3097 		const UCHAR *ptr = NULL, semi_colon = ';';
3098 		int	npos;
3099 
3100 		if (npos = F_NewPos(qb) - 1, npos >= 0)
3101 			ptr = F_NewPtr(qb) - 1;
3102 		for (; npos >= 0 && isspace(*ptr); npos--, ptr--) ;
3103 		if (npos >= 0 && semi_colon == *ptr)
3104 		{
3105 			qb->npos = npos;
3106 			semi_colon_found = TRUE;
3107 		}
3108 		CVT_APPEND_STR(qb, " for read only");
3109 		if (semi_colon_found)
3110 			CVT_APPEND_CHAR(qb, semi_colon);
3111 		CVT_TERMINATE(qb);
3112 	}
3113 #endif /* NOT_USED */
3114 	if (0 != (qp->flags & FLGP_SELECT_INTO) ||
3115 	    0 != (qp->flags & FLGP_MULTIPLE_STATEMENT))
3116 	{
3117 		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3118 	}
3119 	if (0 != (qp->flags & FLGP_SELECT_FOR_UPDATE_OR_SHARE))
3120 	{
3121 		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3122 	}
3123 
3124 	if (conn->DriverToDataSource != NULL)
3125 	{
3126 		size_t			length = strlen(new_statement);
3127 
3128 		conn->DriverToDataSource(conn->translation_option,
3129 					SQL_CHAR, new_statement, (SDWORD) length,
3130 					new_statement, (SDWORD) length, NULL,
3131 					NULL, 0, NULL);
3132 	}
3133 
3134 	if (!stmt->load_statement && qp->from_pos >= 0)
3135 	{
3136 		size_t	npos = qb->load_stmt_len;
3137 
3138 		if (0 == npos)
3139 		{
3140 			npos = qb->npos;
3141 			for (; npos > 0; npos--)
3142 			{
3143 				if (isspace((unsigned char) new_statement[npos - 1]))
3144 					continue;
3145 				if (';' != new_statement[npos - 1])
3146 					break;
3147 			}
3148 			if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
3149 			{
3150 				qb->npos = npos;
3151 				/* ----------
3152 				 * 1st query is for field information
3153 				 * 2nd query is keyset gathering
3154 				 */
3155 				CVT_APPEND_STR(qb, " where ctid = '(0,0)';select \"ctid");
3156 				if (bestitem)
3157 				{
3158 					CVT_APPEND_STR(qb, "\", \"");
3159 					CVT_APPEND_STR(qb, bestitem);
3160 				}
3161 				CVT_APPEND_STR(qb, "\" from ");
3162 				CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5);
3163 			}
3164 		}
3165 		npos -= qp->declare_pos;
3166 		stmt->load_statement = malloc(npos + 1);
3167 		if (!stmt->load_statement)
3168 		{
3169 			retval = SQL_ERROR;
3170 			goto cleanup;
3171 		}
3172 		memcpy(stmt->load_statement, qb->query_statement + qp->declare_pos, npos);
3173 		stmt->load_from_pos = qb->load_from_pos - qp->declare_pos;
3174 		stmt->load_statement[npos] = '\0';
3175 	}
3176 
3177 	stmt->stmt_with_params = qb->query_statement;
3178 	retval = SQL_SUCCESS;
3179 cleanup:
3180 	return retval;
3181 }
3182 
3183 static void
remove_declare_cursor(QueryBuild * qb,QueryParse * qp)3184 remove_declare_cursor(QueryBuild *qb, QueryParse *qp)
3185 {
3186 	qp->flags &= ~FLGP_USING_CURSOR;
3187 	if (qp->declare_pos <= 0)	return;
3188 	memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
3189 	qb->npos -= qp->declare_pos;
3190 	qp->declare_pos = 0;
3191 }
3192 
3193 /*
3194  * When 'tag' starts with dollar-quoted tag, e.g. "$foo$...", return
3195  * the length of the tag (e.g. 5, with the previous example). If there
3196  * is no end-dollar in the string, returns 0. The caller should've checked
3197  * that the string begins with a dollar.
3198  */
3199 size_t
findTag(const char * tag,int ccsc)3200 findTag(const char *tag, int ccsc)
3201 {
3202 	size_t	taglen = 0;
3203 	encoded_str	encstr;
3204 	UCHAR		tchar;
3205 
3206 	encoded_str_constr(&encstr, ccsc, tag + 1);
3207 	for (tchar = encoded_nextchar(&encstr); tchar; tchar = encoded_nextchar(&encstr))
3208 	{
3209 		if (MBCS_NON_ASCII(encstr))
3210 			continue;
3211 		if (DOLLAR_QUOTE == tchar)
3212 		{
3213 			taglen = encstr.pos + 2;
3214 			break;
3215 		}
3216 		if (!isalnum(tchar))
3217 			break;
3218 	}
3219 	return taglen;
3220 }
3221 
3222 int
findIdentifier(const UCHAR * str,int ccsc,const UCHAR ** next_token)3223 findIdentifier(const UCHAR *str, int ccsc, const UCHAR **next_token)
3224 {
3225 	int	slen = -1;
3226 	encoded_str	encstr;
3227 	UCHAR	tchar;
3228 	BOOL	dquote = FALSE;
3229 
3230 	*next_token = NULL;
3231 	encoded_str_constr(&encstr, ccsc, (const char *) str);
3232 	for (tchar = encoded_nextchar(&encstr); tchar; tchar = encoded_nextchar(&encstr))
3233 	{
3234 		if (MBCS_NON_ASCII(encstr))
3235 			continue;
3236 		if (encstr.pos == 0) /* the first character */
3237 		{
3238 			if (dquote = (IDENTIFIER_QUOTE == tchar), dquote)
3239 				continue;
3240 			if (!isalpha(tchar))
3241 			{
3242 				slen = 0;
3243 				if (IS_NOT_SPACE(tchar))
3244 					*next_token = ENCODE_PTR(encstr);
3245 				break;
3246 			}
3247 		}
3248 		if (dquote)
3249 		{
3250 			if (IDENTIFIER_QUOTE == tchar)
3251 			{
3252 				tchar =	encoded_nextchar(&encstr);
3253 				if (IDENTIFIER_QUOTE == tchar)
3254 					continue;
3255 				slen = encstr.pos;
3256 				break;
3257 			}
3258 		}
3259 		else
3260 		{
3261 			if (isalnum(tchar))
3262 				continue;
3263 			switch (tchar)
3264 			{
3265 				case '_':
3266 				case DOLLAR_QUOTE:
3267 					continue;
3268 			}
3269 			slen = encstr.pos;
3270 			if (IS_NOT_SPACE(tchar))
3271 				*next_token = ENCODE_PTR(encstr);
3272 			break;
3273 		}
3274 	}
3275 	if (slen < 0 && !dquote)
3276 		slen = encstr.pos;
3277 	if (NULL == *next_token)
3278 	{
3279 		for (; tchar; tchar = encoded_nextchar(&encstr))
3280 		{
3281 			if (IS_NOT_SPACE((UCHAR) tchar))
3282 			{
3283 				*next_token = ENCODE_PTR(encstr);
3284 				break;
3285 			}
3286 		}
3287 	}
3288 	return slen;
3289 }
3290 
lower_or_remove_dquote(pgNAME nm,const UCHAR * src,int srclen,int ccsc)3291 static pgNAME lower_or_remove_dquote(pgNAME nm, const UCHAR *src, int srclen, int ccsc)
3292 {
3293 	int	i, outlen;
3294 	char *tc;
3295 	UCHAR	tchar;
3296 	BOOL	idQuote;
3297 	encoded_str	encstr;
3298 
3299 	if (nm.name)
3300 		tc = realloc(nm.name, srclen + 1);
3301 	else
3302 		tc = malloc(srclen + 1);
3303 	if (!tc)
3304 	{
3305 		NULL_THE_NAME(nm);
3306 		return nm;
3307 	}
3308 	nm.name = tc;
3309 	idQuote = (src[0] == IDENTIFIER_QUOTE);
3310 	encoded_str_constr(&encstr, ccsc, (const char *) src);
3311 	for (i = 0, tchar = encoded_nextchar(&encstr), outlen = 0; i < srclen; i++, tchar = encoded_nextchar(&encstr))
3312 	{
3313 		if (MBCS_NON_ASCII(encstr))
3314 		{
3315 			tc[outlen++] = tchar;
3316 			continue;
3317 		}
3318 		if (idQuote)
3319 		{
3320 			if (IDENTIFIER_QUOTE == tchar)
3321 			{
3322 				if (0 == i)
3323 					continue;
3324 				if (i == srclen - 1)
3325 					continue;
3326 				i++;
3327 				tchar = encoded_nextchar(&encstr);
3328 			}
3329 			tc[outlen++] = tchar;
3330 		}
3331 		else
3332 		{
3333 			tc[outlen++] = tolower(tchar);
3334 		}
3335 	}
3336 	tc[outlen] = '\0';
3337 	return nm;
3338 }
3339 
3340 int
eatTableIdentifiers(const UCHAR * str,int ccsc,pgNAME * table,pgNAME * schema)3341 eatTableIdentifiers(const UCHAR *str, int ccsc, pgNAME *table, pgNAME *schema)
3342 {
3343 	int	len;
3344 	const UCHAR *next_token;
3345 	const UCHAR *tstr = str;
3346 
3347 	while (isspace(*tstr)) tstr++;
3348 
3349 	if ((len = findIdentifier(tstr, ccsc, &next_token)) <= 0)
3350 		return len;	/* table name doesn't exist */
3351 	if (table)
3352 	{
3353 		if (IDENTIFIER_QUOTE == *tstr)
3354 			*table = lower_or_remove_dquote(*table, tstr, len, ccsc);
3355 		else
3356 			STRN_TO_NAME(*table, tstr, len);
3357 	}
3358 	if (!next_token || '.' != *next_token || (int) (next_token - tstr) != len)
3359 		return (int) (next_token - str); /* table only */
3360 	tstr = next_token + 1;
3361 	if ((len = findIdentifier(tstr, ccsc, &next_token)) <= 0)
3362 		return -1;
3363 	if (table)
3364 	{
3365 		if (schema)
3366 			MOVE_NAME(*schema, *table);
3367 		*table = lower_or_remove_dquote(*table, tstr, len, ccsc);
3368 	}
3369 	if (!next_token || '.' != *next_token || (int) (next_token - tstr) != len)
3370 		return (int) (next_token - str); /* schema.table */
3371 	tstr = next_token + 1;
3372 	if ((len = findIdentifier(tstr, ccsc, &next_token)) <= 0)
3373 		return -1;
3374 	if (table)
3375 	{
3376 		if (schema)
3377 			MOVE_NAME(*schema, *table);
3378 		*table = lower_or_remove_dquote(*table, tstr, len, ccsc);
3379 	}
3380 	return (int) (next_token - str); /* catalog.schema.table */
3381 }
3382 
token_start(QueryParse * qp,char oldchar)3383 static void token_start(QueryParse *qp, char oldchar)
3384 {
3385 	qp->prev_token_end = FALSE;
3386 	qp->token_curr[0] = oldchar;
3387 	qp->token_len = 1;
3388 }
token_finish(QueryParse * qp,char oldchar,char * finished_token)3389 static int token_finish(QueryParse *qp, char oldchar, char *finished_token)
3390 {
3391 	int ret = -1;
3392 	if (!qp->prev_token_end)
3393 	{
3394 		if (oldchar && qp->token_len + 1 < sizeof(qp->token_curr))
3395 			qp->token_curr[qp->token_len++] = oldchar;
3396 		qp->prev_token_end = TRUE;
3397 		qp->token_curr[qp->token_len] = '\0';
3398 		strncpy_null(finished_token, qp->token_curr, sizeof(qp->token_curr));
3399 MYLOG(DETAIL_LOG_LEVEL, "finished token=%s\n", finished_token);
3400 		ret = qp->token_len;
3401 	}
3402 	return ret;
3403 }
3404 
token_restart(QueryParse * qp,char oldchar,char * finished_token)3405 static int token_restart(QueryParse *qp, char oldchar, char *finished_token)
3406 {
3407 	int ret = token_finish(qp, 0, finished_token);
3408 	if (IS_NOT_SPACE(oldchar))
3409 		token_start(qp, oldchar);
3410 
3411 	return ret;
3412 }
3413 
token_continue(QueryParse * qp,char oldchar)3414 static int token_continue(QueryParse *qp, char oldchar)
3415 {
3416 	if (qp->prev_token_end)
3417 		token_start(qp, oldchar);
3418 	else if (qp->token_len + 1 < sizeof(qp->token_curr))
3419 		qp->token_curr[qp->token_len++] = oldchar;
3420 
3421 	return qp->token_len;
3422 }
3423 
3424 /*
3425  *	ParseToken functions
3426  */
3427 typedef struct {
3428 	QueryParse	*qp;
3429 	int		token_len;
3430 	BOOL		curchar_processed;
3431 	unsigned int	in_status;
3432 	char	finished_token[sizeof(((QueryParse *) NULL)->token_curr)];
3433 } ParseToken;
3434 
PT_initialize(ParseToken * pt,QueryParse * qp)3435 static void PT_initialize(ParseToken *pt, QueryParse *qp)
3436 {
3437 	pt->qp = qp;
3438 	pt->token_len = -1;
3439 	pt->curchar_processed = FALSE;
3440 	pt->in_status = 0;
3441 	pt->finished_token[0] = '\0';
3442 }
3443 
PT_token_finish(ParseToken * pt,char oldchar)3444 static int PT_token_finish(ParseToken *pt, char oldchar)
3445 {
3446 	int token_len_tmp;
3447 
3448 	if (pt->curchar_processed)
3449 		return pt->token_len;
3450 	if ((token_len_tmp = token_finish(pt->qp, oldchar, pt->finished_token)) > 0)
3451 	{
3452 		pt->token_len = token_len_tmp;
3453 		pt->in_status = pt->qp->in_status;
3454 	}
3455 	if (oldchar)
3456 		pt->curchar_processed = TRUE;
3457 	return pt->token_len;
3458 }
3459 
PT_token_restart(ParseToken * pt,char oldchar)3460 static int PT_token_restart(ParseToken *pt, char oldchar)
3461 {
3462 	int token_len_tmp;
3463 	unsigned int	in_status_save;
3464 
3465 	if (pt->curchar_processed)
3466 		return pt->token_len;
3467 	in_status_save = pt->qp->in_status;
3468 	if ((token_len_tmp = token_restart(pt->qp, oldchar, pt->finished_token)) > 0)
3469 	{
3470 		pt->token_len = token_len_tmp;
3471 		pt->in_status = in_status_save;
3472 	}
3473 	pt->curchar_processed = TRUE;
3474 	return pt->token_len;
3475 }
3476 
PT_token_continue(ParseToken * pt,char oldchar)3477 static int PT_token_continue(ParseToken *pt, char oldchar)
3478 {
3479 	if (pt->curchar_processed)
3480 		return pt->token_len;
3481 	token_continue(pt->qp, oldchar);
3482 	pt->curchar_processed = TRUE;
3483 	return pt->token_len;
3484 }
3485 #define	PT_TOKEN_IGNORE(pt)	((pt)->curchar_processed = TRUE)
3486 
3487 static int
inner_process_tokens(QueryParse * qp,QueryBuild * qb)3488 inner_process_tokens(QueryParse *qp, QueryBuild *qb)
3489 {
3490 	CSTR func = "inner_process_tokens";
3491 	BOOL	lf_conv = ((qb->flags & FLGB_CONVERT_LF) != 0);
3492 	const char *bestitem = NULL;
3493 
3494 	RETCODE	retval;
3495 	Int4	opos;
3496 	char	   oldchar;
3497 	StatementClass	*stmt = qb->stmt;
3498 	BOOL		isnull;
3499 	BOOL		isbinary;
3500 	Oid			dummy;
3501 	ParseToken	pts, *pt = &pts;
3502 
3503 	PT_initialize(pt, qp);
3504 
3505 	if (stmt->ntab > 0)
3506 		bestitem = GET_NAME(stmt->ti[0]->bestitem);
3507 	opos = (Int4) qp->opos;
3508 	if (opos < 0)
3509 	{
3510 		qb->errornumber = STMT_SEQUENCE_ERROR;
3511 		qb->errormsg = "Function call for inner_process_tokens sequence error";
3512 		return SQL_ERROR;
3513 	}
3514 	if (qp->from_pos == opos)
3515 	{
3516 		if (0 == (qb->flags & FLGB_CREATE_KEYSET))
3517 		{
3518 			qb->errornumber = STMT_SEQUENCE_ERROR;
3519 			qb->errormsg = "Should come here only when handling updatable cursors";
3520 			return SQL_ERROR;
3521 		}
3522 		CVT_APPEND_STR(qb, ", \"ctid");
3523 		if (bestitem)
3524 		{
3525 			CVT_APPEND_STR(qb, "\", \"");
3526 			CVT_APPEND_STR(qb, bestitem);
3527 		}
3528 		CVT_APPEND_STR(qb, "\" ");
3529 		qb->load_from_pos = qb->npos;
3530 	}
3531 	else if (qp->where_pos == opos)
3532 	{
3533 		qb->load_stmt_len = qb->npos;
3534 		if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
3535 		{
3536 			CVT_APPEND_STR(qb, "where ctid = '(0,0)';select \"ctid");
3537 			if (bestitem)
3538 			{
3539 				CVT_APPEND_STR(qb, "\", \"");
3540 				CVT_APPEND_STR(qb, bestitem);
3541 			}
3542 			CVT_APPEND_STR(qb, "\" from ");
3543 			CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5);
3544 		}
3545 	}
3546 	oldchar = encoded_byte_check(&qp->encstr, qp->opos);
3547 	if (MBCS_NON_ASCII(qp->encstr))
3548 	{
3549 		if (QP_in_idle_status(qp))
3550 		{
3551 			PT_token_restart(pt, oldchar); /* placed before QP_enter() */
3552 			QP_enter(qp, QP_IN_IDENT_KEYWORD);	/* identifier */
3553 		}
3554 		else if (qp->token_len > 0)
3555 			PT_token_continue(pt, oldchar);
3556 		CVT_APPEND_CHAR(qb, oldchar);
3557 		return SQL_SUCCESS;
3558 	}
3559 
3560 	/*
3561 	 * From here we are guaranteed to handle a 1-byte character.
3562 	 */
3563 
3564 	if (QP_is_in(qp, QP_IN_IDENT_KEYWORD))	/* identifier or keyword */
3565 	{
3566 		if (isalnum((UCHAR)oldchar) ||
3567 		    DOLLAR_QUOTE == oldchar ||
3568 		    '_' == oldchar)
3569 		{
3570 			CVT_APPEND_CHAR(qb, oldchar);
3571 			PT_token_continue(pt, oldchar);
3572 			return SQL_SUCCESS;
3573 		}
3574 		PT_token_finish(pt, 0); /* placed before QP_exit() */
3575 		QP_exit(qp, QP_IN_IDENT_KEYWORD);
3576 	}
3577 
3578 	if (QP_is_in(qp, QP_IN_ESCAPE))	/* escape in literal check */
3579 	{
3580 		QP_exit(qp, QP_IN_ESCAPE);
3581 		CVT_APPEND_CHAR(qb, oldchar);
3582 		return SQL_SUCCESS;
3583 	}
3584 	else if (QP_is_in(qp, QP_IN_DOLLAR_QUOTE)) /* dollar quote check */
3585 	{
3586 		if (oldchar == DOLLAR_QUOTE)
3587 		{
3588 			if (strncmp(F_OldPtr(qp), qp->dollar_tag, qp->taglen) == 0)
3589 			{
3590 				CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
3591 				qp->opos += (qp->taglen - 1);
3592 				QP_exit(qp, QP_IN_DOLLAR_QUOTE);
3593 				qp->dollar_tag = NULL;
3594 				qp->taglen = -1;
3595 				return SQL_SUCCESS;
3596 			}
3597 		}
3598 		CVT_APPEND_CHAR(qb, oldchar);
3599 		return SQL_SUCCESS;
3600 	}
3601 	else if (QP_is_in(qp, QP_IN_LITERAL)) /* quote check */
3602 	{
3603 		if (oldchar == LITERAL_QUOTE)
3604 		{
3605 			PT_token_finish(pt, oldchar); /* placed before QP_exit() */
3606 			QP_exit(qp, QP_IN_LITERAL);
3607 		}
3608 		else
3609 		{
3610 			PT_token_continue(pt, oldchar);
3611 			if (oldchar == qp->escape_in_literal)
3612 				QP_enter(qp, QP_IN_ESCAPE); /* escape in literal */
3613 		}
3614 		CVT_APPEND_CHAR(qb, oldchar);
3615 		return SQL_SUCCESS;
3616 	}
3617 	else if (QP_is_in(qp, QP_IN_DQUOTE_IDENTIFIER)) /* double quote check */
3618 	{
3619 		if (oldchar == IDENTIFIER_QUOTE)
3620 		{
3621 			PT_token_finish(pt, oldchar); /* placed before QP_exit() */
3622 			QP_exit(qp, QP_IN_DQUOTE_IDENTIFIER);
3623 		}
3624 		else
3625 			PT_token_continue(pt, oldchar);
3626 		CVT_APPEND_CHAR(qb, oldchar);
3627 		return SQL_SUCCESS;
3628 	}
3629 	else if (QP_is_in(qp, QP_IN_COMMENT_BLOCK)) /* comment_level check */
3630 	{
3631 		if ('/' == oldchar &&
3632 		    '*' == F_OldPtr(qp)[1])
3633 		{
3634 			qp->comment_level++;
3635 			QP_enter(qp, QP_IN_COMMENT_BLOCK);
3636 			CVT_APPEND_CHAR(qb, oldchar);
3637 			F_OldNext(qp);
3638 			oldchar = F_OldChar(qp);
3639 		}
3640 		else if ('*' == oldchar &&
3641 			 '/' == F_OldPtr(qp)[1])
3642 		{
3643 			if (--qp->comment_level <= 0)
3644 				QP_exit(qp, QP_IN_COMMENT_BLOCK);
3645 			CVT_APPEND_CHAR(qb, oldchar);
3646 			F_OldNext(qp);
3647 			oldchar = F_OldChar(qp);
3648 		}
3649 		CVT_APPEND_CHAR(qb, oldchar);
3650 		return SQL_SUCCESS;
3651 	}
3652 	else if (QP_is_in(qp, QP_IN_LINE_COMMENT)) /* line comment check */
3653 	{
3654 		if (PG_LINEFEED == oldchar)
3655 			QP_exit(qp, QP_IN_LINE_COMMENT);
3656 		CVT_APPEND_CHAR(qb, oldchar);
3657 		return SQL_SUCCESS;
3658 	}
3659 
3660 	if (!QP_in_idle_status(qp))
3661 	{
3662 		qb->errornumber = STMT_EXEC_ERROR;
3663 		qb->errormsg = "logic error? not in QP_in_idle_status";
3664 		return SQL_ERROR;
3665 	}
3666 
3667 	/*
3668 	 * From here we are guaranteed to be in neither a literal_escape,
3669 	 * a LITREAL_QUOTE nor an IDENTIFIER_QUOTE.
3670 	 */
3671 	/* Squeeze carriage-return/linefeed pairs to linefeed only */
3672 	if (lf_conv &&
3673 		 PG_CARRIAGE_RETURN == oldchar &&
3674 		 qp->opos + 1 < qp->stmt_len &&
3675 		 PG_LINEFEED == qp->statement[qp->opos + 1])
3676 		return SQL_SUCCESS;
3677 
3678 	/*
3679 	 * Handle literals (date, time, timestamp) and ODBC scalar
3680 	 * functions
3681 	 */
3682 	if (oldchar == ODBC_ESCAPE_START)
3683 	{
3684 		PT_token_finish(pt, 0);
3685 		if (SQL_ERROR == convert_escape(qp, qb))
3686 		{
3687 			if (0 == qb->errornumber)
3688 			{
3689 				qb->errornumber = STMT_EXEC_ERROR;
3690 				qb->errormsg = "ODBC escape convert error";
3691 			}
3692 			MYLOG(0, "convert_escape error\n");
3693 			return SQL_ERROR;
3694 		}
3695 		PT_TOKEN_IGNORE(pt);
3696 		return SQL_SUCCESS;
3697 	}
3698 	/* End of an escape sequence */
3699 	else if (oldchar == ODBC_ESCAPE_END)
3700 	{
3701 		PT_token_finish(pt, 0);
3702 		PT_TOKEN_IGNORE(pt);
3703 		return QB_end_brace(qb);
3704 	}
3705 	else if (oldchar == '@' &&
3706 		 strnicmp(F_OldPtr(qp), "@@identity", 10) == 0)
3707 	{
3708 		ConnectionClass	*conn = SC_get_conn(stmt);
3709 		BOOL		converted = FALSE;
3710 		COL_INFO	*coli;
3711 
3712 #ifdef	NOT_USED  /* lastval() isn't always appropriate */
3713 		if (PG_VERSION_GE(conn, 8.1))
3714 		{
3715 			CVT_APPEND_STR(qb, "lastval()");
3716 			converted = TRUE;
3717 		}
3718 		else
3719 #endif /* NOT_USED */
3720 		if (NAME_IS_VALID(conn->tableIns))
3721 		{
3722 			TABLE_INFO	ti, *pti = &ti;
3723 
3724 			memset(&ti, 0, sizeof(ti));
3725 			NAME_TO_NAME(ti.schema_name, conn->schemaIns);
3726 			NAME_TO_NAME(ti.table_name, conn->tableIns);
3727 			getCOLIfromTI(func, conn, qb->stmt, 0, &pti);
3728 			coli = ti.col_info;
3729 			NULL_THE_NAME(ti.schema_name);
3730 			NULL_THE_NAME(ti.table_name);
3731 			if (NULL != coli)
3732 			{
3733 				int	i, num_fields = QR_NumResultCols(coli->result);
3734 				const char *auto_increment;
3735 
3736 				for (i = 0; i < num_fields; i++)
3737 				{
3738 					auto_increment = (const char *) QR_get_value_backend_text(coli->result, i, COLUMNS_AUTO_INCREMENT);
3739 					if (auto_increment && auto_increment[0] == '1')
3740 					{
3741 						converted = TRUE;
3742 						break;
3743 					}
3744 				}
3745 				if (converted)
3746 				{
3747 				        const char *column_def = (const char *) QR_get_value_backend_text(coli->result, i, COLUMNS_COLUMN_DEF);
3748 					if (NULL != column_def &&
3749 					    strncmp(column_def, "nextval", 7) == 0)
3750 					{
3751 						CVT_APPEND_STR(qb, "curr");
3752 						CVT_APPEND_STR(qb, column_def + 4);
3753 					}
3754 					else
3755 					{
3756 						char relcnv[128];
3757 						const char *column_name = (const char *) QR_get_value_backend_text(coli->result, i, COLUMNS_COLUMN_NAME);
3758 
3759 						CVT_APPEND_STR(qb, "currval(pg_get_serial_sequence('");
3760 						if (NAME_IS_VALID(conn->schemaIns))
3761 						{
3762 							CVT_APPEND_STR(qb, identifierEscape((const SQLCHAR *) SAFE_NAME(conn->schemaIns), SQL_NTS, conn, relcnv, sizeof(relcnv), TRUE));
3763 							CVT_APPEND_STR(qb, ".");
3764 						}
3765 						CVT_APPEND_STR(qb, identifierEscape((const SQLCHAR *) SAFE_NAME(conn->tableIns), SQL_NTS, conn, relcnv, sizeof(relcnv), TRUE));
3766 						CVT_APPEND_STR(qb, "','");
3767 						if (NULL != column_name)
3768 							CVT_APPEND_STR(qb, identifierEscape((const SQLCHAR *) column_name, SQL_NTS, conn, relcnv, sizeof(relcnv), FALSE));
3769 						CVT_APPEND_STR(qb, "')::regclass)");
3770 					}
3771 				}
3772 			}
3773 		}
3774 		if (!converted)
3775 			CVT_APPEND_STR(qb, "NULL");
3776 		qp->opos += 10;
3777 		return SQL_SUCCESS;
3778 	}
3779 
3780 	/*
3781 	 * Can you have parameter markers inside of quotes?  I dont think
3782 	 * so. All the queries I've seen expect the driver to put quotes
3783 	 * if needed.
3784 	 */
3785 	else if (oldchar != '?')
3786 	{
3787 		if (oldchar == DOLLAR_QUOTE)
3788 		{
3789 			PT_token_finish(pt, 0);
3790 			qp->taglen = findTag(F_OldPtr(qp), qp->encstr.ccsc);
3791 			if (qp->taglen > 0)
3792 			{
3793 				QP_enter(qp, QP_IN_DOLLAR_QUOTE);
3794 				qp->dollar_tag = F_OldPtr(qp);
3795 				CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
3796 				qp->opos += (qp->taglen - 1);
3797 				return SQL_SUCCESS;
3798 			}
3799 		}
3800 		else if (oldchar == LITERAL_QUOTE)
3801 		{
3802 			PT_token_restart(pt, oldchar); /* placed before QP_enter() */
3803 			QP_enter(qp, QP_IN_LITERAL);
3804 			qp->escape_in_literal = CC_get_escape(qb->conn);
3805 			if (!qp->escape_in_literal)
3806 			{
3807 				if (LITERAL_EXT == F_OldPtr(qp)[-1])
3808 					qp->escape_in_literal = ESCAPE_IN_LITERAL;
3809 			}
3810 		}
3811 		else if (oldchar == IDENTIFIER_QUOTE)
3812 		{
3813 			PT_token_restart(pt, oldchar); /* placed before QP_enter() */
3814 			QP_enter(qp, QP_IN_DQUOTE_IDENTIFIER);
3815 		}
3816 		else if ('/' == oldchar &&
3817 			 '*' == F_OldPtr(qp)[1])
3818 		{
3819 			qp->comment_level++;
3820 			PT_token_finish(pt, 0); /* comments are excluded */
3821 			QP_enter(qp, QP_IN_COMMENT_BLOCK);
3822 			PT_TOKEN_IGNORE(pt);
3823 		}
3824 		else if ('-' == oldchar &&
3825 			 '-' == F_OldPtr(qp)[1])
3826 		{
3827 			PT_token_finish(pt, 0); /* comments are excluded */
3828 			QP_enter(qp, QP_IN_LINE_COMMENT);
3829 			PT_TOKEN_IGNORE(pt);
3830 		}
3831 		else if (oldchar == ';')
3832 		{
3833 			PT_token_restart(pt, 0);
3834 			/*
3835 			 * can't parse multiple statement using protocol V3.
3836 			 * reset the dollar number here in case it is divided
3837 			 * to parse.
3838 			 */
3839 			qb->dollar_number = 0;
3840 			if (0 != (qp->flags & FLGP_USING_CURSOR))
3841 			{
3842 				const char *vp = &(qp->statement[qp->opos + 1]);
3843 
3844 				while (*vp && isspace((unsigned char) *vp))
3845 					vp++;
3846 				if (*vp)	/* multiple statement */
3847 				{
3848 					qp->flags |= FLGP_MULTIPLE_STATEMENT;
3849 					qb->flags &= ~FLGB_KEYSET_DRIVEN;
3850 					remove_declare_cursor(qb, qp);
3851 				}
3852 			}
3853 		}
3854 		else if (isalnum(oldchar))
3855 		{
3856 			PT_token_restart(pt, oldchar); /* placed before QP_enter() */
3857 			QP_enter(qp, QP_IN_IDENT_KEYWORD); /* identifier or keyword */
3858 		}
3859 		else
3860 		{
3861 			/*
3862 			 *	a hack to handle boolean items in VBA
3863 			 *		with MS Access.
3864 			 *	VBA seems to transform the where condition
3865 			 *		a_boolean_item=True
3866 			 *	into
3867 			 *		("a_boolean_item" = 1)
3868 			 *	which causes an ERROR:Operator does not exist boolean = integer .
3869 			 *	So transforms it into
3870 			 *		("a_boolean_item"='1')
3871 			 *	here.
3872 			 */
3873 			if (')' == oldchar &&
3874 			    qb->conn->ms_jet &&
3875 			    1 == qp->token_len &&
3876 			    '1' == qp->token_curr[0] &&
3877 			    8 <= F_OldPos(qp))
3878 			{
3879 				const char *oldptr = F_OldPtr(qp);
3880 				int	oldpos = F_OldPos(qp);
3881 
3882 				if (strncmp(oldptr - 5, "\" =", 3) == 0)
3883 				{
3884 					int	i;
3885 
3886 					for (i = 6; i < oldpos - 1; i++)
3887 					{
3888 						if (oldptr[-i] == '"')
3889 						{
3890 							if (oldptr[-(i+1)] == '(')
3891 							{
3892 								F_NewPtr(qb)[-4] = '=';
3893 								F_NewPtr(qb)[-3] = '\'';
3894 								F_NewPtr(qb)[-2] = '1';
3895 								F_NewPtr(qb)[-1] = '\'';
3896 							}
3897 							break;
3898 						}
3899 					}
3900 				}
3901 			}
3902 			if (!isalnum((UCHAR) oldchar))
3903 			{
3904 				PT_token_restart(pt, oldchar);
3905 			}
3906 			else
3907 				PT_token_continue(pt, oldchar);
3908 		}
3909 
3910 		if (pt->token_len > 0)
3911 			MYLOG(0, "token_len=%d status=%x token=%s\n", pt->token_len, pt->in_status, pt->finished_token);
3912 		if (!pt->curchar_processed)
3913 		{
3914 			MYLOG(0, "Forgot to process ParseToken char=%c status=%u\n", oldchar, qp->in_status);
3915 #ifdef	NOT_USED	/* strict check for debugging */
3916 			qb->errornumber = STMT_EXEC_ERROR;
3917 			qb->errormsg = "Forget to process ParseToken";
3918 			return SQL_ERROR;
3919 #endif /* NOT_USED */
3920 		}
3921 		switch (pt->token_len)
3922 		{
3923 			case 4:
3924 				if (0 != (qp->flags & FLGP_USING_CURSOR) &&
3925 				    into_table_from(&qp->statement[qp->opos - pt->token_len]))
3926 				{
3927 					qp->flags |= FLGP_SELECT_INTO;
3928 					qb->flags &= ~FLGB_KEYSET_DRIVEN;
3929 					qp->statement_type = STMT_TYPE_CREATE;
3930 					remove_declare_cursor(qb, qp);
3931 				}
3932 				else if (stricmp(pt->finished_token, "join") == 0)
3933 					check_join(stmt, F_OldPtr(qp), F_OldPos(qp));
3934 				break;
3935 			case 3:
3936 				if (0 != (qp->flags & FLGP_USING_CURSOR) &&
3937 				    strnicmp(pt->finished_token, "for", 3) == 0)
3938 				{
3939 					UInt4	flg;
3940 					size_t	endpos;
3941 
3942 					flg = table_for_update_or_share(F_OldPtr(qp), &endpos);
3943 					if (0 != (FLGP_SELECT_FOR_UPDATE_OR_SHARE & flg))
3944 					{
3945 						qp->flags |= flg;
3946 						remove_declare_cursor(qb, qp);
3947 					}
3948 					else
3949 						qp->flags |= flg;
3950 				}
3951 				break;
3952 			case 2:
3953 			{
3954 				size_t	endpos;
3955 
3956 				if (STMT_TYPE_INSERT == qp->statement_type &&
3957 				    strnicmp(pt->finished_token, "()", 2) == 0 &&
3958 				    insert_without_target(F_OldPtr(qp), &endpos))
3959 				{
3960 					qb->npos -= 2;
3961 					CVT_APPEND_STR(qb, "DEFAULT VALUES");
3962 					qp->opos += endpos;
3963 					return SQL_SUCCESS;
3964 				}
3965 				break;
3966 			}
3967 			case 1:
3968 			{
3969 				size_t	endpos;
3970 
3971 				if (STMT_TYPE_INSERT == qp->statement_type &&
3972 				    pt->finished_token[0] == '(' &&
3973 				    oldchar == ')' &&
3974 				    insert_without_target(F_OldPtr(qp)+1, &endpos))
3975 				{
3976 					qb->npos --;
3977 					CVT_APPEND_STR(qb, " DEFAULT VALUES");
3978 					qp->opos += endpos;
3979 					return SQL_SUCCESS;
3980 				}
3981 				break;
3982 			}
3983 		}
3984 
3985 		CVT_APPEND_CHAR(qb, oldchar);
3986 		return SQL_SUCCESS;
3987 	}
3988 	else
3989 		PT_token_restart(pt, oldchar);
3990 
3991 	/*
3992 	 * It's a '?' parameter alright
3993 	 */
3994 	retval = ResolveOneParam(qb, qp, &isnull, &isbinary, &dummy);
3995 	if (retval < 0)
3996 		return retval;
3997 
3998 	if (SQL_SUCCESS_WITH_INFO == retval) /* means discarding output parameter */
3999 	{
4000 	}
4001 	retval = SQL_SUCCESS;
4002 cleanup:
4003 	return retval;
4004 }
4005 
4006 #define	MIN_ALC_SIZE	128
4007 
4008 /*
4009  * Build an array of parameters to pass to libpq's PQexecPrepared
4010  * function.
4011  */
4012 BOOL
build_libpq_bind_params(StatementClass * stmt,int * nParams,OID ** paramTypes,char *** paramValues,int ** paramLengths,int ** paramFormats,int * resultFormat)4013 build_libpq_bind_params(StatementClass *stmt,
4014 						int *nParams,
4015 						OID **paramTypes,
4016 						char ***paramValues,
4017 						int **paramLengths,
4018 						int **paramFormats,
4019 						int *resultFormat)
4020 {
4021 	CSTR func = "build_libpq_bind_params";
4022 	QueryBuild	qb;
4023 	SQLSMALLINT	num_p;
4024 	int			i, num_params;
4025 	ConnectionClass	*conn = SC_get_conn(stmt);
4026 	BOOL		ret = FALSE, discard_output;
4027 	RETCODE		retval;
4028 	const		IPDFields *ipdopts = SC_get_IPDF(stmt);
4029 
4030 	*paramTypes = NULL;
4031 	*paramValues = NULL;
4032 	*paramLengths = NULL;
4033 	*paramFormats = NULL;
4034 
4035 	num_params = stmt->num_params;
4036 	if (num_params < 0)
4037 	{
4038 		PGAPI_NumParams(stmt, &num_p);
4039 		num_params = num_p;
4040 	}
4041 	if (ipdopts->allocated < num_params)
4042 	{
4043 		char	tmp[100];
4044 
4045 		if (0 == ipdopts->allocated)
4046 			STRCPY_FIXED(tmp, "Parameters exist but IPD isn't set. Please call SQLDescribeParam()");
4047 		else
4048 			SPRINTF_FIXED(tmp, "The # of IPD parameters %d < %d the # of parameter markers", ipdopts->allocated, num_params);
4049 		MYLOG(0, "%s\n", tmp);
4050 		SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, tmp, func);
4051 		return FALSE;
4052 	}
4053 
4054 	if (QB_initialize(&qb, MIN_ALC_SIZE, stmt, RPM_BUILDING_BIND_REQUEST) < 0)
4055 		return FALSE;
4056 
4057 	if (num_params > 0)
4058 	{
4059 		*paramTypes = malloc(sizeof(OID) * num_params);
4060 		if (*paramTypes == NULL)
4061 			goto cleanup;
4062 		*paramValues = malloc(sizeof(char *) * num_params);
4063 		if (*paramValues == NULL)
4064 			goto cleanup;
4065 		memset(*paramValues, 0, sizeof(char *) * num_params);
4066 		*paramLengths = malloc(sizeof(int) * num_params);
4067 		if (*paramLengths == NULL)
4068 			goto cleanup;
4069 		*paramFormats = malloc(sizeof(int) * num_params);
4070 		if (*paramFormats == NULL)
4071 			goto cleanup;
4072 	}
4073 
4074 	qb.flags |= FLGB_BINARY_AS_POSSIBLE;
4075 
4076 	MYLOG(DETAIL_LOG_LEVEL, "num_params=%d proc_return=%d\n", num_params, stmt->proc_return);
4077 	num_p = num_params - qb.num_discard_params;
4078 MYLOG(DETAIL_LOG_LEVEL, "num_p=%d\n", num_p);
4079 	discard_output = (0 != (qb.flags & FLGB_DISCARD_OUTPUT));
4080 	*nParams = 0;
4081 	if (num_p > 0)
4082 	{
4083 		ParameterImplClass	*parameters = ipdopts->parameters;
4084 		int	pno;
4085 
4086 		BOOL	isnull;
4087 		BOOL	isbinary;
4088 		char	*val_copy;
4089 		OID	pgType;
4090 
4091 		/*
4092 		 * Now build the parameter values.
4093 		 */
4094 		for (i = 0, pno = 0; i < stmt->num_params; i++)
4095 		{
4096 			qb.npos = 0;
4097 			retval = ResolveOneParam(&qb, NULL, &isnull, &isbinary, &pgType);
4098 			if (SQL_ERROR == retval)
4099 			{
4100 				QB_replace_SC_error(stmt, &qb, func);
4101 				ret = FALSE;
4102 				goto cleanup;
4103 			}
4104 
4105 			MYLOG(DETAIL_LOG_LEVEL, "%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(conn, parameters[i]));
4106 
4107 			if (i < qb.proc_return)
4108 				continue;
4109 			if (SQL_PARAM_OUTPUT == parameters[i].paramType)
4110 			{
4111 				if (discard_output)
4112 					continue;
4113 				(*paramTypes)[pno] = PG_TYPE_VOID;
4114 				(*paramValues)[pno] = NULL;
4115 				(*paramLengths)[pno] = 0;
4116 				(*paramFormats)[pno] = 0;
4117 				pno++;
4118 				continue;
4119 			}
4120 			if (!isnull)
4121 			{
4122 				val_copy = malloc(qb.npos + 1);
4123 				if (!val_copy)
4124 					goto cleanup;
4125 				memcpy(val_copy, qb.query_statement, qb.npos);
4126 				val_copy[qb.npos] = '\0';
4127 
4128 				(*paramTypes)[pno] = pgType;
4129 				(*paramValues)[pno] = val_copy;
4130 				if (qb.npos > INT_MAX)
4131 					goto cleanup;
4132 				(*paramLengths)[pno] = (int) qb.npos;
4133 			}
4134 			else
4135 			{
4136 				(*paramTypes)[pno] = pgType;
4137 				(*paramValues)[pno] = NULL;
4138 				(*paramLengths)[pno] = 0;
4139 			}
4140 			if (isbinary)
4141 				MYLOG(0, "%dth parameter is of binary format\n", pno);
4142 			(*paramFormats)[pno] = isbinary ? 1 : 0;
4143 
4144 			pno++;
4145 		}
4146 		*nParams = pno;
4147 	}
4148 
4149 	/* result format is text */
4150 	*resultFormat = 0;
4151 
4152 	ret = TRUE;
4153 
4154 cleanup:
4155 	QB_Destructor(&qb);
4156 
4157 	return ret;
4158 }
4159 
4160 
4161 /*
4162  * With SQL_MAX_NUMERIC_LEN = 16, the highest representable number is
4163  * 2^128 - 1, which fits in 39 digits.
4164  */
4165 #define MAX_NUMERIC_DIGITS 39
4166 
4167 /*
4168  * Convert a SQL_NUMERIC_STRUCT into string representation.
4169  */
4170 static void
ResolveNumericParam(const SQL_NUMERIC_STRUCT * ns,char * chrform)4171 ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
4172 {
4173 	Int4		i, vlen, len, newlen;
4174 	const UCHAR	*val = (const UCHAR *) ns->val;
4175 	UCHAR		vals[SQL_MAX_NUMERIC_LEN];
4176 	int			lastnonzero;
4177 	UCHAR		calv[MAX_NUMERIC_DIGITS];
4178 	int			precision;
4179 
4180 MYLOG(DETAIL_LOG_LEVEL, "C_NUMERIC [prec=%d scale=%d]", ns->precision, ns->scale);
4181 
4182 	if (0 == ns->precision)
4183 	{
4184 		if (chrform)
4185 			strncpy_null(chrform, "0", 2);
4186 		return;
4187 	}
4188 
4189 	precision = ns->precision;
4190 	if (precision > MAX_NUMERIC_DIGITS)
4191 		precision = MAX_NUMERIC_DIGITS;
4192 
4193 	/*
4194 	 * The representation in SQL_NUMERIC_STRUCT is 16 bytes with most
4195 	 * significant byte first. Make a working copy.
4196 	 */
4197 	memcpy(vals, val, SQL_MAX_NUMERIC_LEN);
4198 
4199 	vlen = SQL_MAX_NUMERIC_LEN;
4200 	len = 0;
4201 	do
4202 	{
4203 		UInt2		d, r;
4204 
4205 		/*
4206 		 * Divide the number by 10, and output the reminder as the next digit.
4207 		 *
4208 		 * Begin from the most-significant byte (last in the array), and at
4209 		 * each step, carry the remainder to the prev byte.
4210 		 */
4211 		r = 0;
4212 		lastnonzero = -1;
4213 		for (i = vlen - 1; i >= 0; i--)
4214 		{
4215 			UInt2	v;
4216 
4217 			v = ((UInt2) vals[i]) + (r << 8);
4218 			d = v / 10; r = v % 10;
4219 			vals[i] = (UCHAR) d;
4220 
4221 			if (d != 0 && lastnonzero == -1)
4222 				lastnonzero = i;
4223 		}
4224 
4225 		/* output the remainder */
4226 		calv[len++] = (UCHAR) r;
4227 
4228 		vlen = lastnonzero + 1;
4229 	} while(lastnonzero >= 0 && len < precision);
4230 
4231 	/*
4232 	 * calv now contains the digits in reverse order, i.e. least significant
4233 	 * digit is at calv[0]
4234 	 */
4235 
4236 MYPRINTF(DETAIL_LOG_LEVEL, " len2=%d", len);
4237 
4238 	/* build the final output string. */
4239 	newlen = 0;
4240 	if (0 == ns->sign)
4241 		chrform[newlen++] = '-';
4242 
4243 	i = len - 1;
4244 	if (i < ns->scale)
4245 		i = ns->scale;
4246 	for (; i >= ns->scale; i--)
4247 	{
4248 		if (i >= len)
4249 			chrform[newlen++] = '0';
4250 		else
4251 			chrform[newlen++] = calv[i] + '0';
4252 	}
4253 	if (ns->scale > 0)
4254 	{
4255 		chrform[newlen++] = '.';
4256 		for (; i >= 0; i--)
4257 		{
4258 			if (i >= len)
4259 				chrform[newlen++] = '0';
4260 			else
4261 				chrform[newlen++] = calv[i] + '0';
4262 		}
4263 	}
4264 	if (0 == len)
4265 		chrform[newlen++] = '0';
4266 	chrform[newlen] = '\0';
4267 MYLOG(DETAIL_LOG_LEVEL, " convval(2) len=%d %s\n", newlen, chrform);
4268 }
4269 
4270 /*
4271  * Convert a string representation of a numeric into SQL_NUMERIC_STRUCT.
4272  */
4273 static void
parse_to_numeric_struct(const char * wv,SQL_NUMERIC_STRUCT * ns,BOOL * overflow)4274 parse_to_numeric_struct(const char *wv, SQL_NUMERIC_STRUCT *ns, BOOL *overflow)
4275 {
4276 	int			i, nlen, dig;
4277 	char		calv[SQL_MAX_NUMERIC_LEN * 3];
4278 	BOOL		dot_exist;
4279 
4280 	*overflow = FALSE;
4281 
4282 	/* skip leading space */
4283 	while (*wv && isspace((unsigned char) *wv))
4284 		wv++;
4285 
4286 	/* sign */
4287 	ns->sign = 1;
4288 	if (*wv == '-')
4289 	{
4290 		ns->sign = 0;
4291 		wv++;
4292 	}
4293 	else if (*wv == '+')
4294 		wv++;
4295 
4296 	/* skip leading zeros */
4297 	while (*wv == '0')
4298 		wv++;
4299 
4300 	/* read the digits into calv */
4301 	ns->precision = 0;
4302 	ns->scale = 0;
4303 	for (nlen = 0, dot_exist = FALSE;; wv++)
4304 	{
4305 		if (*wv == '.')
4306 		{
4307 			if (dot_exist)
4308 				break;
4309 			dot_exist = TRUE;
4310 		}
4311 		else if (*wv == '\0' || !isdigit((unsigned char) *wv))
4312 			break;
4313 		else
4314 		{
4315 			if (nlen >= sizeof(calv))
4316 			{
4317 				if (dot_exist)
4318 					break;
4319 				else
4320 				{
4321 					ns->scale--;
4322 					*overflow = TRUE;
4323 					continue;
4324 				}
4325 			}
4326 			if (dot_exist)
4327 				ns->scale++;
4328 			calv[nlen++] = *wv;
4329 		}
4330 	}
4331 	ns->precision = nlen;
4332 
4333 	/* Convert the decimal digits to binary */
4334 	memset(ns->val, 0, sizeof(ns->val));
4335 	for (dig = 0; dig < nlen; dig++)
4336 	{
4337 		UInt4 carry;
4338 
4339 		/* multiply the current value by 10, and add the next digit */
4340 		carry = calv[dig] - '0';
4341 		for (i = 0; i < sizeof(ns->val); i++)
4342 		{
4343 			UInt4		t;
4344 
4345 			t = ((UInt4) ns->val[i]) * 10 + carry;
4346 			ns->val[i] = (unsigned char) (t & 0xFF);
4347 			carry = (t >> 8);
4348 		}
4349 
4350 		if (carry != 0)
4351 			*overflow = TRUE;
4352 	}
4353 }
4354 
4355 static BOOL
parameter_is_with_cast(const QueryParse * qp)4356 parameter_is_with_cast(const QueryParse *qp)
4357 {
4358 	const char *str = F_OldPtr(qp);
4359 
4360 	if ('?' != *str)	return FALSE;
4361 	while (isspace(*(++str))) ;
4362 	if (strncmp(str, "::", 2) == 0)
4363 		return TRUE;
4364 	if (strnicmp(str, "as", 2) != 0)
4365 		return FALSE;
4366 	if (isspace(str[2]))
4367 		return TRUE;
4368 	return FALSE;
4369 }
4370 
4371 #ifdef	UNICODE_SUPPORT
4372 enum {
4373 	ErrorOutConversionErrors	/* error out conversion errors */
4374 	, ReturnZeroLengthString	/* simply returns zero length strings */
4375 };
4376 static int convert_err_flag =
4377 #ifdef	WIN32
4378 	 ReturnZeroLengthString;
4379 #else
4380 	 ErrorOutConversionErrors;
4381 #endif /* WIN32 */
4382 
4383 static BOOL
handle_lu_onvert_error(QueryBuild * qb,int flag,char * buffer,SQLLEN paralen)4384 handle_lu_onvert_error(QueryBuild *qb, int flag, char *buffer, SQLLEN paralen)
4385 {
4386 	int	blen = paralen;
4387 
4388 	if (!buffer)
4389 		return FALSE;
4390 	if (get_mylog() > 0 || ReturnZeroLengthString != flag)
4391 	{
4392 		const UCHAR *buf = (UCHAR *) buffer;
4393 		int	i;
4394 		PQExpBufferData pbuf = {0};
4395 
4396 		if (SQL_NTS == blen)
4397 			blen = strlen(buffer);
4398 		initPQExpBuffer(&pbuf);
4399 		appendPQExpBuffer(&pbuf, "Could not convert the current data '");
4400 		for (i = 0; i < blen; i++)
4401 		{
4402 			if (buf[i] >= 0x80)
4403 				appendPQExpBuffer(&pbuf, "\\%03o", buf[i]);
4404 			else if ('\\' == buf[i])
4405 				appendPQExpBuffer(&pbuf, "\\\\");
4406 			else
4407 				appendPQExpBuffer(&pbuf, "%c", buf[i]);
4408 		}
4409 		appendPQExpBuffer(&pbuf, "' to wide chars");
4410 		MYLOG(0, "%s\n", pbuf.data);
4411 		if (ReturnZeroLengthString != flag)
4412 		{
4413 			if (qb->stmt)
4414 				SC_set_error(qb->stmt, STMT_EXEC_ERROR, pbuf.data, __FUNCTION__);
4415 			else
4416 				qb->errormsg = "could not convert the current data to wide chars";
4417 		}
4418 		termPQExpBuffer(&pbuf);
4419 
4420 	}
4421 	switch (flag)
4422 	{
4423 		case ReturnZeroLengthString:
4424 			if (qb->stmt)
4425 				SC_set_error(qb->stmt, STMT_ERROR_IN_ROW, "conversion error to wide chars occured", __FUNCTION__);
4426 			return TRUE;
4427 		default:
4428 			qb->errornumber = STMT_EXEC_ERROR;
4429 			return FALSE;
4430 	}
4431 }
4432 #endif /* UNICODE_SUPPORT */
4433 
4434 /*
4435  * Resolve one parameter.
4436  *
4437  * *isnull is set to TRUE if it was NULL.
4438  * *isbinary is set to TRUE, if the binary output format was used. (binary
4439  *   output is only produced if the FLGB_BINARY_AS_POSSIBLE flag is set)
4440  * *pgType is set to the PostgreSQL type OID that should be used when binding
4441  * (or 0, to let the server decide)
4442  */
4443 static int
ResolveOneParam(QueryBuild * qb,QueryParse * qp,BOOL * isnull,BOOL * isbinary,OID * pgType)4444 ResolveOneParam(QueryBuild *qb, QueryParse *qp, BOOL *isnull, BOOL *isbinary,
4445 				OID *pgType)
4446 {
4447 	ConnectionClass *conn = qb->conn;
4448 	const APDFields *apdopts = qb->apdopts;
4449 	const IPDFields *ipdopts = qb->ipdopts;
4450 	PutDataInfo *pdata = qb->pdata;
4451 
4452 	int			param_number;
4453 	char		param_string[150],
4454 				tmp[256];
4455 	char		cbuf[PG_NUMERIC_MAX_PRECISION * 2]; /* seems big enough to handle the data in this function */
4456 	OID			param_pgtype;
4457 	SQLSMALLINT	param_ctype, param_sqltype;
4458 	SIMPLE_TIME	st;
4459 	struct tm	*tim;
4460 	SQLLEN		used;
4461 	const char	*send_buf;
4462 
4463 	char		*buffer, *allocbuf = NULL, *lastadd = NULL;
4464 	OID			lobj_oid;
4465 	int			lobj_fd;
4466 	SQLULEN		offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
4467 	size_t		current_row = qb->current_row;
4468 	BOOL		handling_large_object = FALSE, req_bind;
4469 	BOOL		need_quotes = TRUE;
4470 	BOOL		add_parens = FALSE;
4471 	BOOL		negative;
4472 	ParameterInfoClass	*apara;
4473 	ParameterImplClass	*ipara;
4474 	BOOL		outputDiscard,
4475 				valueOutput;
4476 	SDOUBLE		dbv;
4477 	SFLOAT		flv;
4478 	SQL_INTERVAL_STRUCT	*ivstruct;
4479 	const char *ivsign;
4480 	BOOL		final_binary_convert = FALSE;
4481 	RETCODE		retval = SQL_ERROR;
4482 
4483 	*isnull = FALSE;
4484 	*isbinary = FALSE;
4485 	*pgType = 0;
4486 
4487 	outputDiscard = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
4488 	valueOutput = (qb->param_mode != RPM_FAKE_PARAMS &&
4489 				   qb->param_mode != RPM_BUILDING_PREPARE_STATEMENT);
4490 	req_bind = (qb->param_mode == RPM_BUILDING_BIND_REQUEST);
4491 
4492 	if (qb->proc_return < 0 && qb->stmt)
4493 		qb->proc_return = qb->stmt->proc_return;
4494 	/*
4495 	 * It's a '?' parameter alright
4496 	 */
4497 	param_number = ++qb->param_number;
4498 
4499 MYLOG(DETAIL_LOG_LEVEL, "para:%d(%d,%d)\n", param_number, ipdopts->allocated, apdopts->allocated);
4500 	apara = NULL;
4501 	ipara = NULL;
4502 	if (param_number < apdopts->allocated)
4503 		apara = apdopts->parameters + param_number;
4504 	if (param_number < ipdopts->allocated)
4505 		ipara = ipdopts->parameters + param_number;
4506 	if ((!apara || !ipara) && valueOutput)
4507 	{
4508 		MYLOG(0, "The # of (A|I)PD parameters (%d, %d) < %d the # of parameter markers\n", apdopts->allocated, ipdopts->allocated, param_number);
4509 		qb->errormsg = "The # of binded parameters < the # of parameter markers";
4510 		qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
4511 		CVT_TERMINATE(qb);	/* just in case */
4512 		return SQL_ERROR;
4513 	}
4514 
4515 MYLOG(DETAIL_LOG_LEVEL, "ipara=%p paramName=%s paramType=%d %d proc_return=%d\n", ipara, ipara ? PRINT_NAME(ipara->paramName) : PRINT_NULL, ipara ? ipara->paramType : -1, PG_VERSION_LT(conn, 8.1), qb->proc_return);
4516 	if (param_number < qb->proc_return)
4517 	{
4518 		if (ipara && SQL_PARAM_OUTPUT != ipara->paramType)
4519 		{
4520 			qb->errormsg = "The function return value isn't marked as output parameter";
4521 			qb->errornumber = STMT_EXEC_ERROR;
4522 			CVT_TERMINATE(qb);	/* just in case */
4523 			return SQL_ERROR;
4524 		}
4525 		return SQL_SUCCESS;
4526 	}
4527 	if (ipara && SQL_PARAM_OUTPUT == ipara->paramType)
4528 	{
4529 		if (PG_VERSION_LT(conn, 8.1))
4530 		{
4531 			qb->errormsg = "Output parameter isn't available before 8.1 version";
4532 			qb->errornumber = STMT_INTERNAL_ERROR;
4533 			CVT_TERMINATE(qb);	/* just in case */
4534 			return SQL_ERROR;
4535 		}
4536 		if (outputDiscard)
4537 		{
4538 			ssize_t			npos = 0;
4539 
4540 			for (npos = qb->npos - 1; npos >= 0 && isspace((unsigned char) qb->query_statement[npos]) ; npos--) ;
4541 			if (npos >= 0)
4542 			{
4543 				switch (qb->query_statement[npos])
4544 				{
4545 					case ',':
4546 						qb->npos = npos;
4547 						qb->query_statement[npos] = '\0';
4548 						break;
4549 					case '(':
4550 						if (!qp)
4551 							break;
4552 						for (npos = qp->opos + 1; isspace((unsigned char) qp->statement[npos]); npos++) ;
4553 						if (qp->statement[npos] == ',')
4554 							qp->opos = npos;
4555 						break;
4556 				}
4557 			}
4558 			return SQL_SUCCESS_WITH_INFO;
4559 		}
4560 	}
4561 	else
4562 	{
4563 		/* For procedures, use named notation if a parameter name is specified */
4564 		if (!req_bind && ipara && NAME_IS_VALID(ipara->paramName) &&
4565 			qp && qp->statement_type == STMT_TYPE_PROCCALL)
4566 		{
4567 			char	named_notation[COLUMN_NAME_STORAGE_LEN + 7];
4568 			SPRINTF_FIXED(named_notation, "\"%s\" := ", GET_NAME(ipara->paramName));
4569 			CVT_APPEND_STR(qb, named_notation);
4570 		}
4571 	}
4572 
4573 	if ((!apara || !ipara) && qb->param_mode == RPM_FAKE_PARAMS)
4574 	{
4575 		CVT_APPEND_STR(qb, "NULL");
4576 		qb->flags |= FLGB_INACCURATE_RESULT;
4577 		return SQL_SUCCESS;
4578 	}
4579 	if (qb->param_mode == RPM_BUILDING_PREPARE_STATEMENT)
4580 	{
4581 		char	pnum[16];
4582 
4583 		qb->dollar_number++;
4584 		if (ipara &&
4585 		    SQL_PARAM_OUTPUT != ipara->paramType &&
4586 		    (qb->flags & FLGB_PARAM_CAST) != 0 &&
4587 		    !parameter_is_with_cast(qp))
4588 			SPRINTF_FIXED(pnum, "$%d%s", qb->dollar_number, sqltype_to_pgcast(conn, ipara->SQLType));
4589 		else
4590 			SPRINTF_FIXED(pnum, "$%d", qb->dollar_number);
4591 		CVT_APPEND_STR(qb, pnum);
4592 		return SQL_SUCCESS;
4593 	}
4594 	/*
4595 	 * After this point, we can assume apara and ipara to be set. The only
4596 	 * cases where we allow them to be NULL is when param_mode is
4597 	 * RPM_FAKE_PARAMS or RPM_BUILDING_PREPARE_STATEMENT, and we've now handled
4598 	 * those cases.
4599 	 */
4600 
4601 	/* Assign correct buffers based on data at exec param or not */
4602 	if (apara->data_at_exec)
4603 	{
4604 		if (pdata->allocated != apdopts->allocated)
4605 			extend_putdata_info(pdata, apdopts->allocated, TRUE);
4606 		used = pdata->pdata[param_number].EXEC_used ? *pdata->pdata[param_number].EXEC_used : SQL_NTS;
4607 		buffer = pdata->pdata[param_number].EXEC_buffer;
4608 		if (pdata->pdata[param_number].lobj_oid)
4609 			handling_large_object = TRUE;
4610 	}
4611 	else
4612 	{
4613 		UInt4	bind_size = apdopts->param_bind_type;
4614 		UInt4	ctypelen;
4615 		BOOL	bSetUsed = FALSE;
4616 
4617 		buffer = apara->buffer + offset;
4618 		if (current_row > 0)
4619 		{
4620 			if (bind_size > 0)
4621 				buffer += (bind_size * current_row);
4622 			else if (ctypelen = ctype_length(apara->CType), ctypelen > 0)
4623 				buffer += current_row * ctypelen;
4624 			else
4625 				buffer += current_row * apara->buflen;
4626 		}
4627 		if (apara->used || apara->indicator)
4628 		{
4629 			SQLULEN	p_offset;
4630 
4631 			if (bind_size > 0)
4632 				p_offset = offset + bind_size * current_row;
4633 			else
4634 				p_offset = offset + sizeof(SQLLEN) * current_row;
4635 			if (apara->indicator)
4636 			{
4637 				used = *LENADDR_SHIFT(apara->indicator, p_offset);
4638 				if (SQL_NULL_DATA == used)
4639 					bSetUsed = TRUE;
4640 			}
4641 			if (!bSetUsed && apara->used)
4642 			{
4643 				used = *LENADDR_SHIFT(apara->used, p_offset);
4644 				bSetUsed = TRUE;
4645 			}
4646 		}
4647 		if (!bSetUsed)
4648 			used = SQL_NTS;
4649 	}
4650 
4651 	/* Handle DEFAULT_PARAM parameter data. Should be NULL ?
4652 	if (used == SQL_DEFAULT_PARAM)
4653 	{
4654 		return SQL_SUCCESS;
4655 	} */
4656 
4657 	param_ctype = apara->CType;
4658 	param_sqltype = ipara->SQLType;
4659 	param_pgtype = PIC_dsp_pgtype(qb->conn, *ipara);
4660 
4661 	/* XXX: should we use param_pgtype here instead? */
4662 	*pgType = sqltype_to_bind_pgtype(conn, param_sqltype);
4663 
4664 	if (0 == param_sqltype) /* calling SQLSetStmtAttr(.., SQL_ATTR_APP_PARAM_DES, an ARD of another statement) may cause this */
4665 	{
4666 		if (0 != param_pgtype)
4667 		{
4668 			param_sqltype = pgtype_attr_to_concise_type(conn, param_pgtype, PG_ATP_UNSET, PG_ADT_UNSET, PG_UNKNOWNS_UNSET);
4669 			MYLOG(0, "convert from pgtype(%u) to sqltype(%d)\n", param_pgtype, param_sqltype);
4670 		}
4671 	}
4672 
4673 	MYLOG(0, "from(fcType)=%d, to(fSqlType)=%d(%u), *pgType=%u\n",
4674 		  param_ctype, param_sqltype, param_pgtype, *pgType);
4675 
4676 	/* Handle NULL parameter data */
4677 	if (SQL_PARAM_OUTPUT == ipara->paramType
4678 	    || used == SQL_NULL_DATA
4679 	    || used == SQL_DEFAULT_PARAM)
4680 	{
4681 		*isnull = TRUE;
4682 		if (!req_bind)
4683 			CVT_APPEND_STR(qb, "NULL");
4684 		return SQL_SUCCESS;
4685 	}
4686 
4687 	/*
4688 	 * If no buffer, and it's not null, then what the hell is it? Just
4689 	 * leave it alone then.
4690 	 */
4691 	if (!buffer)
4692 	{
4693 		if (qb->param_mode == RPM_FAKE_PARAMS)
4694 		{
4695 			CVT_APPEND_STR(qb, "NULL");
4696 			qb->flags |= FLGB_INACCURATE_RESULT;
4697 			return SQL_SUCCESS;
4698 		}
4699 		else if (!handling_large_object)
4700 		{
4701 			/* shouldn't happen */
4702 			qb->errormsg = "unexpected NULL parameter value";
4703 			qb->errornumber = STMT_EXEC_ERROR;
4704 			return SQL_ERROR;
4705 		}
4706 	}
4707 
4708 	/* replace DEFAULT with something we can use */
4709 	if (param_ctype == SQL_C_DEFAULT)
4710 	{
4711 		param_ctype = sqltype_to_default_ctype(conn, param_sqltype);
4712 #ifdef	UNICODE_SUPPORT
4713 		if (param_ctype == SQL_C_WCHAR
4714 		    && CC_default_is_c(conn))
4715 			param_ctype =SQL_C_CHAR;
4716 #endif
4717 	}
4718 
4719 	allocbuf = NULL;
4720 	send_buf = NULL;
4721 	param_string[0] = '\0';
4722 	cbuf[0] = '\0';
4723 	memset(&st, 0, sizeof(st));
4724 
4725 	ivstruct = (SQL_INTERVAL_STRUCT *) buffer;
4726 	/* Convert input C type to a neutral format */
4727 #ifdef	UNICODE_SUPPORT
4728 	if (get_convtype() > 0) /* coversion between the current locale is available */
4729 	{
4730 		BOOL	wcs_debug = conn->connInfo.wcs_debug;
4731 		BOOL	is_utf8 = (UTF8 == conn->ccsc);
4732 		BOOL	same_encoding = (conn->ccsc == pg_CS_code(conn->locale_encoding));
4733 
4734 		switch (param_ctype)
4735 		{
4736 			case SQL_C_CHAR:
4737 				if (!same_encoding || wcs_debug)
4738 				{
4739 					SQLLEN	paralen = used;
4740 
4741 					MYLOG(0, "locale param convert\n");
4742 					if ((used = bindpara_msg_to_utf8(buffer, &allocbuf, used)) < 0)
4743 					{
4744 						if (!handle_lu_onvert_error(qb, convert_err_flag, buffer, paralen))
4745 							goto cleanup;
4746 						send_buf = NULL_STRING;
4747 						used = 0;
4748 					}
4749 					else
4750 						send_buf = allocbuf;
4751 				}
4752 				break;
4753 			case SQL_C_WCHAR:
4754 				if (!is_utf8 || (same_encoding && wcs_debug))
4755 				{
4756 					MYLOG(0, "hybrid param convert\n");
4757 					if ((used = bindpara_wchar_to_msg((SQLWCHAR *) buffer, &allocbuf, used)) < 0)
4758 					{
4759 						qb->errormsg = "Could not convert from wide characters to the current locale";
4760 						qb->errornumber = STMT_EXEC_ERROR;
4761 						goto cleanup;
4762 					}
4763 					send_buf = allocbuf;
4764 				}
4765 				break;
4766 		}
4767 	}
4768 #endif /* UNICODE_SUPPORT */
4769 	switch (param_ctype)
4770 	{
4771 		case SQL_C_BINARY:
4772 			send_buf = buffer;
4773 			break;
4774 		case SQL_C_CHAR:
4775 			if (NULL == send_buf)
4776 				send_buf = buffer;
4777 			break;
4778 
4779 #ifdef	UNICODE_SUPPORT
4780 		case SQL_C_WCHAR:
4781 MYLOG(0, " C_WCHAR=%d contents=%s(" FORMAT_LEN ")\n", param_ctype, buffer, used);
4782 			if (NULL == send_buf)
4783 			{
4784 				allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used > 0 ? used / WCLEN : used, &used, FALSE);
4785 				send_buf = allocbuf;
4786 			}
4787 			break;
4788 #endif /* UNICODE_SUPPORT */
4789 
4790 		case SQL_C_DOUBLE:
4791 			dbv = *((SDOUBLE *) buffer);
4792 #ifdef	WIN32
4793 			if (_finite(dbv))
4794 #endif /* WIN32 */
4795 			{
4796 				SPRINTF_FIXED(param_string, "%.*g", PG_DOUBLE_DIGITS, dbv);
4797 				set_server_decimal_point(param_string, SQL_NTS);
4798 			}
4799 #ifdef	WIN32
4800 			else if (_isnan(dbv))
4801 				STRCPY_FIXED(param_string, NAN_STRING);
4802 			else if (dbv < .0)
4803 				STRCPY_FIXED(param_string, MINFINITY_STRING);
4804 			else
4805 				STRCPY_FIXED(param_string, INFINITY_STRING);
4806 #endif /* WIN32 */
4807 			break;
4808 
4809 		case SQL_C_FLOAT:
4810 			flv = *((SFLOAT *) buffer);
4811 #ifdef	WIN32
4812 			if (_finite(flv))
4813 #endif /* WIN32 */
4814 			{
4815 				SPRINTF_FIXED(param_string, "%.*g", PG_REAL_DIGITS, flv);
4816 				set_server_decimal_point(param_string, SQL_NTS);
4817 			}
4818 #ifdef	WIN32
4819 			else if (_isnan(flv))
4820 				STRCPY_FIXED(param_string, NAN_STRING);
4821 			else if (flv < .0)
4822 				STRCPY_FIXED(param_string, MINFINITY_STRING);
4823 			else
4824 				STRCPY_FIXED(param_string, INFINITY_STRING);
4825 #endif /* WIN32 */
4826 			break;
4827 
4828 		case SQL_C_SLONG:
4829 		case SQL_C_LONG:
4830 			SPRINTF_FIXED(param_string, FORMAT_INTEGER,
4831 					*((SQLINTEGER *) buffer));
4832 			break;
4833 
4834 #ifdef ODBCINT64
4835 		case SQL_C_SBIGINT:
4836 		case SQL_BIGINT: /* Is this needed ? */
4837 			SPRINTF_FIXED(param_string, FORMATI64,
4838 					*((SQLBIGINT *) buffer));
4839 			break;
4840 
4841 		case SQL_C_UBIGINT:
4842 			SPRINTF_FIXED(param_string, FORMATI64U,
4843 					*((SQLUBIGINT *) buffer));
4844 			break;
4845 
4846 #endif /* ODBCINT64 */
4847 		case SQL_C_SSHORT:
4848 		case SQL_C_SHORT:
4849 			ITOA_FIXED(param_string, *((SQLSMALLINT *) buffer));
4850 			break;
4851 
4852 		case SQL_C_STINYINT:
4853 		case SQL_C_TINYINT:
4854 			ITOA_FIXED(param_string, *((SCHAR *) buffer));
4855 			break;
4856 
4857 		case SQL_C_ULONG:
4858 			SPRINTF_FIXED(param_string, FORMAT_UINTEGER,
4859 					*((SQLUINTEGER *) buffer));
4860 			break;
4861 
4862 		case SQL_C_USHORT:
4863 			SPRINTF_FIXED(param_string, "%u",
4864 					*((SQLUSMALLINT *) buffer));
4865 			break;
4866 
4867 		case SQL_C_UTINYINT:
4868 			SPRINTF_FIXED(param_string, "%u",
4869 					*((UCHAR *) buffer));
4870 			break;
4871 
4872 		case SQL_C_BIT:
4873 			{
4874 				int	i = *((UCHAR *) buffer);
4875 
4876 				ITOA_FIXED(param_string, i ? 1 : 0);
4877 				break;
4878 			}
4879 
4880 		case SQL_C_DATE:
4881 		case SQL_C_TYPE_DATE:		/* 91 */
4882 			{
4883 				DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
4884 
4885 				st.m = ds->month;
4886 				st.d = ds->day;
4887 				st.y = ds->year;
4888 
4889 				break;
4890 			}
4891 
4892 		case SQL_C_TIME:
4893 		case SQL_C_TYPE_TIME:		/* 92 */
4894 			{
4895 				TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
4896 
4897 				st.hh = ts->hour;
4898 				st.mm = ts->minute;
4899 				st.ss = ts->second;
4900 				/*
4901 				 * Initialize date in case conversion destination
4902 				 * expects date part from this source time data.
4903 				 */
4904 				tim = SC_get_localtime(qb->stmt);
4905 				st.m = tim->tm_mon + 1;
4906 				st.d = tim->tm_mday;
4907 				st.y = tim->tm_year + 1900;
4908 				break;
4909 			}
4910 
4911 		case SQL_C_TIMESTAMP:
4912 		case SQL_C_TYPE_TIMESTAMP:	/* 93 */
4913 			{
4914 				TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
4915 
4916 				st.m = tss->month;
4917 				st.d = tss->day;
4918 				st.y = tss->year;
4919 				st.hh = tss->hour;
4920 				st.mm = tss->minute;
4921 				st.ss = tss->second;
4922 				st.fr = tss->fraction;
4923 
4924 				MYLOG(0, "m=%d,d=%d,y=%d,hh=%d,mm=%d,ss=%d\n", st.m, st.d, st.y, st.hh, st.mm, st.ss);
4925 
4926 				break;
4927 
4928 			}
4929 		case SQL_C_NUMERIC:
4930 		{
4931 			ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string);
4932 			break;
4933 		}
4934 		case SQL_C_INTERVAL_YEAR:
4935 			ivsign = ivstruct->interval_sign ? "-" : "";
4936 			SPRINTF_FIXED(param_string, "%s%u years", ivsign, (unsigned int) ivstruct->intval.year_month.year);
4937 			break;
4938 		case SQL_C_INTERVAL_MONTH:
4939 		case SQL_C_INTERVAL_YEAR_TO_MONTH:
4940 			ivsign = ivstruct->interval_sign ? "-" : "";
4941 			SPRINTF_FIXED(param_string, "%s%u years %s%u mons", ivsign, (unsigned int) ivstruct->intval.year_month.year, ivsign, (unsigned int) ivstruct->intval.year_month.month);
4942 			break;
4943 		case SQL_C_INTERVAL_DAY:
4944 			ivsign = ivstruct->interval_sign ? "-" : "";
4945 			SPRINTF_FIXED(param_string, "%s%u days", ivsign, (unsigned int) ivstruct->intval.day_second.day);
4946 			break;
4947 		case SQL_C_INTERVAL_HOUR:
4948 		case SQL_C_INTERVAL_DAY_TO_HOUR:
4949 			ivsign = ivstruct->interval_sign ? "-" : "";
4950 			SPRINTF_FIXED(param_string, "%s%u days %s%02u:00:00", ivsign, (unsigned int) ivstruct->intval.day_second.day, ivsign, (unsigned int) ivstruct->intval.day_second.hour);
4951 			break;
4952 		case SQL_C_INTERVAL_MINUTE:
4953 		case SQL_C_INTERVAL_HOUR_TO_MINUTE:
4954 		case SQL_C_INTERVAL_DAY_TO_MINUTE:
4955 			ivsign = ivstruct->interval_sign ? "-" : "";
4956 			SPRINTF_FIXED(param_string, "%s%u days %s%02u:%02u:00", ivsign, (unsigned int) ivstruct->intval.day_second.day, ivsign, (unsigned int) ivstruct->intval.day_second.hour, (unsigned int) ivstruct->intval.day_second.minute);
4957 			break;
4958 
4959 		case SQL_C_INTERVAL_SECOND:
4960 		case SQL_C_INTERVAL_DAY_TO_SECOND:
4961 		case SQL_C_INTERVAL_HOUR_TO_SECOND:
4962 		case SQL_C_INTERVAL_MINUTE_TO_SECOND:
4963 			ivsign = ivstruct->interval_sign ? "-" : "";
4964 			SPRINTF_FIXED(param_string, "%s%u days %s%02u:%02u:%02u",
4965 					ivsign, (unsigned int) ivstruct->intval.day_second.day,
4966 					ivsign, (unsigned int) ivstruct->intval.day_second.hour,
4967 					(unsigned int) ivstruct->intval.day_second.minute,
4968 					(unsigned int) ivstruct->intval.day_second.second);
4969 			if (ivstruct->intval.day_second.fraction > 0)
4970 			{
4971 				int fraction = ivstruct->intval.day_second.fraction, prec = apara->precision;
4972 
4973 				while (fraction % 10 == 0)
4974 				{
4975 					fraction /= 10;
4976 					prec--;
4977 				}
4978 				SPRINTFCAT_FIXED(param_string, ".%0*d", prec, fraction);
4979 			}
4980 			break;
4981 		case SQL_C_GUID:
4982 		{
4983 			/*
4984 			 * SQLGUID.Data1 is an "unsigned long" on some platforms, and
4985 			 * "unsigned int" on others.
4986 			 */
4987 			SQLGUID *g = (SQLGUID *) buffer;
4988 			SPRINTF_FIXED (param_string,
4989 				"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
4990 				(unsigned int) g->Data1,
4991 				g->Data2, g->Data3,
4992 				g->Data4[0], g->Data4[1], g->Data4[2], g->Data4[3],
4993 				g->Data4[4], g->Data4[5], g->Data4[6], g->Data4[7]);
4994 		}
4995 		break;
4996 		default:
4997 			/* error */
4998 			qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
4999 			qb->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
5000 			CVT_TERMINATE(qb);	/* just in case */
5001 			goto cleanup;
5002 	}
5003 
5004 	/*
5005 	 * Now that the input data is in a neutral format, convert it to
5006 	 * the desired output format (sqltype)
5007 	 */
5008 
5009 	/* Special handling NULL string For FOXPRO */
5010 MYLOG(0, "cvt_null_date_string=%d pgtype=%d send_buf=%p\n", conn->connInfo.cvt_null_date_string, param_pgtype, send_buf);
5011 	if (conn->connInfo.cvt_null_date_string > 0 &&
5012 	    (PG_TYPE_DATE == param_pgtype ||
5013 	     PG_TYPE_DATETIME == param_pgtype ||
5014 	     PG_TYPE_TIMESTAMP_NO_TMZONE == param_pgtype) &&
5015 	    NULL != send_buf &&
5016 	    (
5017 		(SQL_C_CHAR == param_ctype && '\0' == send_buf[0])
5018 #ifdef	UNICODE_SUPPORT
5019 		|| (SQL_C_WCHAR ==param_ctype && '\0' == send_buf[0] && '\0' == send_buf[1])
5020 #endif /* UNICODE_SUPPORT */
5021 	    ))
5022 	{
5023 		*isnull = TRUE;
5024 		if (!req_bind)
5025 			CVT_APPEND_STR(qb, "NULL");
5026 		retval = SQL_SUCCESS;
5027 		goto cleanup;
5028 	}
5029 
5030 	/*
5031 	 * We now have the value we want to print in one of these three canonical
5032 	 * formats:
5033 	 *
5034 	 * 1. As a string in 'send_buf', with length indicated by 'used' (can be
5035 	 *    SQL_NTS).
5036 	 * 2. As a null-terminated string in 'param_string'.
5037 	 * 3. Time-related fields in 'st'.
5038 	 */
5039 
5040 	/*
5041 	 * For simplicity, fold the param_string representation into 'send_buf'.
5042 	 */
5043 	if (!send_buf && param_string[0])
5044 	{
5045 		send_buf = param_string;
5046 		used = SQL_NTS;
5047 	}
5048 
5049 	/*
5050 	 * Do some further processing to create the final string we want to output.
5051 	 * This will use the fields in 'st' to create a string if it's a time/date
5052 	 * value, and do some other conversions.
5053 	 */
5054 	switch (param_sqltype)
5055 	{
5056 		case SQL_CHAR:
5057 		case SQL_VARCHAR:
5058 		case SQL_LONGVARCHAR:
5059 #ifdef	UNICODE_SUPPORT
5060 		case SQL_WCHAR:
5061 		case SQL_WVARCHAR:
5062 		case SQL_WLONGVARCHAR:
5063 #endif /* UNICODE_SUPPORT */
5064 		case SQL_BIT:
5065 
5066 			/* Special handling for some column types */
5067 			switch (param_pgtype)
5068 			{
5069 				case PG_TYPE_BOOL:
5070 					/*
5071 					 * consider True is -1 case.
5072 					 *
5073 					 * FIXME: This actually matches anything that begins
5074 					 * with -1, like "-1234" or "-1foobar". Is that
5075 					 * intentional?
5076 					 */
5077 					if (NULL != send_buf && '-' == send_buf[0] && '1' == send_buf[1])
5078 					{
5079 						send_buf = "1";
5080 						used = 1;
5081 					}
5082 					break;
5083 				case PG_TYPE_FLOAT4:
5084 				case PG_TYPE_FLOAT8:
5085 				case PG_TYPE_NUMERIC:
5086 					if (NULL != send_buf)
5087 						set_server_decimal_point((char *) send_buf, used);
5088 					break;
5089 			}
5090 			if (!send_buf)
5091 			{
5092 				/* it was date,time,timestamp -- use m,d,y,hh,mm,ss */
5093 				SPRINTF_FIXED(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
5094 						st.y, st.m, st.d, st.hh, st.mm, st.ss);
5095 				send_buf = tmp;
5096 				used = SQL_NTS;
5097 			}
5098 			break;
5099 
5100 		case SQL_DATE:
5101 		case SQL_TYPE_DATE:	/* 91 */
5102 			if (send_buf)
5103 			{				/* copy char data to time */
5104 				my_strcpy(cbuf, sizeof(cbuf), send_buf, used);
5105 				parse_datetime(cbuf, &st);
5106 			}
5107 
5108 			if (st.y < 0)
5109 				SPRINTF_FIXED(tmp, "%.4d-%.2d-%.2d BC", -st.y, st.m, st.d);
5110 			else
5111 				SPRINTF_FIXED(tmp, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
5112 			lastadd = "::date";
5113 			send_buf = tmp;
5114 			used = SQL_NTS;
5115 			break;
5116 
5117 		case SQL_TIME:
5118 		case SQL_TYPE_TIME:	/* 92 */
5119 			if (send_buf)
5120 			{				/* copy char data to time */
5121 				my_strcpy(cbuf, sizeof(cbuf), send_buf, used);
5122 				parse_datetime(cbuf, &st);
5123 			}
5124 
5125 			if (st.fr > 0)
5126 			{
5127 				int	wdt;
5128 				int	fr = effective_fraction(st.fr, &wdt);
5129 				SPRINTF_FIXED(tmp, "%.2d:%.2d:%.2d.%0*d", st.hh, st.mm, st.ss, wdt, fr);
5130 			}
5131 			else
5132 				SPRINTF_FIXED(tmp, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
5133 			lastadd = "::time";
5134 			send_buf = tmp;
5135 			used = SQL_NTS;
5136 			break;
5137 
5138 		case SQL_TIMESTAMP:
5139 		case SQL_TYPE_TIMESTAMP:	/* 93 */
5140 			if (send_buf)
5141 			{
5142 				my_strcpy(cbuf, sizeof(cbuf), send_buf, used);
5143 				parse_datetime(cbuf, &st);
5144 			}
5145 
5146 			/*
5147 			 * SPRINTF_FIXED(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", st.y,
5148 			 * st.m, st.d, st.hh, st.mm, st.ss);
5149 			 */
5150 			/* Time zone stuff is unreliable */
5151 			stime2timestamp(&st, tmp, sizeof(tmp), USE_ZONE, 6);
5152 			lastadd = "::timestamp";
5153 			send_buf = tmp;
5154 			used = SQL_NTS;
5155 			break;
5156 
5157 		case SQL_BINARY:
5158 		case SQL_VARBINARY:
5159 		case SQL_LONGVARBINARY:
5160 			switch (param_ctype)
5161 			{
5162 				case SQL_C_BINARY:
5163 					break;
5164 				case SQL_C_CHAR:
5165 #ifdef	UNICODE_SUPPORT
5166 				case SQL_C_WCHAR:
5167 #endif /* UNICODE_SUPPORT */
5168 					switch (used)
5169 					{
5170 						case SQL_NTS:
5171 							used = strlen(send_buf);
5172 							break;
5173 					}
5174 					allocbuf = malloc(used / 2 + 1);
5175 					if (allocbuf)
5176 					{
5177 						pg_hex2bin(send_buf, allocbuf, used);
5178 						send_buf = allocbuf;
5179 						used /= 2;
5180 					}
5181 					break;
5182 				default:
5183 					qb->errormsg = "Could not convert the ctype to binary type";
5184 					qb->errornumber = STMT_EXEC_ERROR;
5185 					goto cleanup;
5186 			}
5187 			if (param_pgtype == PG_TYPE_BYTEA)
5188 			{
5189 				if (0 != (qb->flags & FLGB_BINARY_AS_POSSIBLE))
5190 				{
5191 					MYLOG(0, "sending binary data leng=" FORMAT_LEN "\n", used);
5192 					*isbinary = TRUE;
5193 				}
5194 				else
5195 				{
5196 					/* non-ascii characters should be
5197 					 * converted to octal
5198 					 */
5199 					MYLOG(0, "SQL_VARBINARY: about to call convert_to_pgbinary, used = " FORMAT_LEN "\n", used);
5200 					final_binary_convert = TRUE;
5201 				}
5202 				break;
5203 			}
5204 			if (PG_TYPE_OID == param_pgtype && conn->lo_is_domain)
5205 				;
5206 			else if (param_pgtype != conn->lobj_type)
5207 			{
5208 				qb->errormsg = "Could not convert binary other than LO type";
5209 				qb->errornumber = STMT_EXEC_ERROR;
5210 				goto cleanup;
5211 			}
5212 
5213 			if (apara->data_at_exec)
5214 				lobj_oid = pdata->pdata[param_number].lobj_oid;
5215 			else
5216 			{
5217 				BOOL	is_in_trans_at_entry = CC_is_in_trans(conn);
5218 				int		write_result;
5219 
5220 				/* begin transaction if needed */
5221 				if (!is_in_trans_at_entry)
5222 				{
5223 					if (!CC_begin(conn))
5224 					{
5225 						qb->errormsg = "Could not begin (in-line) a transaction";
5226 						qb->errornumber = STMT_EXEC_ERROR;
5227 						goto cleanup;
5228 					}
5229 				}
5230 
5231 				/* store the oid */
5232 				lobj_oid = odbc_lo_creat(conn, INV_READ | INV_WRITE);
5233 				if (lobj_oid == 0)
5234 				{
5235 					qb->errornumber = STMT_EXEC_ERROR;
5236 					qb->errormsg = "Couldn't create (in-line) large object.";
5237 					goto cleanup;
5238 				}
5239 
5240 				/* store the fd */
5241 				lobj_fd = odbc_lo_open(conn, lobj_oid, INV_WRITE);
5242 				if (lobj_fd < 0)
5243 				{
5244 					qb->errornumber = STMT_EXEC_ERROR;
5245 					qb->errormsg = "Couldn't open (in-line) large object for writing.";
5246 					goto cleanup;
5247 				}
5248 
5249 				write_result = odbc_lo_write(conn, lobj_fd, buffer, (Int4) used);
5250 				if (write_result < 0)
5251 				{
5252 					qb->errornumber = STMT_EXEC_ERROR;
5253 					qb->errormsg = "Couldn't write to (in-line) large object.";
5254 					goto cleanup;
5255 				}
5256 
5257 				odbc_lo_close(conn, lobj_fd);
5258 
5259 				/* commit transaction if needed */
5260 				if (!is_in_trans_at_entry)
5261 				{
5262 					if (!CC_commit(conn))
5263 					{
5264 						qb->errormsg = "Could not commit (in-line) a transaction";
5265 						qb->errornumber = STMT_EXEC_ERROR;
5266 						goto cleanup;
5267 					}
5268 				}
5269 			}
5270 
5271 			/*
5272 			 * the oid of the large object -- just put that in for the
5273 			 * parameter marker -- the data has already been sent to
5274 			 * the large object
5275 			 */
5276 			SPRINTF_FIXED(param_string, "%u", lobj_oid);
5277 			lastadd = "::lo";
5278 			send_buf = param_string;
5279 			used = SQL_NTS;
5280 			break;
5281 
5282 			/*
5283 			 * because of no conversion operator for bool and int4,
5284 			 * SQL_BIT
5285 			 */
5286 			/* must be quoted (0 or 1 is ok to use inside the quotes) */
5287 
5288 		case SQL_REAL:
5289 			set_server_decimal_point((char *) send_buf, used);
5290 			lastadd = "::float4";
5291 			break;
5292 		case SQL_FLOAT:
5293 		case SQL_DOUBLE:
5294 			set_server_decimal_point((char *) send_buf, used);
5295 			lastadd = "::float8";
5296 			break;
5297 		case SQL_NUMERIC:
5298 			break;
5299 		/*
5300 		 * If it looks like a valid integer, we can pass it without quotes
5301 		 * and let the server interpret it. Arguably, it would always be
5302 		 * better to explicitly pass it as 'xxx'::integer or 'xxx'::smallint,
5303 		 * but historically we haven't done that, so let's avoid changing the
5304 		 * behaviour.
5305 		 *
5306 		 * If it's a negative number, we have to wrap it in parens. Otherwise
5307 		 * a query like "SELECT 0-?" would turn into "SELECT 0--123".
5308 		 */
5309 		case SQL_INTEGER:
5310 			if (valid_int_literal(send_buf, used, &negative))
5311 			{
5312 				need_quotes = FALSE;
5313 				add_parens = negative;
5314 			}
5315 			else
5316 			{
5317 				/*
5318 				 * Doesn't look like a valid integer. The server will most
5319 				 * likely throw an error, unless it's in some format we don't
5320 				 * recognize but the server does.
5321 				 */
5322 				lastadd = "::int4";
5323 			}
5324 			break;
5325 		case SQL_SMALLINT:
5326 			if (valid_int_literal(send_buf, used, &negative))
5327 			{
5328 				need_quotes = FALSE;
5329 				add_parens = negative;
5330 			}
5331 			else
5332 				lastadd = "::smallint";
5333 			break;
5334 		default:			/* a numeric type or SQL_BIT */
5335 			break;
5336 	}
5337 
5338 	if (!send_buf)
5339 	{
5340 		qb->errormsg = "Could not convert parameter ctype to sqltype";
5341 		qb->errornumber = STMT_EXEC_ERROR;
5342 		goto cleanup;
5343 	}
5344 	if (used == SQL_NTS)
5345 		used = strlen(send_buf);
5346 
5347 	/*
5348 	 * Ok, we now have the final string representation in 'send_buf', length 'used'.
5349 	 * We're ready to output the final string, with quotes and other
5350 	 * embellishments if necessary.
5351 	 *
5352 	 * In bind-mode, we don't need to do any quoting.
5353 	 */
5354 	if (req_bind)
5355 		CVT_APPEND_DATA(qb, send_buf, used);
5356 	else
5357 	{
5358 		if (add_parens)
5359 			CVT_APPEND_CHAR(qb, '(');
5360 
5361 		if (need_quotes)
5362 		{
5363 			if ((qb->flags & FLGB_LITERAL_EXTENSION) != 0)
5364 				CVT_APPEND_CHAR(qb, LITERAL_EXT);
5365 			CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
5366 
5367 			if (final_binary_convert)
5368 				CVT_APPEND_BINARY(qb, send_buf, used);
5369 			else
5370 				CVT_SPECIAL_CHARS(qb, send_buf, used);
5371 
5372 			CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
5373 		}
5374 		else
5375 			CVT_APPEND_DATA(qb, send_buf, used);
5376 
5377 		if (add_parens)
5378 			CVT_APPEND_CHAR(qb, ')');
5379 		if (lastadd && (FLGB_PARAM_CAST & qb->flags) != 0)
5380 			CVT_APPEND_STR(qb, lastadd);
5381 	}
5382 
5383 	retval = SQL_SUCCESS;
5384 cleanup:
5385 	if (allocbuf)
5386 		free(allocbuf);
5387 	return retval;
5388 }
5389 
5390 
5391 static const char *
mapFunction(const char * func,int param_count,const char * keyword)5392 mapFunction(const char *func, int param_count, const char *keyword)
5393 {
5394 	int			i;
5395 	const char *p1, *p2;
5396 
5397 	for (i = 0; (p1 = mapFuncs[i].odbc_name) != NULL; i++)
5398 	{
5399 		if (p1[0] == '%')
5400 		{
5401 			if (p1[1] - '0' == param_count &&
5402 			    !stricmp(p1 + 2, func))
5403 				return mapFuncs[i].pgsql_name;
5404 		}
5405 		else if (!stricmp(p1, func))
5406 			return mapFuncs[i].pgsql_name;
5407 		else if (p2 = strchr(p1, (int) '('), NULL != p2)
5408 		{
5409 			int len = (int) (p2 - mapFuncs[i].odbc_name);
5410 
5411 			if (strlen(func) == len &&
5412 			    !strnicmp(p1, func, len) &&
5413 			    !stricmp(p2 + 1, keyword))
5414 				return mapFuncs[i].pgsql_name;
5415 		}
5416 	}
5417 
5418 	return NULL;
5419 }
5420 
5421 /*
5422  * processParameters()
5423  * Process function parameters and work with embedded escapes sequences.
5424  */
5425 static int
processParameters(QueryParse * qp,QueryBuild * qb,size_t * output_count,SQLLEN param_pos[][2])5426 processParameters(QueryParse *qp, QueryBuild *qb,
5427 		size_t *output_count, SQLLEN param_pos[][2])
5428 {
5429 	int retval, innerParenthesis, param_count;
5430 	BOOL stop;
5431 
5432 	/* begin with outer '(' */
5433 	innerParenthesis = 0;
5434 	param_count = 0;
5435 	if (NULL != output_count)
5436 		*output_count = 0;
5437 	stop = FALSE;
5438 	for (; F_OldPos(qp) < qp->stmt_len; F_OldNext(qp))
5439 	{
5440 		retval = inner_process_tokens(qp, qb);
5441 		if (retval == SQL_ERROR)
5442 			return retval;
5443 		if (MBCS_NON_ASCII(qp->encstr))
5444 			continue;
5445 		if (!QP_in_idle_status(qp))
5446 			continue;
5447 
5448 		switch (F_OldChar(qp))
5449 		{
5450 			case ',':
5451 				if (1 == innerParenthesis)
5452 				{
5453 					param_pos[param_count][1] = F_NewPos(qb) - 2;
5454 					param_count++;
5455 					param_pos[param_count][0] = F_NewPos(qb);
5456 					param_pos[param_count][1] = -1;
5457 				}
5458 				break;
5459 			case '(':
5460 				if (0 == innerParenthesis)
5461 				{
5462 					param_pos[param_count][0] = F_NewPos(qb);
5463 					param_pos[param_count][1] = -1;
5464 				}
5465 				innerParenthesis++;
5466 				break;
5467 
5468 			case ')':
5469 				innerParenthesis--;
5470 				if (0 == innerParenthesis)
5471 				{
5472 					param_pos[param_count][1] = F_NewPos(qb) - 2;
5473 					param_count++;
5474 					param_pos[param_count][0] =
5475 					param_pos[param_count][1] = -1;
5476 				}
5477 				if (output_count)
5478 					*output_count = F_NewPos(qb);
5479 				break;
5480 
5481 			case ODBC_ESCAPE_END:
5482 				stop = (0 == innerParenthesis);
5483 				break;
5484 
5485 		}
5486 		if (stop) /* returns with the last } position */
5487 			break;
5488 	}
5489 	if (param_pos[param_count][0] >= 0)
5490 	{
5491 		MYLOG(0, "closing ) not found %d\n", innerParenthesis);
5492 		qb->errornumber = STMT_EXEC_ERROR;
5493 		qb->errormsg = "processParameters closing ) not found";
5494 		return SQL_ERROR;
5495 	}
5496 	else if (1 == param_count) /* the 1 parameter is really valid ? */
5497 	{
5498 		BOOL	param_exist = FALSE;
5499 		SQLLEN	i;
5500 
5501 		for (i = param_pos[0][0]; i <= param_pos[0][1]; i++)
5502 		{
5503 			if (IS_NOT_SPACE(qb->query_statement[i]))
5504 			{
5505 				param_exist = TRUE;
5506 				break;
5507 			}
5508 		}
5509 		if (!param_exist)
5510 		{
5511 			param_pos[0][0] = param_pos[0][1] = -1;
5512 		}
5513 	}
5514 
5515 	return SQL_SUCCESS;
5516 }
5517 
5518 /*
5519  * convert_escape()
5520  * This function doesn't return a pointer to static memory any longer !
5521  */
5522 static int
convert_escape(QueryParse * qp,QueryBuild * qb)5523 convert_escape(QueryParse *qp, QueryBuild *qb)
5524 {
5525 	RETCODE	retval = SQL_SUCCESS;
5526 	char		buf[1024], buf_small[128], key[65];
5527 	UCHAR	ucv;
5528 	UInt4		prtlen;
5529 
5530 	QueryBuild	nqb;
5531 	BOOL	nqb_is_valid = FALSE;
5532 
5533 	if (F_OldChar(qp) == ODBC_ESCAPE_START) /* skip the first { */
5534 		F_OldNext(qp);
5535 	/* Separate off the key, skipping leading and trailing whitespace */
5536 	while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
5537 		F_OldNext(qp);
5538 	/*
5539 	 * procedure calls
5540 	 */
5541 	/* '?=' to accept return values exists ? */
5542 	if (F_OldChar(qp) == '?')
5543 	{
5544 		qb->param_number++;
5545 		qb->proc_return = 1;
5546 		if (qb->stmt)
5547 			qb->stmt->proc_return = 1;
5548 		while (isspace((UCHAR) qp->statement[++qp->opos]));
5549 		if (F_OldChar(qp) != '=')
5550 		{
5551 			F_OldPrior(qp);
5552 			return SQL_SUCCESS;
5553 		}
5554 		while (isspace((UCHAR) qp->statement[++qp->opos]));
5555 	}
5556 
5557 	sscanf(F_OldPtr(qp), "%32s", key);
5558 	while ((ucv = F_OldChar(qp)) != '\0' && (IS_NOT_SPACE(ucv)))
5559 		F_OldNext(qp);
5560 	while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
5561 		F_OldNext(qp);
5562 
5563 	/* Avoid the concatenation of the function name with the previous word. Aceto */
5564 
5565 	if (stricmp(key, "call") == 0)
5566 	{
5567 		size_t funclen;
5568 		const UCHAR *next_token;
5569 
5570 		if (SQL_ERROR == QB_start_brace(qb))
5571 		{
5572 			retval = SQL_ERROR;
5573 			goto cleanup;
5574 		}
5575 		if (qb->num_io_params > 1 ||
5576 		    (0 == qb->proc_return))
5577 			CVT_APPEND_STR(qb, "SELECT * FROM ");
5578 		else
5579 			CVT_APPEND_STR(qb, "SELECT ");
5580 		funclen = findIdentifier((const UCHAR *) F_OldPtr(qp), qb->ccsc, &next_token);
5581 		if (next_token && ODBC_ESCAPE_END == *next_token)
5582 		{
5583 			CVT_APPEND_DATA(qb, F_OldPtr(qp), funclen);
5584 			CVT_APPEND_STR(qb, "()");
5585 			if (SQL_ERROR == QB_end_brace(qb))
5586 			{
5587 				retval = SQL_ERROR;
5588 				goto cleanup;
5589 			}
5590 			/* positioned at } */
5591 			qp->opos += ((const char *) next_token - F_OldPtr(qp));
5592 		}
5593 		else
5594 		{
5595 			/* Continue at inner_process_tokens loop */
5596 			F_OldPrior(qp);
5597 			return SQL_SUCCESS;
5598 		}
5599 	}
5600 	else if (stricmp(key, "d") == 0)
5601 	{
5602 		/* Literal; return the escape part adding type cast */
5603 		F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
5604 		prtlen = SPRINTF_FIXED(buf, "%s::date", buf_small);
5605 		CVT_APPEND_DATA(qb, buf, prtlen);
5606 		retval = QB_append_space_to_separate_identifiers(qb, qp);
5607 	}
5608 	else if (stricmp(key, "t") == 0)
5609 	{
5610 		/* Literal; return the escape part adding type cast */
5611 		F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
5612 		prtlen = SPRINTF_FIXED(buf, "%s::time", buf_small);
5613 		CVT_APPEND_DATA(qb, buf, prtlen);
5614 		retval = QB_append_space_to_separate_identifiers(qb, qp);
5615 	}
5616 	else if (stricmp(key, "ts") == 0)
5617 	{
5618 		/* Literal; return the escape part adding type cast */
5619 		F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
5620 		prtlen = SPRINTF_FIXED(buf, "%s::timestamp", buf_small);
5621 		CVT_APPEND_DATA(qb, buf, prtlen);
5622 		retval = QB_append_space_to_separate_identifiers(qb, qp);
5623 	}
5624 	else if (stricmp(key, "oj") == 0) /* {oj syntax support for 7.1 * servers */
5625 	{
5626 		if (qb->stmt)
5627 			SC_set_outer_join(qb->stmt);
5628 		retval = QB_start_brace(qb);
5629 		/* Continue at inner_process_tokens loop */
5630 		F_OldPrior(qp);
5631 		goto cleanup;
5632 	}
5633 	else if (stricmp(key, "escape") == 0) /* like escape syntax support for 7.1+ servers */
5634 	{
5635 		/* Literal; return the escape part adding type cast */
5636 		F_ExtractOldTo(qp, buf_small, ODBC_ESCAPE_END, sizeof(buf_small));
5637 		prtlen = SPRINTF_FIXED(buf, "%s %s", key, buf_small);
5638 		CVT_APPEND_DATA(qb, buf, prtlen);
5639 		retval = QB_append_space_to_separate_identifiers(qb, qp);
5640 	}
5641 	else if (stricmp(key, "fn") == 0)
5642 	{
5643 		const char *mapExpr;
5644 		int	i, param_count;
5645 		SQLLEN	from, to;
5646 		size_t	param_consumed;
5647 		SQLLEN	param_pos[16][2];
5648 		BOOL	cvt_func = FALSE;
5649 
5650 		/* Separate off the func name, skipping leading and trailing whitespace */
5651 		i = 0;
5652 		while ((ucv = F_OldChar(qp)) != '\0' && ucv != '(' &&
5653 			   (IS_NOT_SPACE(ucv)))
5654 		{
5655 			if (i < sizeof(key) - 1)
5656 				key[i++] = ucv;
5657 			F_OldNext(qp);
5658 		}
5659 		key[i] = '\0';
5660 		while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
5661 			F_OldNext(qp);
5662 
5663 		/*
5664 		 * We expect left parenthesis here, else return fn body as-is
5665 		 * since it is one of those "function constants".
5666 		 */
5667 		if (F_OldChar(qp) != '(')
5668 		{
5669 			CVT_APPEND_STR(qb, key);
5670 			goto cleanup;
5671 		}
5672 
5673 		/*
5674 		 * Process parameter list and inner escape
5675 		 * sequences
5676 		 * Aceto 2002-01-29
5677 		 */
5678 
5679 		QB_initialize_copy(&nqb, qb, 1024);
5680 		nqb_is_valid = TRUE;
5681 		if (retval = processParameters(qp, &nqb, &param_consumed, param_pos), retval == SQL_ERROR)
5682 		{
5683 			qb->errornumber = nqb.errornumber;
5684 			qb->errormsg = nqb.errormsg;
5685 			goto cleanup;
5686 		}
5687 
5688 		for (param_count = 0;; param_count++)
5689 		{
5690 			if (param_pos[param_count][0] < 0)
5691 				break;
5692 		}
5693 		if (param_count == 1 &&
5694 		    param_pos[0][1] < param_pos[0][0])
5695 			param_count = 0;
5696 
5697 		mapExpr = NULL;
5698 		if (stricmp(key, "convert") == 0)
5699 			cvt_func = TRUE;
5700 		else
5701 		{
5702 			char keyword[64] = "";
5703 
5704 			if (param_count > 0)
5705 			{
5706 				int i, from, to;
5707 				const char * p;
5708 
5709 				for (i = param_pos[0][0], p = nqb.query_statement + i; i <= param_pos[0][1] && isspace(*p); i++, p++)
5710 					;
5711 				from = i;
5712 				for (; i <= param_pos[0][1] && IS_NOT_SPACE(*p); i++, p++)
5713 					;
5714 				to = i - 1;
5715 				if (to >= from)
5716 				{
5717 					int	len = to - from + 1;
5718 
5719 					if (len < sizeof(keyword))
5720 					{
5721 						memcpy(keyword, nqb.query_statement + from, len);
5722 						keyword[len] = '\0';
5723 					}
5724 				}
5725 			}
5726 			mapExpr = mapFunction(key, param_count, keyword);
5727 		}
5728 		if (cvt_func)
5729 		{
5730 			if (2 == param_count)
5731 			{
5732 				BOOL add_cast = FALSE, add_quote = FALSE;
5733 				const char *pptr;
5734 
5735 				from = param_pos[0][0];
5736 				to = param_pos[0][1];
5737 				for (pptr = nqb.query_statement + from; *pptr && isspace((unsigned char) *pptr); pptr++)
5738 					;
5739 				if (LITERAL_QUOTE == *pptr)
5740 					;
5741 				else if ('-' == *pptr)
5742 					add_quote = TRUE;
5743 				else if (isdigit((unsigned char) *pptr))
5744 					add_quote = TRUE;
5745 				else
5746 					add_cast = TRUE;
5747 				if (add_quote)
5748 					CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
5749 				else if (add_cast)
5750 					CVT_APPEND_CHAR(qb, '(');
5751 				CVT_APPEND_DATA(qb, nqb.query_statement + from, to - from + 1);
5752 				if (add_quote)
5753 					CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
5754 				else if (add_cast)
5755 				{
5756 					const char *cast_form = NULL;
5757 					char	sqltype[32];
5758 					int	typel;
5759 
5760 					CVT_APPEND_CHAR(qb, ')');
5761 					from = param_pos[1][0];
5762 					to = param_pos[1][1];
5763 					typel = to - from + 1;
5764 					if (typel < sizeof(sqltype))
5765 					{
5766 						const char *type;
5767 
5768 						memcpy(sqltype, nqb.query_statement + from, typel);
5769 						sqltype[typel] = '\0';
5770 MYLOG(0, FORMAT_LEN "-" FORMAT_LEN " SQLtype=%s SQL_BIT=%d\n", to, from, sqltype, SQL_BIT);
5771 						for (type = sqltype; *type && isspace(*type); type++)
5772 							;
5773 						if (strncmp(type, "SQL_", 4) == 0)
5774 						{
5775 							type += 4;
5776 							if (strcmp(type, "INTEGER") == 0)
5777 								cast_form = "int4";
5778 							else if (strcmp(type, "CHAR") == 0)
5779 								cast_form = "varchar";
5780 							else if (strcmp(type, "VARCHAR") == 0)
5781 								cast_form = "varchar";
5782 							else if (strcmp(type, "LONGVARCHAR") == 0)
5783 								cast_form = "text";
5784 							else if (strcmp(type, "WCHAR") == 0)
5785 								cast_form = "varchar";
5786 							else if (strcmp(type, "WVARCHAR") == 0)
5787 								cast_form = "varchar";
5788 							else if (strcmp(type, "WLONGVARCHAR") == 0)
5789 								cast_form = "text";
5790 							else if (strcmp(type, "NUMERIC") == 0)
5791 								cast_form = "numeric";
5792 							else if (strcmp(type, "DOUBLE") == 0)
5793 								cast_form = "float8";
5794 							else if (strcmp(type, "FLOAT") == 0)
5795 								cast_form = "float8";
5796 							else if (strcmp(type, "REAL") == 0)
5797 								cast_form = "float4";
5798 							else if (strcmp(type, "BIGINT") == 0)
5799 								cast_form = "int8";
5800 							else if (strcmp(type, "DECIMAL") == 0)
5801 								cast_form = "numeric";
5802 							else if (strcmp(type, "SMALLINT") == 0)
5803 								cast_form = "int2";
5804 							else if (strcmp(type, "TYPE_DATE") == 0)
5805 								cast_form = "date";
5806 							else if (strcmp(type, "TYPE_TIME") == 0)
5807 								cast_form = "time";
5808 							else if (strcmp(type, "TYPE_TIMESTAMP") == 0)
5809 								cast_form = "timestamp";
5810 							else if (strcmp(type, "BIT") == 0)
5811 								cast_form = "bit";
5812 						}
5813 					}
5814 					if (NULL != cast_form)
5815 					{
5816 						CVT_APPEND_STR(qb, "::");
5817 						CVT_APPEND_STR(qb, cast_form);
5818 					}
5819 				}
5820 			}
5821 			else
5822 			{
5823 				qb->errornumber = STMT_EXEC_ERROR;
5824 				qb->errormsg = "convert param count must be 2";
5825 				retval = SQL_ERROR;
5826 			}
5827 		}
5828 		else if (mapExpr == NULL)
5829 		{
5830 			CVT_APPEND_STR(qb, key);
5831 			CVT_APPEND_DATA(qb, nqb.query_statement, nqb.npos);
5832 		}
5833 		else
5834 		{
5835 			const char *mapptr;
5836 			SQLLEN	paramlen;
5837 			int	pidx;
5838 
5839 			for (mapptr = mapExpr; *mapptr; mapptr++)
5840 			{
5841 				if (*mapptr != '$')
5842 				{
5843 					CVT_APPEND_CHAR(qb, *mapptr);
5844 					continue;
5845 				}
5846 				mapptr++;
5847 				if (*mapptr == '*')
5848 				{
5849 					from = 1;
5850 					to = param_consumed - 2;
5851 				}
5852 				else if (isdigit((unsigned char) *mapptr))
5853 				{
5854 					pidx = *mapptr - '0' - 1;
5855 					if (pidx < 0 ||
5856 					    param_pos[pidx][0] < 0)
5857 					{
5858 						qb->errornumber = STMT_EXEC_ERROR;
5859 						qb->errormsg = "param not found";
5860 						MYLOG(0, "%dth param not found for the expression %s\n", pidx + 1, mapExpr);
5861 						retval = SQL_ERROR;
5862 						break;
5863 					}
5864 					from = param_pos[pidx][0];
5865 					to = param_pos[pidx][1];
5866 				}
5867 				else
5868 				{
5869 					qb->errornumber = STMT_EXEC_ERROR;
5870 					qb->errormsg = "internal expression error";
5871 					MYLOG(0, "internal expression error %s\n", mapExpr);
5872 					retval = SQL_ERROR;
5873 					break;
5874 				}
5875 				paramlen = to - from + 1;
5876 				if (paramlen > 0)
5877 					CVT_APPEND_DATA(qb, nqb.query_statement + from, paramlen);
5878 			}
5879 		}
5880 		if (0 == qb->errornumber)
5881 		{
5882 			qb->errornumber = nqb.errornumber;
5883 			qb->errormsg = nqb.errormsg;
5884 		}
5885 		if (SQL_ERROR != retval)
5886 		{
5887 			qb->param_number = nqb.param_number;
5888 			qb->dollar_number = nqb.dollar_number;
5889 			qb->flags = nqb.flags;
5890 		}
5891 	}
5892 	else
5893 	{
5894 		/* Bogus key, leave untranslated */
5895 		retval = SQL_ERROR;
5896 	}
5897 
5898 cleanup:
5899 	if (nqb_is_valid)
5900 		QB_Destructor(&nqb);
5901 	return retval;
5902 }
5903 
5904 static BOOL
convert_money(const char * s,char * sout,size_t soutmax)5905 convert_money(const char *s, char *sout, size_t soutmax)
5906 {
5907 	char		in, decp = 0;
5908 	size_t		i = 0,
5909 				out = 0;
5910 	int	num_in = -1, period_in = -1, comma_in = -1;
5911 
5912 	for (i = 0; s[i]; i++)
5913 	{
5914 		switch (in = s[i])
5915 		{
5916 			case '.':
5917 				if (period_in < 0)
5918 					period_in = i;
5919 				break;
5920 			case ',':
5921 				if (comma_in < 0)
5922 					comma_in = i;
5923 				break;
5924 			default:
5925 				if ('0' <= in && '9' >= in)
5926 					num_in = i;
5927 				break;
5928 		}
5929 	}
5930 	if (period_in > comma_in)
5931 	{
5932 		if ( period_in >= num_in - 2)
5933 			decp = '.';
5934 	}
5935 	else if (comma_in >= 0 &&
5936 		 comma_in >= num_in - 2)
5937 		decp = ',';
5938 	for (i = 0; s[i] && out + 1 < soutmax; i++)
5939 	{
5940 		switch (in = s[i])
5941 		{
5942 			case '(':
5943 			case '-':
5944 				sout[out++] = '-';
5945 				break;
5946 			default:
5947 				if (in >= '0' && in <= '9')
5948 					sout[out++] = in;
5949 				else if (in == decp)
5950 					sout[out++] = '.';
5951 		}
5952 	}
5953 	sout[out] = '\0';
5954 	return TRUE;
5955 }
5956 
5957 
5958 /*
5959  *	This function parses a character string for date/time info and fills in SIMPLE_TIME
5960  *	It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
5961  */
5962 static char
parse_datetime(const char * buf,SIMPLE_TIME * st)5963 parse_datetime(const char *buf, SIMPLE_TIME *st)
5964 {
5965 	int			y,
5966 				m,
5967 				d,
5968 				hh,
5969 				mm,
5970 				ss;
5971 	int			nf;
5972 	BOOL	bZone;	int	zone;
5973 
5974 	y = m = d = hh = mm = ss = 0;
5975 	st->fr = 0;
5976 	st->infinity = 0;
5977 
5978 	/*
5979 	 * Handle ODBC time/date/timestamp literals, e.g.
5980 	 * { d '2011-04-22' }
5981 	 * { t '12:34:56' }
5982 	 * { ts '2011-04-22 12:34:56' }
5983 	 */
5984 	if (buf[0] == ODBC_ESCAPE_START)
5985 	{
5986 		while (*(++buf) && *buf != LITERAL_QUOTE);
5987 		if (!(*buf))
5988 			return FALSE;
5989 		buf++;
5990 	}
5991 	bZone = FALSE;
5992 	if (timestamp2stime(buf, st, &bZone, &zone))
5993 		return TRUE;
5994 	if (buf[4] == '-')			/* year first */
5995 		nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh, &mm, &ss);
5996 	else
5997 		nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh, &mm, &ss);
5998 
5999 	if (nf == 5 || nf == 6)
6000 	{
6001 		st->y = y;
6002 		st->m = m;
6003 		st->d = d;
6004 		st->hh = hh;
6005 		st->mm = mm;
6006 		st->ss = ss;
6007 
6008 		return TRUE;
6009 	}
6010 
6011 	if (buf[4] == '-')			/* year first */
6012 		nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
6013 	else
6014 		nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);
6015 
6016 	if (nf == 3)
6017 	{
6018 		st->y = y;
6019 		st->m = m;
6020 		st->d = d;
6021 
6022 		return TRUE;
6023 	}
6024 
6025 	nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
6026 	if (nf == 2 || nf == 3)
6027 	{
6028 		st->hh = hh;
6029 		st->mm = mm;
6030 		st->ss = ss;
6031 
6032 		return TRUE;
6033 	}
6034 
6035 	return FALSE;
6036 }
6037 
6038 
6039 /*	Change linefeed to carriage-return/linefeed */
6040 size_t
convert_linefeeds(const char * si,char * dst,size_t max,BOOL convlf,BOOL * changed)6041 convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf, BOOL *changed)
6042 {
6043 	size_t		i = 0,
6044 				out = 0;
6045 
6046 	if (max == 0)
6047 		max = 0xffffffff;
6048 	*changed = FALSE;
6049 	for (i = 0; si[i] && out < max - 1; i++)
6050 	{
6051 		if (convlf && si[i] == '\n')
6052 		{
6053 			/* Only add the carriage-return if needed */
6054 			if (i > 0 && PG_CARRIAGE_RETURN == si[i - 1])
6055 			{
6056 				if (dst)
6057 					dst[out++] = si[i];
6058 				else
6059 					out++;
6060 				continue;
6061 			}
6062 			*changed = TRUE;
6063 
6064 			if (dst)
6065 			{
6066 				dst[out++] = PG_CARRIAGE_RETURN;
6067 				dst[out++] = '\n';
6068 			}
6069 			else
6070 				out += 2;
6071 		}
6072 		else
6073 		{
6074 			if (dst)
6075 				dst[out++] = si[i];
6076 			else
6077 				out++;
6078 		}
6079 	}
6080 	if (dst)
6081 		dst[out] = '\0';
6082 	return out;
6083 }
6084 
6085 
6086 /*
6087  *	Change carriage-return/linefeed to just linefeed
6088  *	Plus, escape any special characters.
6089  */
6090 static BOOL
convert_special_chars(QueryBuild * qb,const char * si,size_t used)6091 convert_special_chars(QueryBuild *qb, const char *si, size_t used)
6092 {
6093 	size_t		i = 0,
6094 				max;
6095 	char		tchar;
6096 	encoded_str	encstr;
6097 	BOOL	convlf = (0 != (qb->flags & FLGB_CONVERT_LF));
6098 	BOOL	double_special = (qb->param_mode != RPM_BUILDING_BIND_REQUEST);
6099 	int		ccsc = qb->ccsc;
6100 	char		escape_in_literal = CC_get_escape(qb->conn);
6101 
6102 	if (used == SQL_NTS)
6103 		max = strlen(si);
6104 	else
6105 		max = used;
6106 
6107 	/*
6108 	 * Make sure there's room for the null-terminator, if the input is an
6109 	 * empty string. XXX: I don't think the null-termination is actually
6110 	 * even required, but better safe than sorry.
6111 	 */
6112 	if (!enlarge_query_statement(qb, qb->npos + 1))
6113 		return FALSE;
6114 
6115 	encoded_str_constr(&encstr, ccsc, si);
6116 	for (i = 0; i < max && si[i]; i++)
6117 	{
6118 		tchar = encoded_nextchar(&encstr);
6119 
6120 		/*
6121 		 * Make sure there is room for three more bytes in the buffer. We
6122 		 * expand quotes to two bytes, plus null-terminate the end.
6123 		 */
6124 		if (qb->npos + 3 >= qb->str_alsize)
6125 		{
6126 			if (!enlarge_query_statement(qb, qb->npos + 3))
6127 				return FALSE;
6128 		}
6129 
6130 		if (MBCS_NON_ASCII(encstr))
6131 		{
6132 			qb->query_statement[qb->npos++] = tchar;
6133 			continue;
6134 		}
6135 		if (convlf &&	/* CR/LF -> LF */
6136 		    PG_CARRIAGE_RETURN == tchar &&
6137 		    PG_LINEFEED == si[i + 1])
6138 			continue;
6139 		else if (double_special && /* double special chars ? */
6140 			 (tchar == LITERAL_QUOTE ||
6141 			  tchar == escape_in_literal))
6142 		{
6143 			qb->query_statement[qb->npos++] = tchar;
6144 		}
6145 		qb->query_statement[qb->npos++] = tchar;
6146 	}
6147 
6148 	qb->query_statement[qb->npos] = '\0';
6149 
6150 	return TRUE;
6151 }
6152 
6153 static int
conv_from_octal(const char * s)6154 conv_from_octal(const char *s)
6155 {
6156 	ssize_t			i;
6157 	int			y = 0;
6158 
6159 	for (i = 1; i <= 3; i++)
6160 		y += (s[i] - '0') << (3 * (3 - i));
6161 
6162 	return y;
6163 }
6164 
6165 
6166 /*	convert octal escapes to bytes */
6167 static size_t
convert_from_pgbinary(const char * value,char * rgbValue,SQLLEN cbValueMax)6168 convert_from_pgbinary(const char *value, char *rgbValue, SQLLEN cbValueMax)
6169 {
6170 	size_t		i,
6171 				ilen = strlen(value);
6172 	size_t			o = 0;
6173 
6174 	for (i = 0; i < ilen;)
6175 	{
6176 		if (value[i] == BYTEA_ESCAPE_CHAR)
6177 		{
6178 			if (value[i + 1] == BYTEA_ESCAPE_CHAR)
6179 			{
6180 				if (rgbValue)
6181 					rgbValue[o] = value[i];
6182 				o++;
6183 				i += 2;
6184 			}
6185 			else if (value[i + 1] == 'x')
6186 			{
6187 				i += 2;
6188 				if (i < ilen)
6189 				{
6190 					ilen -= i;
6191 					if (rgbValue)
6192 						pg_hex2bin(value + i, rgbValue + o, ilen);
6193 					o += ilen / 2;
6194 				}
6195 				break;
6196 			}
6197 			else
6198 			{
6199 				if (rgbValue)
6200 					rgbValue[o] = conv_from_octal(&value[i]);
6201 				o++;
6202 				i += 4;
6203 			}
6204 		}
6205 		else
6206 		{
6207 			if (rgbValue)
6208 				rgbValue[o] = value[i];
6209 			o++;
6210 			i++;
6211 		}
6212 		/** if (rgbValue)
6213 			MYLOG(0, "i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]); ***/
6214 	}
6215 
6216 	if (rgbValue)
6217 		rgbValue[o] = '\0';		/* extra protection */
6218 
6219 	MYLOG(0, "in=" FORMAT_SIZE_T ", out = " FORMAT_SIZE_T "\n", ilen, o);
6220 
6221 	return o;
6222 }
6223 
6224 
6225 static UInt2
conv_to_octal(UCHAR val,char * octal,char escape_ch)6226 conv_to_octal(UCHAR val, char *octal, char escape_ch)
6227 {
6228 	int	i, pos = 0, len;
6229 
6230 	if (escape_ch)
6231 		octal[pos++] = escape_ch;
6232 	octal[pos] = BYTEA_ESCAPE_CHAR;
6233 	len = 4 + pos;
6234 	octal[len] = '\0';
6235 
6236 	for (i = len - 1; i > pos; i--)
6237 	{
6238 		octal[i] = (val & 7) + '0';
6239 		val >>= 3;
6240 	}
6241 
6242 	return (UInt2) len;
6243 }
6244 
6245 
6246 static char *
conv_to_octal2(UCHAR val,char * octal)6247 conv_to_octal2(UCHAR val, char *octal)
6248 {
6249 	int			i;
6250 
6251 	octal[0] = BYTEA_ESCAPE_CHAR;
6252 	octal[4] = '\0';
6253 
6254 	for (i = 3; i > 0; i--)
6255 	{
6256 		octal[i] = (val & 7) + '0';
6257 		val >>= 3;
6258 	}
6259 
6260 	return octal;
6261 }
6262 
6263 
6264 /*	convert non-ascii bytes to octal escape sequences */
6265 static size_t
convert_to_pgbinary(const char * in,char * out,size_t len,QueryBuild * qb)6266 convert_to_pgbinary(const char *in, char *out, size_t len, QueryBuild *qb)
6267 {
6268 	UCHAR	inc;
6269 	size_t			i, o = 0;
6270 	char	escape_in_literal = CC_get_escape(qb->conn);
6271 	BOOL	esc_double = (qb->param_mode != RPM_BUILDING_BIND_REQUEST &&
6272 						  0 != escape_in_literal);
6273 
6274 	/* use hex format for 9.0 or later servers */
6275 	if (0 != (qb->flags & FLGB_HEX_BIN_FORMAT))
6276 	{
6277 		if (esc_double)
6278 			out[o++] = escape_in_literal;
6279 		out[o++] = '\\';
6280 		out[o++] = 'x';
6281 		o += pg_bin2hex(in, out + o, len);
6282 		return o;
6283 	}
6284 	for (i = 0; i < len; i++)
6285 	{
6286 		inc = in[i];
6287 		MYLOG(DETAIL_LOG_LEVEL, "in[" FORMAT_SIZE_T "] = %d, %c\n", i, inc, inc);
6288 		if (inc < 128 && (isalnum(inc) || inc == ' '))
6289 			out[o++] = inc;
6290 		else
6291 		{
6292 			if (esc_double)
6293 			{
6294 				o += conv_to_octal(inc, &out[o], escape_in_literal);
6295 			}
6296 			else
6297 			{
6298 				conv_to_octal2(inc, &out[o]);
6299 				o += 4;
6300 			}
6301 		}
6302 	}
6303 
6304 	MYLOG(0, "leaving " FORMAT_SIZE_T ", out='%.*s'\n", o, (int) o, out);
6305 
6306 	return o;
6307 }
6308 
6309 
6310 static const char *hextbl = "0123456789ABCDEF";
6311 
6312 #define	def_bin2hex(type) \
6313 	(const char *src, type *dst, SQLLEN length) \
6314 { \
6315 	const char	*src_wk; \
6316 	UCHAR		chr; \
6317 	type		*dst_wk; \
6318 	BOOL		backwards; \
6319 	int		i; \
6320  \
6321 	backwards = FALSE; \
6322 	if ((char *) dst < src) \
6323 	{ \
6324 		if ((char *) (dst + 2 * (length - 1)) > src + length - 1) \
6325 			return -1; \
6326 	} \
6327 	else if ((char *) dst < src + length) \
6328 		backwards = TRUE; \
6329 	if (backwards) \
6330 	{ \
6331 		for (i = 0, src_wk = src + length - 1, dst_wk = dst + 2 * length - 1; i < length; i++, src_wk--) \
6332 		{ \
6333 			chr = *src_wk; \
6334 			*dst_wk-- = hextbl[chr % 16]; \
6335 			*dst_wk-- = hextbl[chr >> 4]; \
6336 		} \
6337 	} \
6338 	else \
6339 	{ \
6340 		for (i = 0, src_wk = src, dst_wk = dst; i < length; i++, src_wk++) \
6341 		{ \
6342 			chr = *src_wk; \
6343 			*dst_wk++ = hextbl[chr >> 4]; \
6344 			*dst_wk++ = hextbl[chr % 16]; \
6345 		} \
6346 	} \
6347 	dst[2 * length] = '\0'; \
6348 	return 2 * length * sizeof(type); \
6349 }
6350 #ifdef	UNICODE_SUPPORT
6351 static SQLLEN
def_bin2hex(SQLWCHAR)6352 pg_bin2whex def_bin2hex(SQLWCHAR)
6353 #endif /* UNICODE_SUPPORT */
6354 
6355 static SQLLEN
6356 pg_bin2hex def_bin2hex(char)
6357 
6358 SQLLEN
6359 pg_hex2bin(const char *src, char *dst, SQLLEN length)
6360 {
6361 	UCHAR		chr;
6362 	const char *src_wk;
6363 	char	   *dst_wk;
6364 	SQLLEN		i;
6365 	int		val;
6366 	BOOL		HByte = TRUE;
6367 
6368 	for (i = 0, src_wk = src, dst_wk = dst; i < length; i++, src_wk++)
6369 	{
6370 		chr = *src_wk;
6371 		if (!chr)
6372 			break;
6373 		if (chr >= 'a' && chr <= 'f')
6374 			val = chr - 'a' + 10;
6375 		else if (chr >= 'A' && chr <= 'F')
6376 			val = chr - 'A' + 10;
6377 		else
6378 			val = chr - '0';
6379 		if (HByte)
6380 			*dst_wk = (val << 4);
6381 		else
6382 		{
6383 			*dst_wk += val;
6384 			dst_wk++;
6385 		}
6386 		HByte = !HByte;
6387 	}
6388 	*dst_wk = '\0';
6389 	return length;
6390 }
6391 
6392 /*-------
6393  *	1. get oid (from 'value')
6394  *	2. open the large object
6395  *	3. read from the large object (handle multiple GetData)
6396  *	4. close when read less than requested?  -OR-
6397  *		lseek/read each time
6398  *		handle case where application receives truncated and
6399  *		decides not to continue reading.
6400  *
6401  *	CURRENTLY, ONLY LONGVARBINARY is handled, since that is the only
6402  *	data type currently mapped to a PG_TYPE_LO.  But, if any other types
6403  *	are desired to map to a large object (PG_TYPE_LO), then that would
6404  *	need to be handled here.  For example, LONGVARCHAR could possibly be
6405  *	mapped to PG_TYPE_LO someday, instead of PG_TYPE_TEXT as it is now.
6406  *-------
6407  */
6408 static int
convert_lo(StatementClass * stmt,const void * value,SQLSMALLINT fCType,PTR rgbValue,SQLLEN cbValueMax,SQLLEN * pcbValue)6409 convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType, PTR rgbValue,
6410 		   SQLLEN cbValueMax, SQLLEN *pcbValue)
6411 {
6412 	CSTR	func = "convert_lo";
6413 	OID			oid;
6414 	int			result;
6415 	Int8			retval;
6416 	Int8		left64 = -1;
6417 	struct GetBlobDataClass *gdata_blob = NULL;
6418 	ConnectionClass *conn = SC_get_conn(stmt);
6419 	ConnInfo   *ci = &(conn->connInfo);
6420 	GetDataInfo	*gdata_info = SC_get_GDTI(stmt);
6421 	int			factor;
6422 
6423 	oid = ATOI32U(value);
6424 	if (0 == oid)
6425 	{
6426 		if (pcbValue)
6427 			*pcbValue = SQL_NULL_DATA;
6428 		return COPY_OK;
6429 	}
6430 	switch (fCType)
6431 	{
6432 		case SQL_C_CHAR:
6433 			factor = 2;
6434 			break;
6435 		case SQL_C_BINARY:
6436 			factor = 1;
6437 			break;
6438 		default:
6439 			SC_set_error(stmt, STMT_EXEC_ERROR, "Could not convert lo to the c-type", func);
6440 			return COPY_GENERAL_ERROR;
6441 	}
6442 	/* If using SQLGetData, then current_col will be set */
6443 	if (stmt->current_col >= 0)
6444 	{
6445 		gdata_blob = &(gdata_info->gdata[stmt->current_col].blob);
6446 		left64 = gdata_blob->data_left64;
6447 	}
6448 
6449 	/*
6450 	 * if this is the first call for this column, open the large object
6451 	 * for reading
6452 	 */
6453 
6454 	if (!gdata_blob || gdata_blob->data_left64 == -1)
6455 	{
6456 		/* begin transaction if needed */
6457 		if (!CC_is_in_trans(conn))
6458 		{
6459 			if (!CC_begin(conn))
6460 			{
6461 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction", func);
6462 				return COPY_GENERAL_ERROR;
6463 			}
6464 		}
6465 
6466 		stmt->lobj_fd = odbc_lo_open(conn, oid, INV_READ);
6467 		if (stmt->lobj_fd < 0)
6468 		{
6469 			SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for reading.", func);
6470 			return COPY_GENERAL_ERROR;
6471 		}
6472 
6473 		/* Get the size */
6474 		retval = odbc_lo_lseek64(conn, stmt->lobj_fd, 0L, SEEK_END);
6475 		if (retval >= 0)
6476 		{
6477 			left64 = odbc_lo_tell64(conn, stmt->lobj_fd);
6478 			if (gdata_blob)
6479 				gdata_blob->data_left64 = left64;
6480 
6481 			/* return to beginning */
6482 			odbc_lo_lseek64(conn, stmt->lobj_fd, 0L, SEEK_SET);
6483 		}
6484 	}
6485 	else if (left64 == 0)
6486 		return COPY_NO_DATA_FOUND;
6487 	MYLOG(0, "lo data left = " FORMATI64 "\n", left64);
6488 
6489 	if (stmt->lobj_fd < 0)
6490 	{
6491 		SC_set_error(stmt, STMT_EXEC_ERROR, "Large object FD undefined for multiple read.", func);
6492 		return COPY_GENERAL_ERROR;
6493 	}
6494 
6495 	if (0 >= cbValueMax)
6496 		retval = 0;
6497 	else
6498 		retval = (Int8) odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, (Int4) (factor > 1 ? (cbValueMax - 1) / factor : cbValueMax));
6499 	if (retval < 0)
6500 	{
6501 		odbc_lo_close(conn, stmt->lobj_fd);
6502 
6503 		/* commit transaction if needed */
6504 		if (!ci->drivers.use_declarefetch && CC_does_autocommit(conn))
6505 		{
6506 			if (!CC_commit(conn))
6507 			{
6508 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
6509 				return COPY_GENERAL_ERROR;
6510 			}
6511 		}
6512 
6513 		stmt->lobj_fd = -1;
6514 
6515 		SC_set_error(stmt, STMT_EXEC_ERROR, "Error reading from large object.", func);
6516 		return COPY_GENERAL_ERROR;
6517 	}
6518 
6519 	if (factor > 1)
6520 		pg_bin2hex((char *) rgbValue, (char *) rgbValue, retval);
6521 	if (retval < left64)
6522 		result = COPY_RESULT_TRUNCATED;
6523 	else
6524 		result = COPY_OK;
6525 
6526 	if (pcbValue)
6527 	{
6528 		Int8	leftbytes = left64 * factor;
6529 		*pcbValue = left64 < 0 ? SQL_NO_TOTAL : (leftbytes == (SQLLEN) leftbytes ? leftbytes : /* exceeds SQLLEN limit */ SQL_NO_TOTAL);
6530 	}
6531 
6532 	if (gdata_blob && gdata_blob->data_left64 > 0)
6533 		gdata_blob->data_left64 -= retval;
6534 
6535 	if (!gdata_blob || gdata_blob->data_left64 == 0)
6536 	{
6537 		odbc_lo_close(conn, stmt->lobj_fd);
6538 
6539 		/* commit transaction if needed */
6540 		if (!ci->drivers.use_declarefetch && CC_does_autocommit(conn))
6541 		{
6542 			if (!CC_commit(conn))
6543 			{
6544 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
6545 				return COPY_GENERAL_ERROR;
6546 			}
6547 		}
6548 
6549 		stmt->lobj_fd = -1;		/* prevent further reading */
6550 	}
6551 
6552 	return result;
6553 }
6554