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 "notice.txt" for copyright and license information.
16  *
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 
28 #include "psqlodbc.h"
29 
30 #ifndef WIN32
31 #include "isql.h"
32 #include "isqlext.h"
33 #else
34 #include <windows.h>
35 #include <sql.h>
36 #include <sqlext.h>
37 #endif
38 
39 #include <time.h>
40 #ifdef HAVE_LOCALE_H
41 #include <locale.h>
42 #endif
43 #include <math.h>
44 #include "convert.h"
45 #include "statement.h"
46 #include "qresult.h"
47 #include "bind.h"
48 #include "pgtypes.h"
49 #include "lobj.h"
50 #include "connection.h"
51 
52 #ifndef WIN32
53 #ifndef HAVE_STRICMP
54 #define stricmp(s1,s2) strcasecmp(s1,s2)
55 #define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
56 #endif
57 #endif
58 
59 extern GLOBAL_VALUES globals;
60 
61 /*	How to map ODBC scalar functions {fn func(args)} to Postgres
62  *	This is just a simple substitution
63  *	List augmented from
64  *	 http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
65  * - thomas 2000-04-03
66  */
67 char* const mapFuncs[][2] = {
68 /*	{ "ASCII",       "ascii"      }, */
69 	{ "CHAR",        "chr"        },
70 	{ "CONCAT",      "textcat"    },
71 /*	{ "DIFFERENCE",  "difference" }, */
72 /*	{ "INSERT",      "insert"     }, */
73 	{ "LCASE",       "lower"      },
74 	{ "LEFT",        "ltrunc"     },
75 	{ "LOCATE",      "strpos"     },
76 	{ "LENGTH",      "char_length"},
77 /*	{ "LTRIM",       "ltrim"      }, */
78 	{ "RIGHT",       "rtrunc"     },
79 /*	{ "REPEAT",      "repeat"     }, */
80 /*	{ "REPLACE",     "replace"    }, */
81 /*	{ "RTRIM",       "rtrim"      }, */
82 /*	{ "SOUNDEX",     "soundex"    }, */
83 	{ "SUBSTRING",   "substr"     },
84 	{ "UCASE",       "upper"      },
85 
86 /*	{ "ABS",         "abs"        }, */
87 /*	{ "ACOS",        "acos"       }, */
88 /*	{ "ASIN",        "asin"       }, */
89 /*	{ "ATAN",        "atan"       }, */
90 /*	{ "ATAN2",       "atan2"      }, */
91 	{ "CEILING",     "ceil"       },
92 /*	{ "COS",         "cos"        }, */
93 /*	{ "COT",         "cot"        }, */
94 /*	{ "DEGREES",     "degrees"    }, */
95 /*	{ "EXP",         "exp"        }, */
96 /*	{ "FLOOR",       "floor"      }, */
97 	{ "LOG",         "ln"         },
98 	{ "LOG10",       "log"        },
99 /*	{ "MOD",         "mod"        }, */
100 /*	{ "PI",          "pi"         }, */
101 	{ "POWER",       "pow"        },
102 /*	{ "RADIANS",     "radians"    }, */
103 	{ "RAND",        "random"     },
104 /*	{ "ROUND",       "round"      }, */
105 /*	{ "SIGN",        "sign"       }, */
106 /*	{ "SIN",         "sin"        }, */
107 /*	{ "SQRT",        "sqrt"       }, */
108 /*	{ "TAN",         "tan"        }, */
109 	{ "TRUNCATE",    "trunc"      },
110 
111 /*	{ "CURDATE",     "curdate"    }, */
112 /*	{ "CURTIME",     "curtime"    }, */
113 /*	{ "DAYNAME",     "dayname"    }, */
114 /*	{ "DAYOFMONTH",  "dayofmonth" }, */
115 /*	{ "DAYOFWEEK",   "dayofweek"  }, */
116 /*	{ "DAYOFYEAR",   "dayofyear"  }, */
117 /*	{ "HOUR",        "hour"       }, */
118 /*	{ "MINUTE",      "minute"     }, */
119 /*	{ "MONTH",       "month"      }, */
120 /*	{ "MONTHNAME",   "monthname"  }, */
121 /*	{ "NOW",         "now"        }, */
122 /*	{ "QUARTER",     "quarter"    }, */
123 /*	{ "SECOND",      "second"     }, */
124 /*	{ "WEEK",        "week"       }, */
125 /*	{ "YEAR",        "year"       }, */
126 
127 /*	{ "DATABASE",    "database"   }, */
128 	{ "IFNULL",      "coalesce"   },
129 	{ "USER",        "odbc_user"  },
130 	{    0,             0         }
131 };
132 
133 char *mapFunction(char *func);
134 unsigned int conv_from_octal(unsigned char *s);
135 unsigned int conv_from_hex(unsigned char *s);
136 char *conv_to_octal(unsigned char val);
137 
138 /********		A Guide for date/time/timestamp conversions    **************
139 
140 			field_type		fCType				Output
141 			----------		------				----------
142 			PG_TYPE_DATE	SQL_C_DEFAULT		SQL_C_DATE
143 			PG_TYPE_DATE	SQL_C_DATE			SQL_C_DATE
144 			PG_TYPE_DATE	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(time = 0 (midnight))
145 			PG_TYPE_TIME	SQL_C_DEFAULT		SQL_C_TIME
146 			PG_TYPE_TIME	SQL_C_TIME			SQL_C_TIME
147 			PG_TYPE_TIME	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(date = current date)
148 			PG_TYPE_ABSTIME	SQL_C_DEFAULT		SQL_C_TIMESTAMP
149 			PG_TYPE_ABSTIME	SQL_C_DATE			SQL_C_DATE			(time is truncated)
150 			PG_TYPE_ABSTIME	SQL_C_TIME			SQL_C_TIME			(date is truncated)
151 			PG_TYPE_ABSTIME	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP
152 ******************************************************************************/
153 
154 
155 /*	This is called by SQLFetch() */
156 int
copy_and_convert_field_bindinfo(StatementClass * stmt,Int4 field_type,void * value,int col)157 copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
158 {
159 BindInfoClass *bic = &(stmt->bindings[col]);
160 
161 	return copy_and_convert_field(stmt, field_type, value, (Int2)bic->returntype, (PTR)bic->buffer,
162                                 (SDWORD)bic->buflen, (SQLLEN *)bic->used);
163 }
164 
setup_ts(SIMPLE_TIME st)165 static void setup_ts( SIMPLE_TIME st )
166 {
167     time_t t = time( NULL );
168     struct tm *tim;
169 
170 #ifdef HAVE_LOCALTIME_R
171 struct tm tp;
172 #endif
173 
174 #ifdef HAVE_LOCALTIME_R
175     tim = localtime_r(&t, &tp);
176 #else
177     tim = localtime(&t);
178 #endif
179     st.m = tim->tm_mon + 1;
180     st.d = tim->tm_mday;
181     st.y = tim->tm_year + 1900;
182     st.hh = tim->tm_hour;
183 	st.mm = tim->tm_min;
184 	st.ss = tim->tm_sec;
185 }
186 
187 /*	This is called by SQLGetData() */
188 int
copy_and_convert_field(StatementClass * stmt,Int4 field_type,void * value,Int2 fCType,PTR rgbValue,SDWORD cbValueMax,SQLLEN * pcbValue)189 copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
190 					   PTR rgbValue, SDWORD cbValueMax, SQLLEN *pcbValue)
191 {
192 	Int4 len = 0, copy_len = 0;
193 	SIMPLE_TIME st;
194 	time_t t;
195 	struct tm *tim;
196 	int pcbValueOffset, rgbValueOffset;
197 	char *rgbValueBindRow, *ptr;
198 	int bind_row = stmt->bind_row;
199 	int bind_size = stmt->options.bind_size;
200 	int result = COPY_OK;
201 /*	char tempBuf[TEXT_FIELD_SIZE+5]; */
202 	char *tempBuf;
203 #ifdef HAVE_LOCALE_H
204 	char saved_locale[256];
205 #endif
206 #ifdef HAVE_LOCALTIME_R
207 struct tm tp;
208 #endif
209 
210 /*	rgbValueOffset is *ONLY* for character and binary data */
211 /*	pcbValueOffset is for computing any pcbValue location */
212 	tempBuf = (char *) malloc(TEXT_FIELD_SIZE+5);
213 	if (bind_size > 0) {
214 
215 		pcbValueOffset = rgbValueOffset = (bind_size * bind_row);
216 	}
217 	else {
218 
219 		pcbValueOffset = bind_row * sizeof(SDWORD);
220 		rgbValueOffset = bind_row * cbValueMax;
221 
222 	}
223 
224 	memset(&st, 0, sizeof(SIMPLE_TIME));
225 
226 	mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType,  (value==NULL)?"<NULL>":value, cbValueMax);
227 
228 	if ( ! value) {
229         /* handle a null just by returning SQL_NULL_DATA in pcbValue, */
230         /* and doing nothing to the buffer.                           */
231         if(pcbValue) {
232 			*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA;
233         }
234 		free(tempBuf);
235 		return COPY_OK;
236 	}
237 
238 
239 	if (stmt->hdbc->DataSourceToDriver != NULL) {
240 		int length = strlen (value);
241 		stmt->hdbc->DataSourceToDriver (stmt->hdbc->translation_option,
242 										SQL_CHAR,
243 										value, length,
244 										value, length, NULL,
245 										NULL, 0, NULL);
246 	}
247 
248 
249 	/********************************************************************
250 		First convert any specific postgres types into more
251 		useable data.
252 
253 		NOTE: Conversions from PG char/varchar of a date/time/timestamp
254 		value to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
255 	*********************************************************************/
256 	switch(field_type) {
257 	/*  $$$ need to add parsing for date/time/timestamp strings in PG_TYPE_CHAR,VARCHAR $$$ */
258 	case PG_TYPE_DATE:
259         setup_ts( st );
260 		sscanf(value, "%4d-%2d-%2d", &st.y, &st.m, &st.d);
261 		break;
262 
263 	case PG_TYPE_TIME:
264         setup_ts( st );
265 		sscanf(value, "%2d:%2d:%2d", &st.hh, &st.mm, &st.ss);
266 		break;
267 
268 	case PG_TYPE_ABSTIME:
269 	case PG_TYPE_DATETIME:
270 	case PG_TYPE_TIMESTAMP:
271     case PG_TYPE_TIMESTAMP_NO_TMZONE:
272         setup_ts( st );
273 		if (strnicmp(value, "invalid", 7) != 0) {
274 			sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);
275 
276 		} else {	/* The timestamp is invalid so set something conspicuous, like the epoch */
277 			t = 0;
278 #ifdef HAVE_LOCALTIME_R
279 			tim = localtime_r(&t, &tp);
280 #else
281 			tim = localtime(&t);
282 #endif
283 			st.m = tim->tm_mon + 1;
284 			st.d = tim->tm_mday;
285 			st.y = tim->tm_year + 1900;
286 			st.hh = tim->tm_hour;
287 			st.mm = tim->tm_min;
288 			st.ss = tim->tm_sec;
289 		}
290 		break;
291 
292 	case PG_TYPE_BOOL: {		/* change T/F to 1/0 */
293 		char *s = (char *) value;
294 		if (s[0] == 'T' || s[0] == 't')
295 			s[0] = '1';
296 		else
297 			s[0] = '0';
298 		}
299 		break;
300 
301 	/* This is for internal use by SQLStatistics() */
302 	case PG_TYPE_INT2VECTOR: {
303 		int nval, i;
304 		char *vp;
305 		/* this is an array of eight integers */
306 		short *short_array = (short *) ( (char *) rgbValue + rgbValueOffset);
307 
308 		len = 16;
309 		vp = value;
310 		nval = 0;
311 		for (i = 0; i < 8; i++)
312 		{
313 			if (sscanf(vp, "%hd", &short_array[i]) != 1)
314 				break;
315 
316 			nval++;
317 
318 			/* skip the current token */
319 			while ((*vp != '\0') && (! isspace((unsigned char) *vp))) vp++;
320 			/* and skip the space to the next token */
321 			while ((*vp != '\0') && (isspace((unsigned char) *vp))) vp++;
322 			if (*vp == '\0')
323 				break;
324 		}
325 
326 		for (i = nval; i < 8; i++)
327 		{
328 			short_array[i] = 0;
329 		}
330 
331 #if 0
332 		sscanf(value, "%hd %hd %hd %hd %hd %hd %hd %hd",
333 			&short_array[0],
334 			&short_array[1],
335 			&short_array[2],
336 			&short_array[3],
337 			&short_array[4],
338 			&short_array[5],
339 			&short_array[6],
340 			&short_array[7]);
341 #endif
342 
343 		/*  There is no corresponding fCType for this. */
344 		if(pcbValue)
345 			*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
346 		free(tempBuf);
347 		return COPY_OK;		/* dont go any further or the data will be trashed */
348 	}
349 
350 	/* This is a large object OID, which is used to store LONGVARBINARY objects. */
351 	case PG_TYPE_LO:
352 		free(tempBuf);
353 		return convert_lo( stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset));
354 
355 	default:
356 
357 		if (field_type == stmt->hdbc->lobj_type)	/* hack until permanent type available */
358 		{	free(tempBuf);
359 			return convert_lo( stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset));
360 		}
361 	}
362 
363 	/*  Change default into something useable */
364 	if (fCType == SQL_C_DEFAULT) {
365 		fCType = pgtype_to_ctype(stmt, field_type);
366 
367 		mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
368 	}
369 
370 
371 	rgbValueBindRow = (char *) rgbValue + rgbValueOffset;
372 
373     if(fCType == SQL_C_CHAR) {
374 
375 
376 		/*	Special character formatting as required */
377 		/*	These really should return error if cbValueMax is not big enough. */
378 		switch(field_type) {
379 		case PG_TYPE_DATE:
380 		    len = 10;
381 			if (cbValueMax > len)
382 				sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
383 			break;
384 
385 		case PG_TYPE_TIME:
386 			len = 8;
387 			if (cbValueMax > len)
388 				sprintf(rgbValueBindRow, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
389 			break;
390 
391 		case PG_TYPE_ABSTIME:
392 		case PG_TYPE_DATETIME:
393 		case PG_TYPE_TIMESTAMP:
394         case PG_TYPE_TIMESTAMP_NO_TMZONE:
395 			len = 19;
396 			if (cbValueMax > len)
397 				sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
398 					st.y, st.m, st.d, st.hh, st.mm, st.ss);
399 			break;
400 
401 		case PG_TYPE_BOOL:
402 			len = 1;
403 			if (cbValueMax > len) {
404 				strcpy(rgbValueBindRow, value);
405 				mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n", rgbValueBindRow);
406 			}
407 			break;
408 
409 		/*	Currently, data is SILENTLY TRUNCATED for BYTEA and character data
410 			types if there is not enough room in cbValueMax because the driver
411 			can't handle multiple calls to SQLGetData for these, yet.  Most likely,
412 			the buffer passed in will be big enough to handle the maximum limit of
413 			postgres, anyway.
414 
415 			LongVarBinary types are handled correctly above, observing truncation
416 			and all that stuff since there is essentially no limit on the large
417 			object used to store those.
418 		*/
419 		case PG_TYPE_BYTEA:		/* convert binary data to hex strings (i.e, 255 = "FF") */
420 			len = convert_pgbinary_to_char(value, rgbValueBindRow, cbValueMax);
421 
422 			/***** THIS IS NOT PROPERLY IMPLEMENTED *****/
423 			break;
424 
425 		default:
426 			/*	convert linefeeds to carriage-return/linefeed */
427 			len = convert_linefeeds(value, tempBuf, TEXT_FIELD_SIZE+5);
428 			ptr = tempBuf;
429 
430 			mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
431 
432 			if (stmt->current_col >= 0) {
433 				if (stmt->bindings[stmt->current_col].data_left == 0) {
434 					free( tempBuf );
435 					return COPY_NO_DATA_FOUND;
436 				}
437 				else if (stmt->bindings[stmt->current_col].data_left > 0) {
438 					ptr += len - stmt->bindings[stmt->current_col].data_left;
439 					len = stmt->bindings[stmt->current_col].data_left;
440 				}
441 				else
442 					stmt->bindings[stmt->current_col].data_left = strlen(ptr);
443 			}
444 
445 			if (cbValueMax > 0) {
446 
447 				copy_len = (len >= cbValueMax) ? cbValueMax -1 : len;
448 
449 #ifdef HAVE_LOCALE_H
450 				switch (field_type) {
451 				case PG_TYPE_FLOAT4:
452 				case PG_TYPE_FLOAT8:
453 				case PG_TYPE_NUMERIC:
454 				{
455 					struct lconv	*lc;
456 					char		*new_string;
457 					int		i, j, dplen;
458 
459 					new_string = malloc( cbValueMax );
460 					lc = localeconv();
461 					dplen = strlen(lc->decimal_point);
462 					for (i = 0, j = 0; (j < cbValueMax - 1) && ptr[i]; i++)
463 						if (ptr[i] == '.') {
464 							if ((j + dplen) <= (cbValueMax - 1)) {
465 								strncpy(&new_string[j], lc->decimal_point, dplen);
466 								j += dplen;
467 							} else
468 								break;
469 						} else
470 							new_string[j++] = ptr[i];
471 					new_string[j] = '\0';
472 					strncpy_null(rgbValueBindRow, new_string, copy_len + 1);
473 					free(new_string);
474 					break;
475 				}
476 				default:
477 					/*      Copy the data */
478 					strncpy_null(rgbValueBindRow, ptr, copy_len + 1);
479 				}
480 #else
481 				/*	Copy the data */
482 				strncpy_null(rgbValueBindRow, ptr, copy_len + 1);
483 #endif
484 
485 				/*	Adjust data_left for next time */
486 				if (stmt->current_col >= 0) {
487 					stmt->bindings[stmt->current_col].data_left -= copy_len;
488 				}
489 			}
490 
491 			/*	Finally, check for truncation so that proper status can be returned */
492 			if ( len >= cbValueMax)
493 				result = COPY_RESULT_TRUNCATED;
494 
495 
496 			mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
497 			break;
498 		}
499 
500 
501     } else {
502 
503 		/*	for SQL_C_CHAR, it's probably ok to leave currency symbols in.  But
504 			to convert to numeric types, it is necessary to get rid of those.
505 		*/
506 		if (field_type == PG_TYPE_MONEY)
507 			convert_money(value);
508 
509 		switch(fCType) {
510 		case SQL_C_DATE:
511 			len = 6;
512 			{
513 			DATE_STRUCT *ds;
514 
515 			if (bind_size > 0) {
516 				ds = (DATE_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
517 			} else {
518 				ds = (DATE_STRUCT *) rgbValue + bind_row;
519 			}
520 			ds->year = st.y;
521 			ds->month = st.m;
522 			ds->day = st.d;
523 			}
524 			break;
525 
526 		case SQL_C_TIME:
527 			len = 6;
528 			{
529 			TIME_STRUCT *ts;
530 
531 			if (bind_size > 0) {
532 				ts = (TIME_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
533 			} else {
534 				ts = (TIME_STRUCT *) rgbValue + bind_row;
535 			}
536 			ts->hour = st.hh;
537 			ts->minute = st.mm;
538 			ts->second = st.ss;
539 			}
540 			break;
541 
542 		case SQL_C_TIMESTAMP:
543 			len = 16;
544 			{
545 			TIMESTAMP_STRUCT *ts;
546 			if (bind_size > 0) {
547 				ts = (TIMESTAMP_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
548 			} else {
549 				ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row;
550 			}
551 			ts->year = st.y;
552 			ts->month = st.m;
553 			ts->day = st.d;
554 			ts->hour = st.hh;
555 			ts->minute = st.mm;
556 			ts->second = st.ss;
557 			ts->fraction = 0;
558 			}
559 			break;
560 
561 		case SQL_C_BIT:
562 			len = 1;
563 			if (bind_size > 0) {
564 				*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
565 			} else {
566 				*((UCHAR *)rgbValue + bind_row) = atoi(value);
567 			}
568 			/* mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue)); */
569 			break;
570 
571 		case SQL_C_STINYINT:
572 		case SQL_C_TINYINT:
573 			len = 1;
574 			if (bind_size > 0) {
575 				*(SCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
576 			} else {
577 				*((SCHAR *) rgbValue + bind_row) = atoi(value);
578 			}
579 			break;
580 
581 		case SQL_C_UTINYINT:
582 			len = 1;
583 			if (bind_size > 0) {
584 				*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
585 			} else {
586 				*((UCHAR *) rgbValue + bind_row) = atoi(value);
587 			}
588 			break;
589 
590 		case SQL_C_FLOAT:
591 #ifdef HAVE_LOCALE_H
592 			strcpy(saved_locale,setlocale(LC_ALL, NULL));
593 			setlocale(LC_ALL, "C");
594 #endif
595 			len = 4;
596 			if (bind_size > 0) {
597 				*(SFLOAT *) ((char *) rgbValue + (bind_row * bind_size)) = (float) atof(value);
598 			} else {
599 				*((SFLOAT *)rgbValue + bind_row) = (float) atof(value);
600 			}
601 #ifdef HAVE_LOCALE_H
602 			setlocale(LC_ALL, saved_locale);
603 #endif
604 			break;
605 
606 		case SQL_C_DOUBLE:
607 #ifdef HAVE_LOCALE_H
608 			strcpy(saved_locale, setlocale(LC_ALL, NULL));
609 			setlocale(LC_ALL, "C");
610 #endif
611 			len = 8;
612 			if (bind_size > 0) {
613 				*(SDOUBLE *) ((char *) rgbValue + (bind_row * bind_size)) = atof(value);
614 			} else {
615 				*((SDOUBLE *)rgbValue + bind_row) = atof(value);
616 			}
617 #ifdef HAVE_LOCALE_H
618 			setlocale(LC_ALL, saved_locale);
619 #endif
620 			break;
621 
622 		case SQL_C_SSHORT:
623 		case SQL_C_SHORT:
624 			len = 2;
625 			if (bind_size > 0) {
626 				*(SWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
627 			} else {
628 				*((SWORD *)rgbValue + bind_row) = atoi(value);
629 			}
630 			break;
631 
632 		case SQL_C_USHORT:
633 			len = 2;
634 			if (bind_size > 0) {
635 				*(UWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
636 			} else {
637 				*((UWORD *)rgbValue + bind_row) = atoi(value);
638 			}
639 			break;
640 
641 		case SQL_C_SLONG:
642 		case SQL_C_LONG:
643 			len = 4;
644 			if (bind_size > 0) {
645 				*(SDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(value);
646 			} else {
647 				*((SDWORD *)rgbValue + bind_row) = atol(value);
648 			}
649 			break;
650 
651 		case SQL_C_ULONG:
652 			len = 4;
653 			if (bind_size > 0) {
654 				*(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(value);
655 			} else {
656 				*((UDWORD *)rgbValue + bind_row) = atol(value);
657 			}
658 			break;
659 
660 #ifdef HAVE_LONG_LONG
661 		case SQL_BIGINT:
662             {
663             long long lv;
664 
665 			len = 8;
666 
667 #ifdef HAVE_ATOLL
668             lv = atoll( value );
669 #elif HAVE_STROLL
670             lv = strtoll( value, NULL, 10 );
671 #else
672             lv = atol( value );
673 #endif
674 
675 			if (bind_size > 0) {
676 				*(long long *) ((char *) rgbValue + (bind_row * bind_size)) = lv;
677 			} else {
678 				*((long long *)rgbValue + bind_row) = lv;
679 			}
680             }
681 			break;
682 #endif
683 
684 		case SQL_C_BINARY:
685 
686 			/*	truncate if necessary */
687 			/*	convert octal escapes to bytes */
688 
689 			len = convert_from_pgbinary(value, (SQLCHAR*)tempBuf, TEXT_FIELD_SIZE+5);
690 			ptr = tempBuf;
691 
692 			if (stmt->current_col >= 0) {
693 
694 				/*	No more data left for this column */
695 				if (stmt->bindings[stmt->current_col].data_left == 0)
696 				{
697 					free(tempBuf);
698 					return COPY_NO_DATA_FOUND;
699 				}
700 
701 				/*	Second (or more) call to SQLGetData so move the pointer */
702 				else if (stmt->bindings[stmt->current_col].data_left > 0) {
703 					ptr += len - stmt->bindings[stmt->current_col].data_left;
704 					len = stmt->bindings[stmt->current_col].data_left;
705 				}
706 
707 				/*	First call to SQLGetData so initialize data_left */
708 				else
709 					stmt->bindings[stmt->current_col].data_left = len;
710 
711 			}
712 
713 			if (cbValueMax > 0) {
714 				copy_len = (len > cbValueMax) ? cbValueMax : len;
715 
716 				/*	Copy the data */
717 				memcpy(rgbValueBindRow, ptr, copy_len);
718 
719 				/*	Adjust data_left for next time */
720 				if (stmt->current_col >= 0) {
721 					stmt->bindings[stmt->current_col].data_left -= copy_len;
722 				}
723 			}
724 
725 			/*	Finally, check for truncation so that proper status can be returned */
726 			if ( len > cbValueMax)
727 				result = COPY_RESULT_TRUNCATED;
728 
729 			mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
730 			break;
731 
732 		default:
733 			free(tempBuf);
734 			return COPY_UNSUPPORTED_TYPE;
735 		}
736 	}
737 
738     /* store the length of what was copied, if there's a place for it */
739     if(pcbValue) {
740         *(SDWORD *) ((char *)pcbValue + pcbValueOffset) = len;
741 	}
742 	free(tempBuf);
743 	return result;
744 
745 }
746 
747 
748 /*	This function inserts parameters into an SQL statements.
749 	It will also modify a SELECT statement for use with declare/fetch cursors.
750 	This function no longer does any dynamic memory allocation!
751 */
752 int
copy_statement_with_parameters(StatementClass * stmt)753 copy_statement_with_parameters(StatementClass *stmt)
754 {
755 static char* const func="copy_statement_with_parameters";
756 unsigned int opos, npos, oldstmtlen;
757 char param_string[1024], tmp[256];
758 char * cbuf; /* [TEXT_FIELD_SIZE+5]; */
759 int param_number;
760 Int2 param_ctype, param_sqltype;
761 char *old_statement = stmt->statement;
762 char *new_statement = stmt->stmt_with_params;
763 SIMPLE_TIME st;
764 time_t t = time(NULL);
765 struct tm *tim;
766 SDWORD used;
767 char *buffer, *buf;
768 char in_quote = FALSE;
769 Oid  lobj_oid;
770 int lobj_fd, retval;
771 
772     stmt -> reexecute = 0;
773 	cbuf=(char *)malloc(TEXT_FIELD_SIZE+5);
774 	if ( ! old_statement) {
775 		SC_log_error(func, "No statement string", stmt);
776 		free(cbuf);
777 		return SQL_ERROR;
778 	}
779 
780 	memset(&st, 0, sizeof(SIMPLE_TIME));
781 
782 	/*	If the application hasn't set a cursor name, then generate one */
783 	if ( stmt->cursor_name[0] == '\0')
784 		sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
785 
786 	/*	For selects, prepend a declare cursor to the statement */
787 	if (stmt->statement_type == STMT_TYPE_SELECT && globals.use_declarefetch) {
788 		sprintf(new_statement, "declare %s cursor for ", stmt->cursor_name);
789 		npos = strlen(new_statement);
790 	}
791 	else {
792 		new_statement[0] = '0';
793 		npos = 0;
794 	}
795 
796     param_number = -1;
797 
798 	oldstmtlen = strlen(old_statement);
799 
800     for (opos = 0; opos < oldstmtlen; opos++) {
801 
802 		/*	Squeeze carriage-return/linefeed pairs to linefeed only */
803 		if (old_statement[opos] == '\r' && opos+1 < oldstmtlen &&
804 			old_statement[opos+1] == '\n') {
805 			continue;
806 		}
807 
808 		/*	Handle literals (date, time, timestamp) and ODBC scalar functions */
809 		else if (old_statement[opos] == '{') {
810 			char *esc;
811 			char *begin = &old_statement[opos + 1];
812 			char *end = strchr(begin, '}');
813 
814 			if ( ! end)
815 				continue;
816 
817 			*end = '\0';
818 
819 			esc = convert_escape(begin);
820 			if (esc) {
821 				memcpy(&new_statement[npos], esc, strlen(esc));
822 				npos += strlen(esc);
823 			}
824 			else {		/* it's not a valid literal so just copy */
825 				*end = '}';
826 				new_statement[npos++] = old_statement[opos];
827 				continue;
828 			}
829 
830 			opos += end - begin + 1;
831 
832 			*end = '}';
833 
834 			continue;
835 		}
836 
837 		/*	Can you have parameter markers inside of quotes?  I dont think so.
838 			All the queries I've seen expect the driver to put quotes if needed.
839 		*/
840 		else if (old_statement[opos] == '?' && !in_quote)
841 			;	/* ok */
842 		else {
843 			if (old_statement[opos] == '\'')
844 				in_quote = (in_quote ? FALSE : TRUE);
845 
846 			new_statement[npos++] = old_statement[opos];
847 			continue;
848 		}
849 
850 
851 
852 		/****************************************************/
853 		/*       Its a '?' parameter alright                */
854 		/****************************************************/
855 
856 		param_number++;
857 
858 	    if (param_number >= stmt->parameters_allocated)
859         {
860             strcpy(&new_statement[npos], "NULL");
861             npos += strlen("NULL");
862             stmt -> reexecute = 1;
863             continue;
864         }
865 
866 		/*	Assign correct buffers based on data at exec param or not */
867 		if ( stmt->parameters[param_number].data_at_exec) {
868 			used = stmt->parameters[param_number].EXEC_used ? *stmt->parameters[param_number].EXEC_used : SQL_NTS;
869 			buffer = stmt->parameters[param_number].EXEC_buffer;
870 		}
871 		else {
872 			used = stmt->parameters[param_number].used ? *stmt->parameters[param_number].used : SQL_NTS;
873 			buffer = stmt->parameters[param_number].buffer;
874 		}
875 
876 		/*	Handle NULL parameter data */
877 		if (used == SQL_NULL_DATA) {
878 			strcpy(&new_statement[npos], "NULL");
879 			npos += 4;
880 			continue;
881 		}
882 
883 		/*	If no buffer, and it's not null, then what the hell is it?
884 			Just leave it alone then.
885 		*/
886 		if ( ! buffer) {
887 			new_statement[npos++] = '?';
888 			continue;
889 		}
890 
891 		param_ctype = stmt->parameters[param_number].CType;
892 		param_sqltype = stmt->parameters[param_number].SQLType;
893 
894 		mylog("copy_statement_with_params: from(fcType)=%d, to(fSqlType)=%d\n", param_ctype, param_sqltype);
895 
896 		/* replace DEFAULT with something we can use */
897 		if(param_ctype == SQL_C_DEFAULT)
898 			param_ctype = sqltype_to_default_ctype(param_sqltype);
899 
900 		buf = NULL;
901 		param_string[0] = '\0';
902 		cbuf[0] = '\0';
903 
904 		/*	Convert input C type to a neutral format */
905 		switch(param_ctype) {
906 		case SQL_C_BINARY:
907 			buf = buffer;
908 			break;
909 
910 #ifdef HAVE_LOCALE_H
911 		case SQL_C_CHAR:
912 			if (param_sqltype == SQL_NUMERIC ||
913 				param_sqltype == SQL_DECIMAL ||
914 				param_sqltype == SQL_FLOAT ||
915 				param_sqltype == SQL_REAL ||
916 				param_sqltype == SQL_DOUBLE) {
917 				struct lconv	*lc;
918 				int		i, j, dplen;
919 
920 				lc = localeconv();
921 				dplen = strlen(lc->decimal_point);
922 				for (i = 0, j = 0; j < sizeof(param_string)-1 && buffer[i]; )
923 					if (!strncmp(&buffer[i], lc->decimal_point, dplen)) {
924 						param_string[j++] = '.';
925 						i += dplen;
926 					} else
927 						param_string[j++] = buffer[i++];
928 				param_string[j] = '\0';
929 				break;
930 			} else
931 				buf = buffer;
932 			break;
933 #else
934 		case SQL_C_CHAR:
935 			buf = buffer;
936 			break;
937 #endif
938 
939 		case SQL_C_DOUBLE:
940 #ifdef HAVE_LOCALE_H
941 			strcpy(tmp, setlocale(LC_ALL, NULL));
942 			setlocale(LC_ALL, "C");
943 #endif
944 			sprintf(param_string, "%g",
945 				 *((SDOUBLE *) buffer));
946 #ifdef HAVE_LOCALE_H
947 			setlocale(LC_ALL, tmp);
948 #endif
949 			break;
950 
951 		case SQL_C_FLOAT:
952 #ifdef HAVE_LOCALE_H
953 			strcpy(tmp, setlocale(LC_ALL, NULL));
954 			setlocale(LC_ALL, "C");
955 #endif
956 			sprintf(param_string, "%g",
957 				 *((SFLOAT *) buffer));
958 #ifdef HAVE_LOCALE_H
959 			setlocale(LC_ALL, tmp);
960 #endif
961 			break;
962 
963 		case SQL_C_SLONG:
964 		case SQL_C_LONG:
965 #if (SIZEOF_LONG_INT == 4)
966 			sprintf(param_string, "%ld",
967 #else
968 			sprintf(param_string, "%d",
969 #endif
970 				*((SDWORD *) buffer));
971 			break;
972 
973 		case SQL_C_SSHORT:
974 		case SQL_C_SHORT:
975 			sprintf(param_string, "%d",
976 				*((SWORD *) buffer));
977 			break;
978 
979 		case SQL_C_STINYINT:
980 		case SQL_C_TINYINT:
981 			sprintf(param_string, "%d",
982 				*((SCHAR *) buffer));
983 			break;
984 
985 		case SQL_C_ULONG:
986 #if (SIZEOF_LONG_INT == 4)
987 			sprintf(param_string, "%lu",
988 #else
989 			sprintf(param_string, "%u",
990 #endif
991 				*((UDWORD *) buffer));
992 			break;
993 
994 		case SQL_C_USHORT:
995 			sprintf(param_string, "%u",
996 				*((UWORD *) buffer));
997 			break;
998 
999 		case SQL_C_UTINYINT:
1000 			sprintf(param_string, "%u",
1001 				*((UCHAR *) buffer));
1002 			break;
1003 
1004 		case SQL_C_BIT: {
1005 			int i = *((UCHAR *) buffer);
1006 
1007 			sprintf(param_string, "%d", i ? 1 : 0);
1008 			break;
1009 						}
1010 
1011 		case SQL_C_DATE: {
1012 			DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
1013             setup_ts( st );
1014 			st.m = ds->month;
1015 			st.d = ds->day;
1016 			st.y = ds->year;
1017 
1018 			break;
1019 						 }
1020 
1021 		case SQL_C_TIME: {
1022 			TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
1023             setup_ts( st );
1024 			st.hh = ts->hour;
1025 			st.mm = ts->minute;
1026 			st.ss = ts->second;
1027 
1028 			break;
1029 						 }
1030 
1031 		case SQL_C_TIMESTAMP: {
1032 			TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
1033             setup_ts( st );
1034 			st.m = tss->month;
1035 			st.d = tss->day;
1036 			st.y = tss->year;
1037 			st.hh = tss->hour;
1038 			st.mm = tss->minute;
1039 			st.ss = tss->second;
1040 
1041 			mylog("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);
1042 
1043 			break;
1044 
1045 							  }
1046 		default:
1047 			/* error */
1048 			SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unrecognized C_parameter type in copy_statement_with_parameters");
1049 			new_statement[npos] = '\0';   /* just in case */
1050 			SC_log_error(func, "", stmt);
1051 			free(cbuf);
1052 			return SQL_ERROR;
1053 		}
1054 
1055 		/*	Now that the input data is in a neutral format, convert it to
1056 			the desired output format (sqltype)
1057 		*/
1058 
1059 		switch(param_sqltype) {
1060 		case SQL_CHAR:
1061 		case SQL_VARCHAR:
1062 		case SQL_LONGVARCHAR:
1063 
1064 			new_statement[npos++] = '\'';	/*    Open Quote */
1065 
1066 			/* it was a SQL_C_CHAR */
1067 			if (buf) {
1068 				convert_special_chars(buf, &new_statement[npos], used);
1069 				npos += strlen(&new_statement[npos]);
1070 			}
1071 
1072 			/* it was a numeric type */
1073 			else if (param_string[0] != '\0') {
1074 				strcpy(&new_statement[npos], param_string);
1075 				npos += strlen(param_string);
1076 			}
1077 
1078 			/* it was date,time,timestamp -- use m,d,y,hh,mm,ss */
1079 			else {
1080                 setup_ts( st );
1081 
1082 				sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
1083 					st.y, st.m, st.d, st.hh, st.mm, st.ss);
1084 
1085 				strcpy(&new_statement[npos], tmp);
1086 				npos += strlen(tmp);
1087 			}
1088 
1089 			new_statement[npos++] = '\'';	/*    Close Quote */
1090 
1091 			break;
1092 
1093 		case SQL_DATE:
1094 			if (buf) {  /* copy char data to time */
1095 				my_strcpy(cbuf, TEXT_FIELD_SIZE+5, buf, used);
1096 				parse_datetime(cbuf, &st);
1097 			}
1098 
1099 			sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d);
1100 
1101 			strcpy(&new_statement[npos], tmp);
1102 			npos += strlen(tmp);
1103 			break;
1104 
1105 		case SQL_TIME:
1106 			if (buf) {  /* copy char data to time */
1107 				my_strcpy(cbuf, TEXT_FIELD_SIZE+5, buf, used);
1108 				parse_datetime(cbuf, &st);
1109 			}
1110 
1111 			sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss);
1112 
1113 			strcpy(&new_statement[npos], tmp);
1114 			npos += strlen(tmp);
1115 			break;
1116 
1117 		case SQL_TIMESTAMP:
1118 
1119 			if (buf) {
1120 				my_strcpy(cbuf, TEXT_FIELD_SIZE+5, buf, used);
1121 				parse_datetime(cbuf, &st);
1122 			}
1123 
1124 			sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'",
1125 				st.y, st.m, st.d, st.hh, st.mm, st.ss);
1126 
1127 			strcpy(&new_statement[npos], tmp);
1128 			npos += strlen(tmp);
1129 
1130 			break;
1131 
1132 		case SQL_BINARY:
1133 		case SQL_VARBINARY:			/* non-ascii characters should be converted to octal */
1134 			new_statement[npos++] = '\'';	/*    Open Quote */
1135 
1136 			mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
1137 
1138 			npos += convert_to_pgbinary((SQLCHAR*)buf, &new_statement[npos], used);
1139 
1140 			new_statement[npos++] = '\'';	/*    Close Quote */
1141 
1142 			break;
1143 
1144 		case SQL_LONGVARBINARY:
1145 
1146 			if ( stmt->parameters[param_number].data_at_exec) {
1147 
1148 				lobj_oid = stmt->parameters[param_number].lobj_oid;
1149 
1150 			}
1151 			else {
1152 
1153 				/* begin transaction if needed */
1154 				if(!CC_is_in_trans(stmt->hdbc)) {
1155 					QResultClass *res;
1156 					char ok;
1157 
1158 					res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
1159 					if (!res) {
1160 						SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
1161 						SC_log_error(func, "", stmt);
1162 						free(cbuf);
1163 						return SQL_ERROR;
1164 					}
1165 					ok = QR_command_successful(res);
1166 					QR_Destructor(res);
1167 					if (!ok) {
1168 						SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
1169 						SC_log_error(func, "", stmt);
1170 						free(cbuf);
1171 						return SQL_ERROR;
1172 					}
1173 
1174 					CC_set_in_trans(stmt->hdbc);
1175 				}
1176 
1177 				/*	store the oid */
1178 				lobj_oid = odbc_lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
1179 				if (lobj_oid == 0) {
1180 					SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create (in-line) large object.");
1181 					SC_log_error(func, "", stmt);
1182 					free(cbuf);
1183 					return SQL_ERROR;
1184 				}
1185 
1186 				/*	store the fd */
1187 				lobj_fd = odbc_lo_open(stmt->hdbc, lobj_oid, INV_WRITE);
1188 				if ( lobj_fd < 0) {
1189 					SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open (in-line) large object for writing.");
1190 					SC_log_error(func, "", stmt);
1191 					free(cbuf);
1192 					return SQL_ERROR;
1193 				}
1194 
1195 				retval = odbc_lo_write(stmt->hdbc, lobj_fd, buffer, used);
1196 
1197 				odbc_lo_close(stmt->hdbc, lobj_fd);
1198 
1199 				/* commit transaction if needed */
1200 				if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) {
1201 					QResultClass *res;
1202 					char ok;
1203 
1204 					res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
1205 					if (!res) {
1206 						SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
1207 						SC_log_error(func, "", stmt);
1208 						free(cbuf);
1209 						return SQL_ERROR;
1210 					}
1211 					ok = QR_command_successful(res);
1212 					QR_Destructor(res);
1213 					if (!ok) {
1214 						SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
1215 						SC_log_error(func, "", stmt);
1216 						free(cbuf);
1217 						return SQL_ERROR;
1218 					}
1219 
1220 					CC_set_no_trans(stmt->hdbc);
1221 				}
1222 			}
1223 
1224 			/*	the oid of the large object -- just put that in for the
1225 				parameter marker -- the data has already been sent to the large object
1226 			*/
1227 			sprintf(param_string, "'%d'", lobj_oid);
1228 			strcpy(&new_statement[npos], param_string);
1229 			npos += strlen(param_string);
1230 
1231 			break;
1232 
1233 			/*	because of no conversion operator for bool and int4, SQL_BIT */
1234 			/*	must be quoted (0 or 1 is ok to use inside the quotes) */
1235 
1236 		case SQL_REAL:
1237 			if (buf)
1238             			my_strcpy(param_string, sizeof(param_string), buf, used);
1239 			sprintf(tmp, "'%s'::float4", param_string);
1240 			strcpy(&new_statement[npos], tmp);
1241 			npos += strlen(tmp);
1242 			break;
1243 		case SQL_FLOAT:
1244 		case SQL_DOUBLE:
1245 			if (buf)
1246             			my_strcpy(param_string, sizeof(param_string), buf, used);
1247 			sprintf(tmp, "'%s'::float8", param_string);
1248 			strcpy(&new_statement[npos], tmp);
1249 			npos += strlen(tmp);
1250 			break;
1251 		case SQL_NUMERIC:
1252 			if (buf)
1253 			{
1254 				cbuf[0] = '\'';
1255 				my_strcpy(cbuf + 1, TEXT_FIELD_SIZE+5 - 12, buf, used);	/* 12 = 1('\'') + strlen("'::numeric") + 1('\0') */
1256 				strcat(cbuf, "'::numeric");
1257 			}
1258 			else
1259 				sprintf(cbuf, "'%s'::numeric", param_string);
1260 			my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos - 1, cbuf, strlen(cbuf));
1261 			npos += strlen(&new_statement[npos]);
1262 			break;
1263 		default:		/* a numeric type or SQL_BIT */
1264 			if (param_sqltype == SQL_BIT)
1265 				new_statement[npos++] = '\'';	/*    Open Quote */
1266 
1267 			if (buf) {
1268 				my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos, buf, used);
1269 				npos += strlen(&new_statement[npos]);
1270 			}
1271 			else {
1272 				strcpy(&new_statement[npos], param_string);
1273 				npos += strlen(param_string);
1274 			}
1275 
1276 			if (param_sqltype == SQL_BIT)
1277 				new_statement[npos++] = '\'';	/*    Close Quote */
1278 
1279 			break;
1280 
1281 		}
1282 
1283 	}	/* end, for */
1284 
1285 	/* make sure new_statement is always null-terminated */
1286 	new_statement[npos] = '\0';
1287 
1288 
1289 	if(stmt->hdbc->DriverToDataSource != NULL) {
1290 		int length = strlen (new_statement);
1291 		stmt->hdbc->DriverToDataSource (stmt->hdbc->translation_option,
1292 										SQL_CHAR,
1293 										new_statement, length,
1294 										new_statement, length, NULL,
1295 										NULL, 0, NULL);
1296 	}
1297 
1298 	free(cbuf);
1299 
1300 	return SQL_SUCCESS;
1301 }
1302 
1303 char *
mapFunction(char * func)1304 mapFunction(char *func)
1305 {
1306 int i;
1307 
1308 	for (i = 0; mapFuncs[i][0]; i++)
1309 		if ( ! stricmp(mapFuncs[i][0], func))
1310 			return mapFuncs[i][1];
1311 
1312 	return NULL;
1313 }
1314 
1315 /* convert_escape()
1316  * This function returns a pointer to static memory!
1317  */
1318 char *
convert_escape(char * value)1319 convert_escape(char *value)
1320 {
1321 static char escape[1024];
1322 char key[33];
1323 
1324 	/* Separate off the key, skipping leading and trailing whitespace */
1325 	while ((*value != '\0') && isspace((unsigned char) *value)) value++;
1326 	sscanf(value, "%32s", key);
1327 	while ((*value != '\0') && (! isspace((unsigned char) *value))) value++;
1328 	while ((*value != '\0') && isspace((unsigned char) *value)) value++;
1329 
1330 	mylog("convert_escape: key='%s', val='%s'\n", key, value);
1331 
1332 	if ( (strcmp(key, "d") == 0) ||
1333 		 (strcmp(key, "t") == 0) ||
1334 		 (strcmp(key, "ts") == 0) ||
1335 		 (stricmp(key, "oj") == 0)) {
1336 		/* Literal; return the escape part as-is */
1337 		strncpy(escape, value, sizeof(escape)-1);
1338 	}
1339 	else if (strcmp(key, "fn") == 0) {
1340 		/* Function invocation
1341 		 * Separate off the func name,
1342 		 * skipping trailing whitespace.
1343 		 */
1344 		char *funcEnd = value;
1345 		char svchar;
1346 		char *mapFunc;
1347 
1348 		while ((*funcEnd != '\0') && (*funcEnd != '(') &&
1349 			   (! isspace((unsigned char) *funcEnd)))
1350 			funcEnd++;
1351 		svchar = *funcEnd;
1352 		*funcEnd = '\0';
1353 		sscanf(value, "%32s", key);
1354 		*funcEnd = svchar;
1355 		while ((*funcEnd != '\0') && isspace((unsigned char) *funcEnd))
1356 			funcEnd++;
1357 
1358 		/* We expect left parenthesis here,
1359 		 * else return fn body as-is since it is
1360 		 * one of those "function constants".
1361 		 */
1362 		if (*funcEnd != '(') {
1363 			strncpy(escape, value, sizeof(escape)-1);
1364 			return escape;
1365 		}
1366 		mapFunc = mapFunction(key);
1367 		/* We could have mapFunction() return key if not in table...
1368 		 * - thomas 2000-04-03
1369 		 */
1370 		if (mapFunc == NULL) {
1371 			/* If unrecognized function name, return fn body as-is */
1372 			strncpy(escape, value, sizeof(escape)-1);
1373 			return escape;
1374 		}
1375 		/* copy mapped name and remaining input string */
1376 		strcpy(escape, mapFunc);
1377 		strncat(escape, funcEnd, sizeof(escape)-1-strlen(mapFunc));
1378 	}
1379 	else {
1380 		/* Bogus key, leave untranslated */
1381 		return NULL;
1382 	}
1383 
1384 	return escape;
1385 
1386 }
1387 
1388 
1389 char *
convert_money(char * s)1390 convert_money(char *s)
1391 {
1392 size_t i = 0, out = 0, slen=strlen(s);
1393 
1394 	for (i = 0; i < slen; i++) {
1395 		if (s[i] == '$' || s[i] == ',' || s[i] == ')')
1396 			; /* skip these characters */
1397 		else if (s[i] == '(')
1398 			s[out++] = '-';
1399 		else
1400 			s[out++] = s[i];
1401 	}
1402 	s[out] = '\0';
1403 	return s;
1404 }
1405 
1406 
1407 
1408 /*	This function parses a character string for date/time info and fills in SIMPLE_TIME */
1409 /*	It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value */
1410 char
parse_datetime(char * buf,SIMPLE_TIME * st)1411 parse_datetime(char *buf, SIMPLE_TIME *st)
1412 {
1413 int y,m,d,hh,mm,ss;
1414 int nf;
1415 
1416 	y = m = d = hh = mm = ss = 0;
1417 
1418 	if (buf[4] == '-')	/* year first */
1419 		nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y,&m,&d,&hh,&mm,&ss);
1420 	else
1421 		nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m,&d,&y,&hh,&mm,&ss);
1422 
1423 	if (nf == 5 || nf == 6) {
1424 		st->y = y;
1425 		st->m = m;
1426 		st->d = d;
1427 		st->hh = hh;
1428 		st->mm = mm;
1429 		st->ss = ss;
1430 
1431 		return TRUE;
1432 	}
1433 
1434 	if (buf[4] == '-')	/* year first */
1435 		nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
1436 	else
1437 		nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);
1438 
1439 	if (nf == 3) {
1440 		st->y = y;
1441 		st->m = m;
1442 		st->d = d;
1443 
1444 		return TRUE;
1445 	}
1446 
1447 	nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
1448 	if (nf == 2 || nf == 3) {
1449 		st->hh = hh;
1450 		st->mm = mm;
1451 		st->ss = ss;
1452 
1453 		return TRUE;
1454 	}
1455 
1456 	return FALSE;
1457 }
1458 
1459 /*	Change linefeed to carriage-return/linefeed */
1460 int
convert_linefeeds(char * si,char * dst,size_t max)1461 convert_linefeeds(char *si, char *dst, size_t max)
1462 {
1463 size_t i = 0, out = 0;
1464 
1465 	for (i = 0; si[ i ]  && out < max - 1; i++) {
1466 		if (si[i] == '\n') {
1467 			/*	Only add the carriage-return if needed */
1468 			if (i > 0 && si[i-1] == '\r') {
1469 				dst[out++] = si[i];
1470 				continue;
1471 			}
1472 
1473 			dst[out++] = '\r';
1474 			dst[out++] = '\n';
1475 		}
1476 		else
1477 			dst[out++] = si[i];
1478 	}
1479 	dst[out] = '\0';
1480 	return out;
1481 }
1482 
1483 /*	Change carriage-return/linefeed to just linefeed
1484 	Plus, escape any special characters.
1485 */
1486 char *
convert_special_chars(char * si,char * dst,int used)1487 convert_special_chars(char *si, char *dst, int used)
1488 {
1489 size_t i = 0, out = 0, max;
1490 /*static char sout[TEXT_FIELD_SIZE+5];*/
1491 char *p;
1492 int in_len = strlen( si );
1493 
1494 	if (dst)
1495 		p = dst;
1496 	else
1497 	/*
1498 		p = sout;
1499 	*/
1500 	{
1501 	printf("BUG !!! convert_special_chars\n");
1502 	exit(0);
1503 	}
1504 	p[0] = '\0';
1505 
1506 	if (used == SQL_NTS)
1507 		max = strlen(si);
1508 	else
1509 		max = used;
1510 
1511 	for (i = 0; i < max; i++) {
1512 		if (si[i] == '\r' && i+1 < in_len && si[i+1] == '\n')
1513 			continue;
1514 		else if (si[i] == '\'' || si[i] == '\\')
1515 			p[out++] = '\\';
1516 
1517 		p[out++] = si[i];
1518 	}
1519 	p[out] = '\0';
1520 	return p;
1521 }
1522 
1523 /*	!!! Need to implement this function !!!  */
1524 int
convert_pgbinary_to_char(char * value,char * rgbValue,int cbValueMax)1525 convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax)
1526 {
1527 	mylog("convert_pgbinary_to_char: value = '%s'\n", value);
1528 
1529 	strncpy_null(rgbValue, value, cbValueMax);
1530 	return 0;
1531 }
1532 
1533 unsigned int
conv_from_octal(unsigned char * s)1534 conv_from_octal(unsigned char *s)
1535 {
1536 int i, y=0;
1537 
1538 	for (i = 1; i <= 3; i++) {
1539 		y += (s[i] - 48) * (int) pow(8, 3-i);
1540 	}
1541 
1542 	return y;
1543 
1544 }
1545 
1546 unsigned int
conv_from_hex(unsigned char * s)1547 conv_from_hex(unsigned char *s)
1548 {
1549 int i, y=0, val;
1550 
1551 	for (i = 1; i <= 2; i++) {
1552 
1553         if (s[i] >= 'a' && s[i] <= 'f')
1554             val = s[i] - 'a' + 10;
1555         else if (s[i] >= 'A' && s[i] <= 'F')
1556             val = s[i] - 'A' + 10;
1557         else
1558             val = s[i] - '0';
1559 
1560 		y += val * (int) pow(16, 2-i);
1561 	}
1562 
1563 	return y;
1564 }
1565 
1566 /*	convert octal escapes to bytes */
1567 int
convert_from_pgbinary(unsigned char * value,unsigned char * rgbValue,int cbValueMax)1568 convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax)
1569 {
1570 int o=0;
1571 size_t i, valen=strlen((char*)value);;
1572 
1573 
1574 	for (i = 0; i < valen && o < cbValueMax; )
1575     {
1576 		if (value[i] == '\\')
1577         {
1578 			rgbValue[o] = conv_from_octal(&value[i]);
1579 			i += 4;
1580 		}
1581 		else
1582         {
1583 			rgbValue[o] = value[i++];
1584 		}
1585 		mylog("convert_from_pgbinary: i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]);
1586 		o++;
1587 	}
1588 
1589 	rgbValue[o] = '\0';	/* extra protection */
1590 
1591 	return o;
1592 }
1593 
1594 
1595 char *
conv_to_octal(unsigned char val)1596 conv_to_octal(unsigned char val)
1597 {
1598 int i;
1599 static char x[6];
1600 
1601 	x[0] = '\\';
1602 	x[1] = '\\';
1603 	x[5] = '\0';
1604 
1605 	for (i = 4; i > 1; i--) {
1606 		x[i] = (val & 7) + 48;
1607 		val >>= 3;
1608 	}
1609 
1610 	return x;
1611 }
1612 
1613 /*	convert non-ascii bytes to octal escape sequences */
1614 int
convert_to_pgbinary(unsigned char * in,char * out,int len)1615 convert_to_pgbinary(unsigned char *in, char *out, int len)
1616 {
1617 int i, o=0;
1618 
1619 
1620 	for (i = 0; i < len; i++) {
1621 		mylog("convert_to_pgbinary: in[%d] = %d, %c\n", i, in[i], in[i]);
1622 		if ( isalnum(in[i]) || in[i] == ' ') {
1623 			out[o++] = in[i];
1624 		}
1625 		else {
1626 			strcpy(&out[o], conv_to_octal(in[i]));
1627 			o += 5;
1628 		}
1629 
1630 	}
1631 
1632 	mylog("convert_to_pgbinary: returning %d, out='%.*s'\n", o, o, out);
1633 
1634 	return o;
1635 }
1636 
1637 
1638 void
encode(char * in,char * out)1639 encode(char *in, char *out)
1640 {
1641 	unsigned int i, o = 0;
1642 	size_t inlen=strlen(in);
1643 
1644 	for (i = 0; i < inlen; i++) {
1645 		if ( in[i] == '+') {
1646 			sprintf(&out[o], "%%2B");
1647 			o += 3;
1648 		}
1649 		else if ( isspace((unsigned char) in[i])) {
1650 			out[o++] = '+';
1651 		}
1652 		else if ( ! isalnum((unsigned char) in[i])) {
1653 			sprintf(&out[o], "%%%02x", (unsigned char) in[i]);
1654 			o += 3;
1655 		}
1656 		else
1657 			out[o++] = in[i];
1658 	}
1659 	out[o++] = '\0';
1660 }
1661 
1662 
1663 void
decode(char * in,char * out)1664 decode(char *in, char *out)
1665 {
1666 unsigned int i, o = 0;
1667 size_t stlen=strlen(in);
1668 
1669 	for(i=0; i < stlen; i++) {
1670 		if (in[i] == '+')
1671 			out[o++] = ' ';
1672 		else if (in[i] == '%') {
1673 			sprintf(&out[o++], "%c", conv_from_hex((SQLCHAR*)&in[i]));
1674 			i+=2;
1675 		}
1676 		else
1677 			out[o++] = in[i];
1678 	}
1679 	out[o++] = '\0';
1680 }
1681 
1682 
1683 
1684 /*	1. get oid (from 'value')
1685 	2. open the large object
1686 	3. read from the large object (handle multiple GetData)
1687 	4. close when read less than requested?  -OR-
1688 		lseek/read each time
1689 		handle case where application receives truncated and
1690 		decides not to continue reading.
1691 
1692 	CURRENTLY, ONLY LONGVARBINARY is handled, since that is the only
1693 	data type currently mapped to a PG_TYPE_LO.  But, if any other types
1694 	are desired to map to a large object (PG_TYPE_LO), then that would
1695 	need to be handled here.  For example, LONGVARCHAR could possibly be
1696 	mapped to PG_TYPE_LO someday, instead of PG_TYPE_TEXT as it is now.
1697 */
1698 int
convert_lo(StatementClass * stmt,void * value,Int2 fCType,PTR rgbValue,SDWORD cbValueMax,SDWORD * pcbValue)1699 convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue,
1700 		   SDWORD cbValueMax, SDWORD *pcbValue)
1701 {
1702 	Oid oid;
1703 	int retval, result, left = -1;
1704 	BindInfoClass *bindInfo = NULL;
1705 
1706 
1707 /*	If using SQLGetData, then current_col will be set */
1708 	if (stmt->current_col >= 0) {
1709 		bindInfo = &stmt->bindings[stmt->current_col];
1710 		left = bindInfo->data_left;
1711 	}
1712 
1713 	/*	if this is the first call for this column,
1714 		open the large object for reading
1715 	*/
1716 
1717 	if ( ! bindInfo || bindInfo->data_left == -1) {
1718 
1719 		/* begin transaction if needed */
1720 		if(!CC_is_in_trans(stmt->hdbc)) {
1721 			QResultClass *res;
1722 			char ok;
1723 
1724 			res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
1725 			if (!res) {
1726 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
1727 				return COPY_GENERAL_ERROR;
1728 			}
1729 			ok = QR_command_successful(res);
1730 			QR_Destructor(res);
1731 			if (!ok) {
1732 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
1733 				return COPY_GENERAL_ERROR;
1734 			}
1735 
1736 			CC_set_in_trans(stmt->hdbc);
1737 		}
1738 
1739 		oid = atoi(value);
1740 		stmt->lobj_fd = odbc_lo_open(stmt->hdbc, oid, INV_READ);
1741 		if (stmt->lobj_fd < 0) {
1742 			SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for reading.");
1743 			return COPY_GENERAL_ERROR;
1744 		}
1745 
1746 		/*	Get the size */
1747 		retval = odbc_lo_lseek(stmt->hdbc, stmt->lobj_fd, 0L, SEEK_END);
1748 		if (retval >= 0) {
1749 
1750 			left = odbc_lo_tell(stmt->hdbc, stmt->lobj_fd);
1751 			if (bindInfo)
1752 				bindInfo->data_left = left;
1753 
1754 			/*	return to beginning */
1755 			odbc_lo_lseek(stmt->hdbc, stmt->lobj_fd, 0L, SEEK_SET);
1756 		}
1757 	}
1758 
1759 	if (left == 0) {
1760 		return COPY_NO_DATA_FOUND;
1761 	}
1762 
1763 	if (stmt->lobj_fd < 0) {
1764 		SC_set_error(stmt, STMT_EXEC_ERROR, "Large object FD undefined for multiple read.");
1765 		return COPY_GENERAL_ERROR;
1766 	}
1767 
1768 	retval = odbc_lo_read(stmt->hdbc, stmt->lobj_fd, (char *) rgbValue, cbValueMax);
1769 	if (retval < 0) {
1770 		odbc_lo_close(stmt->hdbc, stmt->lobj_fd);
1771 
1772 		/* commit transaction if needed */
1773 		if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) {
1774 			QResultClass *res;
1775 			char ok;
1776 
1777 			res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
1778 			if (!res) {
1779 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
1780 				return COPY_GENERAL_ERROR;
1781 			}
1782 			ok = QR_command_successful(res);
1783 			QR_Destructor(res);
1784 			if (!ok) {
1785 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
1786 				return COPY_GENERAL_ERROR;
1787 			}
1788 
1789 			CC_set_no_trans(stmt->hdbc);
1790 		}
1791 
1792 		stmt->lobj_fd = -1;
1793 
1794 		SC_set_error(stmt, STMT_EXEC_ERROR, "Error reading from large object.");
1795 		return COPY_GENERAL_ERROR;
1796 	}
1797 
1798 	if (retval < left)
1799 		result = COPY_RESULT_TRUNCATED;
1800 	else
1801 		result = COPY_OK;
1802 
1803 	if (pcbValue)
1804 		*pcbValue = left < 0 ? SQL_NO_TOTAL : left;
1805 
1806 
1807 	if (bindInfo && bindInfo->data_left > 0)
1808 		bindInfo->data_left -= retval;
1809 
1810 
1811 	if (! bindInfo || bindInfo->data_left == 0) {
1812 		odbc_lo_close(stmt->hdbc, stmt->lobj_fd);
1813 
1814 		/* commit transaction if needed */
1815 		if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) {
1816 			QResultClass *res;
1817 			char ok;
1818 
1819 			res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
1820 			if (!res) {
1821 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
1822 				return COPY_GENERAL_ERROR;
1823 			}
1824 			ok = QR_command_successful(res);
1825 			QR_Destructor(res);
1826 			if (!ok) {
1827 				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
1828 				return COPY_GENERAL_ERROR;
1829 			}
1830 
1831 			CC_set_no_trans(stmt->hdbc);
1832 		}
1833 
1834 		stmt->lobj_fd = -1;	/* prevent further reading */
1835 	}
1836 
1837 
1838 	return result;
1839 
1840 }
1841