convert.c 53.1 KB
Newer Older
1
/*-------
2
 * Module:               convert.c
3
 *
B
Bruce Momjian 已提交
4 5 6 7 8 9
 * Description:    This module contains routines related to
 *				   converting parameters and columns into requested data types.
 *				   Parameters are converted from their SQL_C data types into
 *				   the appropriate postgres type.  Columns are converted from
 *				   their postgres type (SQL type) into the appropriate SQL_C
 *				   data type.
10
 *
B
Bruce Momjian 已提交
11
 * Classes:		   n/a
12 13 14
 *
 * API functions:  none
 *
B
Bruce Momjian 已提交
15
 * Comments:	   See "notice.txt" for copyright and license information.
16
 *-------
17
 */
H
Hiroshi Inoue 已提交
18
/* Multibyte support  Eiji Tokuya	2001-03-15	*/
19

20 21
#include "convert.h"

22 23
#include <stdio.h>
#include <string.h>
24
#include <ctype.h>
B
Byron Nikolaidis 已提交
25

H
Hiroshi Inoue 已提交
26 27 28 29
#ifdef MULTIBYTE
#include "multibyte.h"
#endif

30
#include <time.h>
31
#include <math.h>
32
#include <stdlib.h>
33
#include "statement.h"
B
Byron Nikolaidis 已提交
34
#include "qresult.h"
35 36
#include "bind.h"
#include "pgtypes.h"
37 38
#include "lobj.h"
#include "connection.h"
39
#include "pgapifunc.h"
40 41


42 43 44 45
/*
 *	How to map ODBC scalar functions {fn func(args)} to Postgres.
 *	This is just a simple substitution.  List augmented from:
 *	http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
46
 *	- thomas 2000-04-03
47
 */
B
Bruce Momjian 已提交
48 49 50 51
char	   *mapFuncs[][2] = {
/*	{ "ASCII",		 "ascii"	  }, */
	{"CHAR", "chr"},
	{"CONCAT", "textcat"},
B
Bruce Momjian 已提交
52
/*	{ "DIFFERENCE",  "difference" }, */
B
Bruce Momjian 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
/*	{ "INSERT",		 "insert"	  }, */
	{"LCASE", "lower"},
	{"LEFT", "ltrunc"},
	{"LOCATE", "strpos"},
	{"LENGTH", "char_length"},
/*	{ "LTRIM",		 "ltrim"	  }, */
	{"RIGHT", "rtrunc"},
/*	{ "REPEAT",		 "repeat"	  }, */
/*	{ "REPLACE",	 "replace"	  }, */
/*	{ "RTRIM",		 "rtrim"	  }, */
/*	{ "SOUNDEX",	 "soundex"	  }, */
	{"SUBSTRING", "substr"},
	{"UCASE", "upper"},

/*	{ "ABS",		 "abs"		  }, */
/*	{ "ACOS",		 "acos"		  }, */
/*	{ "ASIN",		 "asin"		  }, */
/*	{ "ATAN",		 "atan"		  }, */
/*	{ "ATAN2",		 "atan2"	  }, */
	{"CEILING", "ceil"},
/*	{ "COS",		 "cos"		  }, */
/*	{ "COT",		 "cot"		  }, */
/*	{ "DEGREES",	 "degrees"	  }, */
/*	{ "EXP",		 "exp"		  }, */
/*	{ "FLOOR",		 "floor"	  }, */
	{"LOG", "ln"},
	{"LOG10", "log"},
/*	{ "MOD",		 "mod"		  }, */
/*	{ "PI",			 "pi"		  }, */
	{"POWER", "pow"},
/*	{ "RADIANS",	 "radians"	  }, */
	{"RAND", "random"},
/*	{ "ROUND",		 "round"	  }, */
/*	{ "SIGN",		 "sign"		  }, */
/*	{ "SIN",		 "sin"		  }, */
/*	{ "SQRT",		 "sqrt"		  }, */
/*	{ "TAN",		 "tan"		  }, */
	{"TRUNCATE", "trunc"},

/*	{ "CURDATE",	 "curdate"	  }, */
/*	{ "CURTIME",	 "curtime"	  }, */
/*	{ "DAYNAME",	 "dayname"	  }, */
B
Bruce Momjian 已提交
95
/*	{ "DAYOFMONTH",  "dayofmonth" }, */
B
Bruce Momjian 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
/*	{ "DAYOFWEEK",	 "dayofweek"  }, */
/*	{ "DAYOFYEAR",	 "dayofyear"  }, */
/*	{ "HOUR",		 "hour"		  }, */
/*	{ "MINUTE",		 "minute"	  }, */
/*	{ "MONTH",		 "month"	  }, */
/*	{ "MONTHNAME",	 "monthname"  }, */
/*	{ "NOW",		 "now"		  }, */
/*	{ "QUARTER",	 "quarter"	  }, */
/*	{ "SECOND",		 "second"	  }, */
/*	{ "WEEK",		 "week"		  }, */
/*	{ "YEAR",		 "year"		  }, */

/*	{ "DATABASE",	 "database"   }, */
	{"IFNULL", "coalesce"},
	{"USER", "odbc_user"},
	{0, 0}
112 113
};

114 115 116 117
static char   *mapFunction(const char *func);
static unsigned int conv_from_octal(const unsigned char *s);
static unsigned int conv_from_hex(const unsigned char *s);
static char	   *conv_to_octal(unsigned char val);
118

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
/*---------
 *			A Guide for date/time/timestamp conversions
 *
 *			field_type		fCType				Output
 *			----------		------				----------
 *			PG_TYPE_DATE	SQL_C_DEFAULT		SQL_C_DATE
 *			PG_TYPE_DATE	SQL_C_DATE			SQL_C_DATE
 *			PG_TYPE_DATE	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(time = 0 (midnight))
 *			PG_TYPE_TIME	SQL_C_DEFAULT		SQL_C_TIME
 *			PG_TYPE_TIME	SQL_C_TIME			SQL_C_TIME
 *			PG_TYPE_TIME	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(date = current date)
 *			PG_TYPE_ABSTIME SQL_C_DEFAULT		SQL_C_TIMESTAMP
 *			PG_TYPE_ABSTIME SQL_C_DATE			SQL_C_DATE			(time is truncated)
 *			PG_TYPE_ABSTIME SQL_C_TIME			SQL_C_TIME			(date is truncated)
 *			PG_TYPE_ABSTIME SQL_C_TIMESTAMP		SQL_C_TIMESTAMP
 *---------
 */
136 137 138 139 140



/*	This is called by SQLFetch() */
int
B
Bruce Momjian 已提交
141
copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
142
{
B
Bruce Momjian 已提交
143
	BindInfoClass *bic = &(stmt->bindings[col]);
144

B
Bruce Momjian 已提交
145 146
	return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) bic->buffer,
							 (SDWORD) bic->buflen, (SDWORD *) bic->used);
147 148
}

149

150 151
/*	This is called by SQLGetData() */
int
B
Bruce Momjian 已提交
152
copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
B
Bruce Momjian 已提交
153
					   PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
154
{
B
Bruce Momjian 已提交
155 156
	Int4		len = 0,
				copy_len = 0;
157
	SIMPLE_TIME st;
B
Bruce Momjian 已提交
158 159 160 161
	time_t		t = time(NULL);
	struct tm  *tim;
	int			pcbValueOffset,
				rgbValueOffset;
162 163
	char	   *rgbValueBindRow;
	const char	*ptr;
B
Bruce Momjian 已提交
164 165 166
	int			bind_row = stmt->bind_row;
	int			bind_size = stmt->options.bind_size;
	int			result = COPY_OK;
167 168 169
	BOOL		changed;
	static		char *tempBuf= NULL;
	static		unsigned int tempBuflen = 0;
170 171 172
	const char *neut_str = value;
	char	midtemp[2][32];
	int	mtemp_cnt = 0;
173

174 175
	if (!tempBuf)
		tempBuflen = 0;
176 177 178 179 180
	/*---------
	 *	rgbValueOffset is *ONLY* for character and binary data.
	 *	pcbValueOffset is for computing any pcbValue location
	 *---------
	 */
181

B
Bruce Momjian 已提交
182
	if (bind_size > 0)
183
		pcbValueOffset = rgbValueOffset = (bind_size * bind_row);
B
Bruce Momjian 已提交
184 185
	else
	{
186 187
		pcbValueOffset = bind_row * sizeof(SDWORD);
		rgbValueOffset = bind_row * cbValueMax;
188

189
	}
190 191 192

	memset(&st, 0, sizeof(SIMPLE_TIME));

B
Bruce Momjian 已提交
193
	/* Initialize current date */
194 195 196 197 198
	tim = localtime(&t);
	st.m = tim->tm_mon + 1;
	st.d = tim->tm_mday;
	st.y = tim->tm_year + 1900;

B
Bruce Momjian 已提交
199
	mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, (value == NULL) ? "<NULL>" : value, cbValueMax);
200

B
Bruce Momjian 已提交
201 202
	if (!value)
	{
203

204
		/*
205 206
		 * handle a null just by returning SQL_NULL_DATA in pcbValue, and
		 * doing nothing to the buffer.
207
		 */
B
Bruce Momjian 已提交
208
		if (pcbValue)
209
			*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA;
B
Byron Nikolaidis 已提交
210 211 212
		return COPY_OK;
	}

B
Bruce Momjian 已提交
213 214 215 216 217 218 219 220 221
	if (stmt->hdbc->DataSourceToDriver != NULL)
	{
		int			length = strlen(value);

		stmt->hdbc->DataSourceToDriver(stmt->hdbc->translation_option,
									   SQL_CHAR,
									   value, length,
									   value, length, NULL,
									   NULL, 0, NULL);
B
Byron Nikolaidis 已提交
222 223
	}

224
	/*
225
	 * First convert any specific postgres types into more useable data.
226
	 *
227 228
	 * NOTE: Conversions from PG char/varchar of a date/time/timestamp value
	 * to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
229
	 */
B
Bruce Momjian 已提交
230 231
	switch (field_type)
	{
232 233 234 235 236

			/*
			 * $$$ need to add parsing for date/time/timestamp strings in
			 * PG_TYPE_CHAR,VARCHAR $$$
			 */
B
Bruce Momjian 已提交
237 238 239
		case PG_TYPE_DATE:
			sscanf(value, "%4d-%2d-%2d", &st.y, &st.m, &st.d);
			break;
240

B
Bruce Momjian 已提交
241 242 243
		case PG_TYPE_TIME:
			sscanf(value, "%2d:%2d:%2d", &st.hh, &st.mm, &st.ss);
			break;
244

B
Bruce Momjian 已提交
245 246 247 248 249 250
		case PG_TYPE_ABSTIME:
		case PG_TYPE_DATETIME:
		case PG_TYPE_TIMESTAMP:
			if (strnicmp(value, "invalid", 7) != 0)
				sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);
			else
251
			{
252

253
				/*
254 255
				 * The timestamp is invalid so set something conspicuous,
				 * like the epoch
256
				 */
B
Bruce Momjian 已提交
257 258 259 260 261 262 263 264 265 266 267 268
				t = 0;
				tim = localtime(&t);
				st.m = tim->tm_mon + 1;
				st.d = tim->tm_mday;
				st.y = tim->tm_year + 1900;
				st.hh = tim->tm_hour;
				st.mm = tim->tm_min;
				st.ss = tim->tm_sec;
			}
			break;

		case PG_TYPE_BOOL:
269 270
			{			/* change T/F to 1/0 */
				char	   *s;
B
Bruce Momjian 已提交
271

272 273
				s = midtemp[mtemp_cnt];
				strcpy(s, (char *) value);
274
				if (s[0] == 'f' || s[0] == 'F' || s[0] == 'n' || s[0] == 'N' || s[0] == '0')
275
					s[0] = '0';
B
Bruce Momjian 已提交
276
				else
277 278 279 280
					s[0] = '1';
				s[1] = '\0';
				neut_str = midtemp[mtemp_cnt];
				mtemp_cnt++;
281

B
Bruce Momjian 已提交
282 283 284
			}
			break;

285
			/* This is for internal use by SQLStatistics() */
B
Bruce Momjian 已提交
286 287 288 289
		case PG_TYPE_INT2VECTOR:
			{
				int			nval,
							i;
290
				const char	*vp;
B
Bruce Momjian 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

				/* this is an array of eight integers */
				short	   *short_array = (short *) ((char *) rgbValue + rgbValueOffset);

				len = 32;
				vp = value;
				nval = 0;
				mylog("index=(");
				for (i = 0; i < 16; i++)
				{
					if (sscanf(vp, "%hd", &short_array[i]) != 1)
						break;

					mylog(" %d", short_array[i]);
					nval++;

					/* skip the current token */
					while ((*vp != '\0') && (!isspace((unsigned char) *vp)))
						vp++;
					/* and skip the space to the next token */
					while ((*vp != '\0') && (isspace((unsigned char) *vp)))
						vp++;
					if (*vp == '\0')
						break;
				}
				mylog(") nval = %d\n", nval);

				for (i = nval; i < 16; i++)
					short_array[i] = 0;
B
Byron Nikolaidis 已提交
320

321
#if 0
B
Bruce Momjian 已提交
322 323 324 325 326 327 328 329 330
				sscanf(value, "%hd %hd %hd %hd %hd %hd %hd %hd",
					   &short_array[0],
					   &short_array[1],
					   &short_array[2],
					   &short_array[3],
					   &short_array[4],
					   &short_array[5],
					   &short_array[6],
					   &short_array[7]);
331
#endif
B
Byron Nikolaidis 已提交
332

B
Bruce Momjian 已提交
333 334 335
				/* There is no corresponding fCType for this. */
				if (pcbValue)
					*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
B
Byron Nikolaidis 已提交
336

B
Bruce Momjian 已提交
337 338 339
				return COPY_OK; /* dont go any further or the data will be
								 * trashed */
			}
B
Byron Nikolaidis 已提交
340

B
Bruce Momjian 已提交
341 342 343 344 345
			/*
			 * This is a large object OID, which is used to store
			 * LONGVARBINARY objects.
			 */
		case PG_TYPE_LO:
B
Byron Nikolaidis 已提交
346

B
Bruce Momjian 已提交
347
			return convert_lo(stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset));
B
Byron Nikolaidis 已提交
348

B
Bruce Momjian 已提交
349
		default:
B
Byron Nikolaidis 已提交
350

B
Bruce Momjian 已提交
351 352 353
			if (field_type == stmt->hdbc->lobj_type)	/* hack until permanent
														 * type available */
				return convert_lo(stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset));
B
Byron Nikolaidis 已提交
354 355
	}

B
Bruce Momjian 已提交
356 357 358
	/* Change default into something useable */
	if (fCType == SQL_C_DEFAULT)
	{
B
Byron Nikolaidis 已提交
359 360 361 362 363
		fCType = pgtype_to_ctype(stmt, field_type);

		mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
	}

364 365
	rgbValueBindRow = (char *) rgbValue + rgbValueOffset;

B
Bruce Momjian 已提交
366 367 368
	if (fCType == SQL_C_CHAR)
	{
		/* Special character formatting as required */
369

B
Bruce Momjian 已提交
370 371 372 373 374 375 376 377 378 379 380
		/*
		 * These really should return error if cbValueMax is not big
		 * enough.
		 */
		switch (field_type)
		{
			case PG_TYPE_DATE:
				len = 10;
				if (cbValueMax > len)
					sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
				break;
381

B
Bruce Momjian 已提交
382 383 384 385 386
			case PG_TYPE_TIME:
				len = 8;
				if (cbValueMax > len)
					sprintf(rgbValueBindRow, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
				break;
387

B
Bruce Momjian 已提交
388 389 390 391 392 393 394 395
			case PG_TYPE_ABSTIME:
			case PG_TYPE_DATETIME:
			case PG_TYPE_TIMESTAMP:
				len = 19;
				if (cbValueMax > len)
					sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
							st.y, st.m, st.d, st.hh, st.mm, st.ss);
				break;
396

B
Bruce Momjian 已提交
397 398 399 400
			case PG_TYPE_BOOL:
				len = 1;
				if (cbValueMax > len)
				{
401
					strcpy(rgbValueBindRow, neut_str);
B
Bruce Momjian 已提交
402 403 404
					mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n", rgbValueBindRow);
				}
				break;
405

B
Bruce Momjian 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
				/*
				 * Currently, data is SILENTLY TRUNCATED for BYTEA and
				 * character data types if there is not enough room in
				 * cbValueMax because the driver can't handle multiple
				 * calls to SQLGetData for these, yet.	Most likely, the
				 * buffer passed in will be big enough to handle the
				 * maximum limit of postgres, anyway.
				 *
				 * LongVarBinary types are handled correctly above, observing
				 * truncation and all that stuff since there is
				 * essentially no limit on the large object used to store
				 * those.
				 */
			case PG_TYPE_BYTEA:/* convert binary data to hex strings
								 * (i.e, 255 = "FF") */
421
				len = convert_pgbinary_to_char(neut_str, rgbValueBindRow, cbValueMax);
B
Bruce Momjian 已提交
422 423 424

				/***** THIS IS NOT PROPERLY IMPLEMENTED *****/
				break;
425

B
Bruce Momjian 已提交
426
			default:
427 428 429 430 431
				if (stmt->current_col >= 0 && stmt->bindings[stmt->current_col].data_left == -2)
					stmt->bindings[stmt->current_col].data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be needed for ADO ? */
				if (stmt->current_col < 0 || stmt->bindings[stmt->current_col].data_left < 0)
				{
					/* convert linefeeds to carriage-return/linefeed */
432
					len = convert_linefeeds(neut_str, NULL, 0, &changed);
433 434 435 436 437 438 439 440 441 442 443 444
					if (cbValueMax == 0) /* just returns length info */
					{
						result = COPY_RESULT_TRUNCATED;
						break;
					}
					if (changed || len >= cbValueMax)
					{
						if (len >= (int) tempBuflen)
						{
							tempBuf = realloc(tempBuf, len + 1);
							tempBuflen = len + 1;
						}
445
						convert_linefeeds(neut_str, tempBuf, tempBuflen, &changed);
446 447 448 449 450 451 452 453 454
						ptr = tempBuf;
					}
					else
					{
						if (tempBuf)
						{
							free(tempBuf);
							tempBuf = NULL;
						}
455
						ptr = neut_str;
456 457 458 459
					}
				}
				else
					ptr = tempBuf;
B
Bruce Momjian 已提交
460 461 462 463 464 465

				mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);

				if (stmt->current_col >= 0)
				{
					if (stmt->bindings[stmt->current_col].data_left == 0)
466 467 468 469 470 471 472 473
					{
						if (tempBuf)
						{
							free(tempBuf);
							tempBuf = NULL;
						}
						/* The following seems to be needed for ADO ? */
						stmt->bindings[stmt->current_col].data_left = -2;
B
Bruce Momjian 已提交
474
						return COPY_NO_DATA_FOUND;
475
					}
B
Bruce Momjian 已提交
476 477
					else if (stmt->bindings[stmt->current_col].data_left > 0)
					{
478
						ptr += strlen(ptr) - stmt->bindings[stmt->current_col].data_left;
B
Bruce Momjian 已提交
479 480 481
						len = stmt->bindings[stmt->current_col].data_left;
					}
					else
482
						stmt->bindings[stmt->current_col].data_left = len;
483 484
				}

B
Bruce Momjian 已提交
485 486 487
				if (cbValueMax > 0)
				{
					copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len;
488

B
Bruce Momjian 已提交
489
					/* Copy the data */
490 491
					memcpy(rgbValueBindRow, ptr, copy_len);
					rgbValueBindRow[copy_len] = '\0';
492

B
Bruce Momjian 已提交
493 494 495
					/* Adjust data_left for next time */
					if (stmt->current_col >= 0)
						stmt->bindings[stmt->current_col].data_left -= copy_len;
496 497
				}

B
Bruce Momjian 已提交
498 499 500 501
				/*
				 * Finally, check for truncation so that proper status can
				 * be returned
				 */
502
				if (cbValueMax > 0 && len >= cbValueMax)
B
Bruce Momjian 已提交
503
					result = COPY_RESULT_TRUNCATED;
504 505 506 507 508 509 510 511
				else
				{
					if (tempBuf)
					{
						free(tempBuf);
						tempBuf = NULL;
					}
				}
512 513


B
Bruce Momjian 已提交
514 515
				mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
				break;
B
Byron Nikolaidis 已提交
516
		}
517 518


B
Bruce Momjian 已提交
519 520 521
	}
	else
	{
522

B
Bruce Momjian 已提交
523 524 525 526 527
		/*
		 * for SQL_C_CHAR, it's probably ok to leave currency symbols in.
		 * But to convert to numeric types, it is necessary to get rid of
		 * those.
		 */
B
Byron Nikolaidis 已提交
528
		if (field_type == PG_TYPE_MONEY)
529 530 531 532 533 534 535 536 537
		{
			if (convert_money(neut_str, midtemp[mtemp_cnt], sizeof(midtemp[0])))
			{
				neut_str = midtemp[mtemp_cnt];
				mtemp_cnt++;
			}
			else
				return COPY_UNSUPPORTED_TYPE;
		}
B
Byron Nikolaidis 已提交
538

B
Bruce Momjian 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
		switch (fCType)
		{
			case SQL_C_DATE:
				len = 6;
				{
					DATE_STRUCT *ds;

					if (bind_size > 0)
						ds = (DATE_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
					else
						ds = (DATE_STRUCT *) rgbValue + bind_row;
					ds->year = st.y;
					ds->month = st.m;
					ds->day = st.d;
				}
				break;
555

B
Bruce Momjian 已提交
556 557 558 559 560 561 562 563 564 565 566 567 568 569
			case SQL_C_TIME:
				len = 6;
				{
					TIME_STRUCT *ts;

					if (bind_size > 0)
						ts = (TIME_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
					else
						ts = (TIME_STRUCT *) rgbValue + bind_row;
					ts->hour = st.hh;
					ts->minute = st.mm;
					ts->second = st.ss;
				}
				break;
B
Byron Nikolaidis 已提交
570

B
Bruce Momjian 已提交
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
			case SQL_C_TIMESTAMP:
				len = 16;
				{
					TIMESTAMP_STRUCT *ts;

					if (bind_size > 0)
						ts = (TIMESTAMP_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
					else
						ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row;
					ts->year = st.y;
					ts->month = st.m;
					ts->day = st.d;
					ts->hour = st.hh;
					ts->minute = st.mm;
					ts->second = st.ss;
					ts->fraction = 0;
				}
				break;
589

B
Bruce Momjian 已提交
590 591 592
			case SQL_C_BIT:
				len = 1;
				if (bind_size > 0)
593
					*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str);
B
Bruce Momjian 已提交
594
				else
595
					*((UCHAR *) rgbValue + bind_row) = atoi(neut_str);
596

B
Bruce Momjian 已提交
597
				/*
598
				 * mylog("SQL_C_BIT: bind_row = %d val = %d, cb = %d, rgb=%d\n",
599
				 * bind_row, atoi(neut_str), cbValueMax, *((UCHAR *)rgbValue));
B
Bruce Momjian 已提交
600 601
				 */
				break;
602

B
Bruce Momjian 已提交
603 604 605 606
			case SQL_C_STINYINT:
			case SQL_C_TINYINT:
				len = 1;
				if (bind_size > 0)
607
					*(SCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str);
B
Bruce Momjian 已提交
608
				else
609
					*((SCHAR *) rgbValue + bind_row) = atoi(neut_str);
B
Bruce Momjian 已提交
610
				break;
611

B
Bruce Momjian 已提交
612 613 614
			case SQL_C_UTINYINT:
				len = 1;
				if (bind_size > 0)
615
					*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str);
B
Bruce Momjian 已提交
616
				else
617
					*((UCHAR *) rgbValue + bind_row) = atoi(neut_str);
B
Bruce Momjian 已提交
618
				break;
619

B
Bruce Momjian 已提交
620 621 622
			case SQL_C_FLOAT:
				len = 4;
				if (bind_size > 0)
623
					*(SFLOAT *) ((char *) rgbValue + (bind_row * bind_size)) = (float) atof(neut_str);
B
Bruce Momjian 已提交
624
				else
625
					*((SFLOAT *) rgbValue + bind_row) = (float) atof(neut_str);
B
Bruce Momjian 已提交
626
				break;
627

B
Bruce Momjian 已提交
628 629 630
			case SQL_C_DOUBLE:
				len = 8;
				if (bind_size > 0)
631
					*(SDOUBLE *) ((char *) rgbValue + (bind_row * bind_size)) = atof(neut_str);
B
Bruce Momjian 已提交
632
				else
633
					*((SDOUBLE *) rgbValue + bind_row) = atof(neut_str);
B
Bruce Momjian 已提交
634
				break;
635

B
Bruce Momjian 已提交
636 637 638 639
			case SQL_C_SSHORT:
			case SQL_C_SHORT:
				len = 2;
				if (bind_size > 0)
640
					*(SWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str);
B
Bruce Momjian 已提交
641
				else
642
					*((SWORD *) rgbValue + bind_row) = atoi(neut_str);
B
Bruce Momjian 已提交
643
				break;
644

B
Bruce Momjian 已提交
645 646 647
			case SQL_C_USHORT:
				len = 2;
				if (bind_size > 0)
648
					*(UWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(neut_str);
B
Bruce Momjian 已提交
649
				else
650
					*((UWORD *) rgbValue + bind_row) = atoi(neut_str);
B
Bruce Momjian 已提交
651
				break;
652

B
Bruce Momjian 已提交
653 654 655 656
			case SQL_C_SLONG:
			case SQL_C_LONG:
				len = 4;
				if (bind_size > 0)
657
					*(SDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(neut_str);
B
Bruce Momjian 已提交
658
				else
659
					*((SDWORD *) rgbValue + bind_row) = atol(neut_str);
B
Bruce Momjian 已提交
660 661 662 663 664
				break;

			case SQL_C_ULONG:
				len = 4;
				if (bind_size > 0)
665
					*(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(neut_str);
B
Bruce Momjian 已提交
666
				else
667
					*((UDWORD *) rgbValue + bind_row) = atol(neut_str);
B
Bruce Momjian 已提交
668
				break;
669

B
Bruce Momjian 已提交
670
			case SQL_C_BINARY:
671

B
Bruce Momjian 已提交
672 673
				/* truncate if necessary */
				/* convert octal escapes to bytes */
674

675
				if (len = strlen(neut_str), len >= (int) tempBuflen)
676 677 678 679
				{
					tempBuf = realloc(tempBuf, len + 1);
					tempBuflen = len + 1;
				}
680
				len = convert_from_pgbinary(neut_str, tempBuf, tempBuflen);
B
Bruce Momjian 已提交
681
				ptr = tempBuf;
682

B
Bruce Momjian 已提交
683 684 685 686
				if (stmt->current_col >= 0)
				{
					/* No more data left for this column */
					if (stmt->bindings[stmt->current_col].data_left == 0)
687 688 689
					{
						free(tempBuf);
						tempBuf = NULL;
B
Bruce Momjian 已提交
690
						return COPY_NO_DATA_FOUND;
691
					}
692

B
Bruce Momjian 已提交
693 694 695 696 697 698 699 700 701
					/*
					 * Second (or more) call to SQLGetData so move the
					 * pointer
					 */
					else if (stmt->bindings[stmt->current_col].data_left > 0)
					{
						ptr += len - stmt->bindings[stmt->current_col].data_left;
						len = stmt->bindings[stmt->current_col].data_left;
					}
702

B
Bruce Momjian 已提交
703 704 705
					/* First call to SQLGetData so initialize data_left */
					else
						stmt->bindings[stmt->current_col].data_left = len;
706

B
Bruce Momjian 已提交
707
				}
708

B
Bruce Momjian 已提交
709 710 711
				if (cbValueMax > 0)
				{
					copy_len = (len > cbValueMax) ? cbValueMax : len;
712

B
Bruce Momjian 已提交
713 714
					/* Copy the data */
					memcpy(rgbValueBindRow, ptr, copy_len);
715

B
Bruce Momjian 已提交
716 717 718
					/* Adjust data_left for next time */
					if (stmt->current_col >= 0)
						stmt->bindings[stmt->current_col].data_left -= copy_len;
719
				}
720

B
Bruce Momjian 已提交
721 722 723 724 725 726
				/*
				 * Finally, check for truncation so that proper status can
				 * be returned
				 */
				if (len > cbValueMax)
					result = COPY_RESULT_TRUNCATED;
727

728 729 730 731 732
				if (tempBuf)
				{
					free(tempBuf);
					tempBuf = NULL;
				}
B
Bruce Momjian 已提交
733 734 735 736 737
				mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
				break;

			default:
				return COPY_UNSUPPORTED_TYPE;
B
Byron Nikolaidis 已提交
738 739
		}
	}
740

B
Bruce Momjian 已提交
741 742 743
	/* store the length of what was copied, if there's a place for it */
	if (pcbValue)
		*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
744

745
	return result;
746

747 748
}

749

750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
/*--------------------------------------------------------------------
 *	Functions/Macros to get rid of query size limit.
 *
 *	I always used the follwoing macros to convert from
 *	old_statement to new_statement.	 Please improve it
 *	if you have a better way.	Hiroshi 2001/05/22
 *--------------------------------------------------------------------
 */
#define	INIT_MIN_ALLOC	4096
static int enlarge_statement(StatementClass *stmt, unsigned int newsize)
{
	unsigned int	newalsize = INIT_MIN_ALLOC;
	static char *func = "enlarge_statement";

	if (stmt->stmt_size_limit > 0 && stmt->stmt_size_limit < (int) newsize)
	{
		stmt->errormsg = "Query buffer overflow in copy_statement_with_parameters";
		stmt->errornumber = STMT_EXEC_ERROR;
		SC_log_error(func, "", stmt);
		return -1;
	}
	while (newalsize <= newsize)
		newalsize *= 2;
	if (!(stmt->stmt_with_params = realloc(stmt->stmt_with_params, newalsize)))
	{
		stmt->errormsg = "Query buffer allocate error in copy_statement_with_parameters";
		stmt->errornumber = STMT_EXEC_ERROR;
		SC_log_error(func, "", stmt);
		return 0;
	}
	return newalsize;
}

/*----------
 *	Enlarge stmt_with_params if necessary.
 *----------
 */
#define	ENLARGE_NEWSTATEMENT(newpos) \
	if (newpos >= new_stsize) \
	{ \
		if ((new_stsize = enlarge_statement(stmt, newpos)) <= 0) \
			return SQL_ERROR; \
		new_statement = stmt->stmt_with_params; \
	}
/*----------
 *	Initialize stmt_with_params, new_statement etc.
 *----------
 */
#define	CVT_INIT(size) \
799
do { \
800 801 802 803 804 805 806 807 808 809 810 811 812 813
	if (stmt->stmt_with_params) \
		free(stmt->stmt_with_params); \
	if (stmt->stmt_size_limit > 0) \
		new_stsize = stmt->stmt_size_limit; \
	else \
	{ \
		new_stsize = INIT_MIN_ALLOC; \
		while (new_stsize <= size) \
			new_stsize *= 2; \
	} \
	new_statement = malloc(new_stsize); \
	stmt->stmt_with_params = new_statement; \
	npos = 0; \
	new_statement[0] = '\0'; \
814 815
} while (0)

816 817 818 819
/*----------
 *	Terminate the stmt_with_params string with NULL.
 *----------
 */
820 821 822 823
#define	CVT_TERMINATE \
do { \
	new_statement[npos] = '\0'; \
} while (0)
824 825 826 827 828 829

/*----------
 *	Append a data.
 *----------
 */
#define	CVT_APPEND_DATA(s, len) \
830
do { \
831 832 833 834 835
	unsigned int	newpos = npos + len; \
	ENLARGE_NEWSTATEMENT(newpos) \
	memcpy(&new_statement[npos], s, len); \
	npos = newpos; \
	new_statement[npos] = '\0'; \
836 837
} while (0)

838 839 840 841 842
/*----------
 *	Append a string.
 *----------
 */
#define	CVT_APPEND_STR(s) \
843
do { \
844 845
	unsigned int len = strlen(s); \
	CVT_APPEND_DATA(s, len); \
846 847
} while (0)

848 849 850 851 852
/*----------
 *	Append a char.	
 *----------
 */
#define	CVT_APPEND_CHAR(c) \
853
do { \
854 855
	ENLARGE_NEWSTATEMENT(npos + 1); \
	new_statement[npos++] = c; \
856 857
} while (0)

858 859 860 861 862 863
/*----------
 *	Append a binary data.
 *	Newly reqeuired size may be overestimated currently. 
 *----------
 */
#define	CVT_APPEND_BINARY(buf, used) \
864
do { \
865 866 867
	unsigned int	newlimit = npos + 5 * used; \
	ENLARGE_NEWSTATEMENT(newlimit); \
	npos += convert_to_pgbinary(buf, &new_statement[npos], used); \
868 869
} while (0)

870 871 872 873 874
/*----------
 *
 *----------
 */
#define	CVT_SPECIAL_CHARS(buf, used) \
875
do { \
876 877 878 879 880 881
	int	cnvlen = convert_special_chars(buf, NULL, used); \
	unsigned int	newlimit = npos + cnvlen; \
\
	ENLARGE_NEWSTATEMENT(newlimit); \
	convert_special_chars(buf, &new_statement[npos], used); \
	npos += cnvlen; \
882
} while (0)
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928

/*----------
 *	Check if the statement is	
 *	SELECT ... INTO table FROM .....
 *	This isn't really a strict check but ...
 *---------- 
 */
static BOOL
into_table_from(const char *stmt)
{
	if (strnicmp(stmt, "into", 4))
		return FALSE;
	stmt += 4;
	if (!isspace((unsigned char) *stmt))
		return FALSE;
	while (isspace((unsigned char) *(++stmt)));
	switch (*stmt)
	{
		case '\0':
		case ',':
		case '\'':
			return FALSE;
		case '\"': /* double quoted table name ? */
			do
			{
				do
				{
					 while (*(++stmt) != '\"' && *stmt);
				}
				while (*stmt && *(++stmt) == '\"');
				while (*stmt && !isspace((unsigned char) *stmt) && *stmt != '\"') stmt++;
			}
			while (*stmt == '\"');
			break;
		default:
			while (!isspace((unsigned char) *(++stmt)));
			break;
	}
	if (! *stmt)
		return FALSE;
	while (isspace((unsigned char) *(++stmt)));
	if (strnicmp(stmt, "from", 4))
		return FALSE;
	return isspace((unsigned char) stmt[4]);
}

H
Hiroshi Inoue 已提交
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
/*----------
 *	Check if the statement is	
 *	SELECT ... FOR UPDATE .....
 *	This isn't really a strict check but ...
 *---------- 
 */
static BOOL
table_for_update(const char *stmt, int *endpos)
{
	const char *wstmt = stmt;
	while (isspace((unsigned char) *(++wstmt)));
	if (! *wstmt)
		return FALSE;
	if (strnicmp(wstmt, "update", 6))
		return FALSE;
	wstmt += 6;
	*endpos = wstmt - stmt;
	return !wstmt[0] || isspace((unsigned char) wstmt[0]);
}

949 950 951
/*
 *	This function inserts parameters into an SQL statements.
 *	It will also modify a SELECT statement for use with declare/fetch cursors.
952
 *	This function does a dynamic memory allocation to get rid of query size limit!
953
 */
954
int
B
Bruce Momjian 已提交
955
copy_statement_with_parameters(StatementClass *stmt)
956
{
B
Bruce Momjian 已提交
957 958 959 960 961 962
	static char *func = "copy_statement_with_parameters";
	unsigned int opos,
				npos,
				oldstmtlen;
	char		param_string[128],
				tmp[256],
963
				cbuf[PG_NUMERIC_MAX_PRECISION * 2]; /* seems big enough to handle the data in this function */
B
Bruce Momjian 已提交
964 965 966
	int			param_number;
	Int2		param_ctype,
				param_sqltype;
967
	char	   *old_statement = stmt->statement, oldchar;
B
Bruce Momjian 已提交
968
	char	   *new_statement = stmt->stmt_with_params;
969
	unsigned int	new_stsize = 0;
B
Bruce Momjian 已提交
970 971 972 973
	SIMPLE_TIME st;
	time_t		t = time(NULL);
	struct tm  *tim;
	SDWORD		used;
974
	char	   	*buffer, *buf;
975
	BOOL		in_quote = FALSE, in_dquote = FALSE, in_escape = FALSE;
B
Bruce Momjian 已提交
976 977 978
	Oid			lobj_oid;
	int			lobj_fd,
				retval;
H
Hiroshi Inoue 已提交
979
	BOOL	check_cursor_ok = FALSE; /* check cursor restriction */
980
	BOOL	proc_no_param = TRUE;
H
Hiroshi Inoue 已提交
981
	unsigned int	declare_pos = 0;
982 983
	ConnectionClass	*conn = SC_get_conn(stmt);
	ConnInfo	*ci = &(conn->connInfo);
984
	BOOL		prepare_dummy_cursor = FALSE, begin_first = FALSE;
H
Hiroshi Inoue 已提交
985
	char	token_save[64];
H
Hiroshi Inoue 已提交
986 987
	int	token_len;
	BOOL	prev_token_end;
988
#ifdef	DRIVER_CURSOR_IMPLEMENT
H
Hiroshi Inoue 已提交
989
	BOOL search_from_pos = FALSE;
990
#endif /* DRIVER_CURSOR_IMPLEMENT */
991 992
	if (ci->disallow_premature)
		prepare_dummy_cursor = stmt->pre_executing;
B
Bruce Momjian 已提交
993 994 995

	if (!old_statement)
	{
B
Byron Nikolaidis 已提交
996
		SC_log_error(func, "No statement string", stmt);
997
		return SQL_ERROR;
B
Byron Nikolaidis 已提交
998
	}
999

1000 1001
	memset(&st, 0, sizeof(SIMPLE_TIME));

B
Bruce Momjian 已提交
1002
	/* Initialize current date */
1003 1004 1005 1006 1007
	tim = localtime(&t);
	st.m = tim->tm_mon + 1;
	st.d = tim->tm_mday;
	st.y = tim->tm_year + 1900;

1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
#ifdef	DRIVER_CURSOR_IMPLEMENT
	if (stmt->statement_type != STMT_TYPE_SELECT)
	{
		stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
	}
	else if (stmt->options.cursor_type == SQL_CURSOR_FORWARD_ONLY)
    		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
	else if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
	{
		if (stmt->parse_status == STMT_PARSE_NONE)
			parse_statement(stmt);
		if (stmt->parse_status != STMT_PARSE_COMPLETE)
			stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
		else if (!stmt->ti || stmt->ntab != 1)
    			stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
1024 1025
		else
			search_from_pos = TRUE;
1026 1027
	}
#endif /* DRIVER_CURSOR_IMPLEMENT */
1028 1029 1030 1031 1032 1033

	/* If the application hasn't set a cursor name, then generate one */
	if (stmt->cursor_name[0] == '\0')
		sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
	oldstmtlen = strlen(old_statement);
	CVT_INIT(oldstmtlen);
H
Hiroshi Inoue 已提交
1034

1035
	stmt->miscinfo = 0;
H
Hiroshi Inoue 已提交
1036 1037
	token_len = 0;
	prev_token_end = TRUE;
1038 1039 1040 1041 1042 1043 1044 1045
	/* For selects, prepend a declare cursor to the statement */
	if (stmt->statement_type == STMT_TYPE_SELECT)
	{
		SC_set_pre_executable(stmt);
		if (prepare_dummy_cursor || ci->drivers.use_declarefetch)
		{
			if (prepare_dummy_cursor)
			{
1046 1047 1048 1049 1050
				if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1))
				{
					strcpy(new_statement, "BEGIN;");
					begin_first = TRUE;
				}
1051 1052 1053
			}
			else if (ci->drivers.use_declarefetch)
				SC_set_fetchcursor(stmt);
H
Hiroshi Inoue 已提交
1054
			sprintf(new_statement, "%sdeclare %s cursor for ",
1055 1056
				 new_statement, stmt->cursor_name);
			npos = strlen(new_statement);
H
Hiroshi Inoue 已提交
1057
			check_cursor_ok = TRUE;
1058 1059 1060 1061
			declare_pos = npos;
		}
	}
	param_number = -1;
H
Hiroshi Inoue 已提交
1062
#ifdef MULTIBYTE
B
Bruce Momjian 已提交
1063
	multibyte_init();
H
Hiroshi Inoue 已提交
1064
#endif
1065

B
Bruce Momjian 已提交
1066 1067
	for (opos = 0; opos < oldstmtlen; opos++)
	{
1068
		oldchar = old_statement[opos];
1069
#ifdef MULTIBYTE
1070
		if (multibyte_char_check(oldchar) != 0)
1071
		{
1072
			CVT_APPEND_CHAR(oldchar);
1073 1074 1075 1076 1077 1078 1079
			continue;
		}
		/*
		 *	From here we are guaranteed to handle a
		 *	1-byte character.
		 */
#endif
1080

1081
		if (in_escape) /* escape check */
1082 1083
		{
			in_escape = FALSE;
1084
			CVT_APPEND_CHAR(oldchar);
1085 1086 1087 1088
			continue;
		}	
		else if (in_quote || in_dquote) /* quote/double quote check */
		{
1089 1090 1091
			if (oldchar == '\\')
				in_escape = TRUE;
			else if (oldchar == '\'' && in_quote)
1092
				in_quote = FALSE;
1093
			else if (oldchar == '\"' && in_dquote)
1094
				in_dquote = FALSE;
1095
			CVT_APPEND_CHAR(oldchar);
1096 1097 1098 1099
			continue;	
		}
		/*
		 *	From here we are guranteed to be in neither
1100
		 *	an escape, a quote nor a double quote.
1101
		 */
1102 1103 1104 1105
		/* Squeeze carriage-return/linefeed pairs to linefeed only */
		else if (oldchar == '\r' && opos + 1 < oldstmtlen &&
			old_statement[opos + 1] == '\n')
			continue;
B
Bruce Momjian 已提交
1106 1107 1108 1109
		/*
		 * Handle literals (date, time, timestamp) and ODBC scalar
		 * functions
		 */
1110
		else if (oldchar == '{')
B
Bruce Momjian 已提交
1111 1112 1113 1114
		{
			char	   *esc;
			char	   *begin = &old_statement[opos + 1];

H
Hiroshi Inoue 已提交
1115
#ifdef MULTIBYTE
B
Bruce Momjian 已提交
1116
			char	   *end = multibyte_strchr(begin, '}');
1117

H
Hiroshi Inoue 已提交
1118
#else
B
Bruce Momjian 已提交
1119
			char	   *end = strchr(begin, '}');
1120

H
Hiroshi Inoue 已提交
1121
#endif
1122

B
Bruce Momjian 已提交
1123
			if (!end)
1124
				continue;
H
Hiroshi Inoue 已提交
1125 1126 1127
			/* procedure calls */
			if (stmt->statement_type == STMT_TYPE_PROCCALL)
			{
1128
				int	lit_call_len = 4;
H
Hiroshi Inoue 已提交
1129
				while (isspace((unsigned char) old_statement[++opos]));
1130
				/* '=?' to accept return values exists ? */
H
Hiroshi Inoue 已提交
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
				if (old_statement[opos] == '?')
				{
					param_number++;
					while (isspace((unsigned char) old_statement[++opos]));
					if (old_statement[opos] != '=')
					{
						opos--;
						continue;
					}
					while (isspace((unsigned char) old_statement[++opos]));
				}
1142 1143
				if (strnicmp(&old_statement[opos], "call", lit_call_len) ||
					!isspace(old_statement[opos + lit_call_len]))
H
Hiroshi Inoue 已提交
1144 1145 1146 1147
				{
					opos--;
					continue;
				}
1148 1149
				opos += lit_call_len; 
				CVT_APPEND_STR("SELECT ");
H
Hiroshi Inoue 已提交
1150 1151 1152
#ifdef MULTIBYTE
				if (multibyte_strchr(&old_statement[opos], '('))
#else
1153
				if (strchr(&old_statement[opos], '('))
H
Hiroshi Inoue 已提交
1154
#endif /* MULTIBYTE */
1155
					proc_no_param = FALSE;
H
Hiroshi Inoue 已提交
1156 1157
				continue; 
			}
1158 1159 1160
			*end = '\0';

			esc = convert_escape(begin);
B
Bruce Momjian 已提交
1161 1162
			if (esc)
			{
1163
				CVT_APPEND_STR(esc);
1164
			}
B
Bruce Momjian 已提交
1165 1166 1167
			else
			{					/* it's not a valid literal so just copy */
				*end = '}';
1168
				CVT_APPEND_CHAR(oldchar);
1169 1170
				continue;
			}
1171

1172
			opos += end - begin + 1;
1173 1174 1175
			*end = '}';
			continue;
		}
H
Hiroshi Inoue 已提交
1176 1177
		/* End of a procedure call */
		else if (oldchar == '}' && stmt->statement_type == STMT_TYPE_PROCCALL)
1178 1179 1180
		{
			if (proc_no_param)
				CVT_APPEND_STR("()");
H
Hiroshi Inoue 已提交
1181
			continue;
1182
		}
1183

B
Bruce Momjian 已提交
1184 1185 1186 1187 1188
		/*
		 * Can you have parameter markers inside of quotes?  I dont think
		 * so. All the queries I've seen expect the driver to put quotes
		 * if needed.
		 */
1189
		else if (oldchar == '?')
B
Bruce Momjian 已提交
1190 1191 1192
			;					/* ok */
		else
		{
1193
			if (oldchar == '\'')
1194
				in_quote = TRUE;
1195
			else if (oldchar == '\\')
1196
				in_escape = TRUE;
1197
			else if (oldchar == '\"')
1198
				in_dquote = TRUE;
H
Hiroshi Inoue 已提交
1199
			else 
1200
			{
H
Hiroshi Inoue 已提交
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
				if (isspace(oldchar))
				{
					if (!prev_token_end)
					{
						prev_token_end = TRUE;
						token_save[token_len] = '\0';
						if (token_len == 4)
						{
							if (check_cursor_ok &&
    				 			   into_table_from(&old_statement[opos - token_len]))
							{
								stmt->statement_type = STMT_TYPE_CREATE;
								SC_no_pre_executable(stmt);
								SC_no_fetchcursor(stmt);
								stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
								memmove(new_statement, new_statement + declare_pos, npos - declare_pos);
								npos -= declare_pos;
							}
1219
#ifdef	DRIVER_CURSOR_IMPLEMENT
H
Hiroshi Inoue 已提交
1220 1221 1222 1223 1224 1225 1226
							else if (search_from_pos && /* where's from clause */
    				 				 strnicmp(token_save, "from", 4) == 0)
							{
								search_from_pos = FALSE;
								npos -= 5;
								CVT_APPEND_STR(", CTID, OID from");
							}
1227
#endif /* DRIVER_CURSOR_IMPLEMENT */
H
Hiroshi Inoue 已提交
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
						}
						if (token_len == 3)
						{
							int	endpos;
							if (check_cursor_ok &&
    				 			    strnicmp(token_save, "for", 3) == 0 &&
    				 			    table_for_update(&old_statement[opos], &endpos))
							{
								SC_no_fetchcursor(stmt);
								stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
								if (prepare_dummy_cursor)
								{
									npos -= 4;
									opos += endpos;
								}
								else
								{
									memmove(new_statement, new_statement + declare_pos, npos - declare_pos);
									npos -= declare_pos;
								}
							}
						}
					}	
				}
				else if (prev_token_end)
				{
					prev_token_end = FALSE;
					token_save[0] = oldchar;
					token_len = 1;
				}
H
Hiroshi Inoue 已提交
1258
				else if (token_len + 1 < sizeof(token_save))
H
Hiroshi Inoue 已提交
1259 1260
					token_save[token_len++] = oldchar;
			} 
1261
			CVT_APPEND_CHAR(oldchar);
1262 1263 1264
			continue;
		}

1265 1266 1267
		/*
		 * Its a '?' parameter alright
		 */
1268 1269
		param_number++;

B
Bruce Momjian 已提交
1270
		if (param_number >= stmt->parameters_allocated)
1271 1272 1273
		{
			if (stmt->pre_executing)
			{
1274
				CVT_APPEND_STR("NULL");
1275 1276 1277 1278 1279
				stmt->inaccurate_result = TRUE;
				continue;
			}
			else
			{
1280
				CVT_APPEND_CHAR('?');
1281 1282 1283
				continue;
			}
		}
1284

B
Bruce Momjian 已提交
1285 1286 1287
		/* Assign correct buffers based on data at exec param or not */
		if (stmt->parameters[param_number].data_at_exec)
		{
1288 1289 1290
			used = stmt->parameters[param_number].EXEC_used ? *stmt->parameters[param_number].EXEC_used : SQL_NTS;
			buffer = stmt->parameters[param_number].EXEC_buffer;
		}
B
Bruce Momjian 已提交
1291 1292
		else
		{
1293 1294
			
			
1295
			used = stmt->parameters[param_number].used ? *stmt->parameters[param_number].used : SQL_NTS;
1296
			
1297 1298 1299
			buffer = stmt->parameters[param_number].buffer;
		}

B
Bruce Momjian 已提交
1300 1301 1302
		/* Handle NULL parameter data */
		if (used == SQL_NULL_DATA)
		{
1303
			CVT_APPEND_STR("NULL");
1304 1305 1306
			continue;
		}

B
Bruce Momjian 已提交
1307 1308 1309 1310 1311 1312
		/*
		 * If no buffer, and it's not null, then what the hell is it? Just
		 * leave it alone then.
		 */
		if (!buffer)
		{
1313 1314
			if (stmt->pre_executing)
			{
1315
				CVT_APPEND_STR("NULL");
1316 1317 1318 1319 1320
				stmt->inaccurate_result = TRUE;
				continue;
			}
			else
			{
1321
				CVT_APPEND_CHAR('?');
1322 1323
				continue;
			}
1324
		}
1325 1326 1327

		param_ctype = stmt->parameters[param_number].CType;
		param_sqltype = stmt->parameters[param_number].SQLType;
B
Bruce Momjian 已提交
1328

1329
		mylog("copy_statement_with_params: from(fcType)=%d, to(fSqlType)=%d\n", param_ctype, param_sqltype);
B
Bruce Momjian 已提交
1330

B
Bruce Momjian 已提交
1331
		/* replace DEFAULT with something we can use */
B
Bruce Momjian 已提交
1332
		if (param_ctype == SQL_C_DEFAULT)
1333 1334 1335 1336 1337 1338
			param_ctype = sqltype_to_default_ctype(param_sqltype);

		buf = NULL;
		param_string[0] = '\0';
		cbuf[0] = '\0';

B
Bruce Momjian 已提交
1339 1340 1341 1342 1343 1344 1345
		/* Convert input C type to a neutral format */
		switch (param_ctype)
		{
			case SQL_C_BINARY:
			case SQL_C_CHAR:
				buf = buffer;
				break;
1346

B
Bruce Momjian 已提交
1347
			case SQL_C_DOUBLE:
1348
				sprintf(param_string, "%.15g",
B
Bruce Momjian 已提交
1349 1350
						*((SDOUBLE *) buffer));
				break;
1351

B
Bruce Momjian 已提交
1352
			case SQL_C_FLOAT:
1353
				sprintf(param_string, "%.6g",
B
Bruce Momjian 已提交
1354 1355
						*((SFLOAT *) buffer));
				break;
1356

B
Bruce Momjian 已提交
1357 1358 1359 1360 1361
			case SQL_C_SLONG:
			case SQL_C_LONG:
				sprintf(param_string, "%ld",
						*((SDWORD *) buffer));
				break;
1362

B
Bruce Momjian 已提交
1363 1364 1365 1366 1367
			case SQL_C_SSHORT:
			case SQL_C_SHORT:
				sprintf(param_string, "%d",
						*((SWORD *) buffer));
				break;
1368

B
Bruce Momjian 已提交
1369 1370 1371 1372 1373
			case SQL_C_STINYINT:
			case SQL_C_TINYINT:
				sprintf(param_string, "%d",
						*((SCHAR *) buffer));
				break;
1374

B
Bruce Momjian 已提交
1375 1376 1377 1378
			case SQL_C_ULONG:
				sprintf(param_string, "%lu",
						*((UDWORD *) buffer));
				break;
1379

B
Bruce Momjian 已提交
1380 1381 1382 1383
			case SQL_C_USHORT:
				sprintf(param_string, "%u",
						*((UWORD *) buffer));
				break;
1384

B
Bruce Momjian 已提交
1385 1386 1387 1388
			case SQL_C_UTINYINT:
				sprintf(param_string, "%u",
						*((UCHAR *) buffer));
				break;
1389

B
Bruce Momjian 已提交
1390 1391 1392
			case SQL_C_BIT:
				{
					int			i = *((UCHAR *) buffer);
1393

B
Bruce Momjian 已提交
1394 1395 1396
					sprintf(param_string, "%d", i ? 1 : 0);
					break;
				}
1397

B
Bruce Momjian 已提交
1398 1399 1400
			case SQL_C_DATE:
				{
					DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
1401

B
Bruce Momjian 已提交
1402 1403 1404
					st.m = ds->month;
					st.d = ds->day;
					st.y = ds->year;
1405

B
Bruce Momjian 已提交
1406 1407
					break;
				}
1408

B
Bruce Momjian 已提交
1409 1410 1411
			case SQL_C_TIME:
				{
					TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
1412

B
Bruce Momjian 已提交
1413 1414 1415
					st.hh = ts->hour;
					st.mm = ts->minute;
					st.ss = ts->second;
1416

B
Bruce Momjian 已提交
1417 1418
					break;
				}
1419

B
Bruce Momjian 已提交
1420 1421 1422
			case SQL_C_TIMESTAMP:
				{
					TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
1423

B
Bruce Momjian 已提交
1424 1425 1426 1427 1428 1429
					st.m = tss->month;
					st.d = tss->day;
					st.y = tss->year;
					st.hh = tss->hour;
					st.mm = tss->minute;
					st.ss = tss->second;
1430

B
Bruce Momjian 已提交
1431
					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);
1432

B
Bruce Momjian 已提交
1433
					break;
1434

B
Bruce Momjian 已提交
1435 1436 1437 1438 1439
				}
			default:
				/* error */
				stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
				stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
1440
				CVT_TERMINATE;	/* just in case */
B
Bruce Momjian 已提交
1441 1442 1443
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
		}
1444

B
Bruce Momjian 已提交
1445 1446 1447 1448
		/*
		 * Now that the input data is in a neutral format, convert it to
		 * the desired output format (sqltype)
		 */
1449

B
Bruce Momjian 已提交
1450 1451 1452 1453 1454
		switch (param_sqltype)
		{
			case SQL_CHAR:
			case SQL_VARCHAR:
			case SQL_LONGVARCHAR:
1455

1456
				CVT_APPEND_CHAR('\'');	/* Open Quote */
1457

B
Bruce Momjian 已提交
1458 1459 1460
				/* it was a SQL_C_CHAR */
				if (buf)
				{
1461
					CVT_SPECIAL_CHARS(buf, used);
B
Bruce Momjian 已提交
1462
				}
1463

B
Bruce Momjian 已提交
1464 1465 1466
				/* it was a numeric type */
				else if (param_string[0] != '\0')
				{
1467
					CVT_APPEND_STR(param_string);
B
Bruce Momjian 已提交
1468
				}
1469

B
Bruce Momjian 已提交
1470 1471 1472 1473 1474
				/* it was date,time,timestamp -- use m,d,y,hh,mm,ss */
				else
				{
					sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
							st.y, st.m, st.d, st.hh, st.mm, st.ss);
1475

1476
					CVT_APPEND_STR(tmp);
B
Bruce Momjian 已提交
1477
				}
1478

1479
				CVT_APPEND_CHAR('\'');	/* Close Quote */
1480

B
Bruce Momjian 已提交
1481
				break;
1482

B
Bruce Momjian 已提交
1483 1484 1485 1486 1487 1488
			case SQL_DATE:
				if (buf)
				{				/* copy char data to time */
					my_strcpy(cbuf, sizeof(cbuf), buf, used);
					parse_datetime(cbuf, &st);
				}
1489

B
Bruce Momjian 已提交
1490
				sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d);
1491

1492
				CVT_APPEND_STR(tmp);
B
Bruce Momjian 已提交
1493
				break;
1494

B
Bruce Momjian 已提交
1495 1496 1497 1498 1499 1500
			case SQL_TIME:
				if (buf)
				{				/* copy char data to time */
					my_strcpy(cbuf, sizeof(cbuf), buf, used);
					parse_datetime(cbuf, &st);
				}
1501

B
Bruce Momjian 已提交
1502
				sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss);
1503

1504
				CVT_APPEND_STR(tmp);
B
Bruce Momjian 已提交
1505
				break;
1506

B
Bruce Momjian 已提交
1507
			case SQL_TIMESTAMP:
1508

B
Bruce Momjian 已提交
1509 1510 1511 1512 1513
				if (buf)
				{
					my_strcpy(cbuf, sizeof(cbuf), buf, used);
					parse_datetime(cbuf, &st);
				}
1514

B
Bruce Momjian 已提交
1515 1516
				sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'",
						st.y, st.m, st.d, st.hh, st.mm, st.ss);
1517

1518
				CVT_APPEND_STR(tmp);
1519

B
Bruce Momjian 已提交
1520
				break;
1521

B
Bruce Momjian 已提交
1522 1523 1524
			case SQL_BINARY:
			case SQL_VARBINARY:/* non-ascii characters should be
								 * converted to octal */
1525
				CVT_APPEND_CHAR('\'');	/* Open Quote */
1526

B
Bruce Momjian 已提交
1527
				mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
1528

1529
				CVT_APPEND_BINARY(buf, used);
1530

1531
				CVT_APPEND_CHAR('\'');	/* Close Quote */
B
Byron Nikolaidis 已提交
1532

B
Bruce Momjian 已提交
1533
				break;
1534

B
Bruce Momjian 已提交
1535 1536 1537 1538 1539 1540 1541
			case SQL_LONGVARBINARY:

				if (stmt->parameters[param_number].data_at_exec)
					lobj_oid = stmt->parameters[param_number].lobj_oid;
				else
				{
					/* begin transaction if needed */
1542
					if (!CC_is_in_trans(conn))
B
Bruce Momjian 已提交
1543 1544 1545 1546
					{
						QResultClass *res;
						char		ok;

1547
						res = CC_send_query(conn, "BEGIN", NULL);
B
Bruce Momjian 已提交
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
						if (!res)
						{
							stmt->errormsg = "Could not begin (in-line) a transaction";
							stmt->errornumber = STMT_EXEC_ERROR;
							SC_log_error(func, "", stmt);
							return SQL_ERROR;
						}
						ok = QR_command_successful(res);
						QR_Destructor(res);
						if (!ok)
						{
							stmt->errormsg = "Could not begin (in-line) a transaction";
							stmt->errornumber = STMT_EXEC_ERROR;
							SC_log_error(func, "", stmt);
							return SQL_ERROR;
						}
1564

1565
						CC_set_in_trans(conn);
B
Bruce Momjian 已提交
1566
					}
B
Byron Nikolaidis 已提交
1567

B
Bruce Momjian 已提交
1568
					/* store the oid */
1569
					lobj_oid = lo_creat(conn, INV_READ | INV_WRITE);
B
Bruce Momjian 已提交
1570 1571
					if (lobj_oid == 0)
					{
B
Byron Nikolaidis 已提交
1572
						stmt->errornumber = STMT_EXEC_ERROR;
B
Bruce Momjian 已提交
1573
						stmt->errormsg = "Couldnt create (in-line) large object.";
B
Byron Nikolaidis 已提交
1574 1575 1576
						SC_log_error(func, "", stmt);
						return SQL_ERROR;
					}
B
Bruce Momjian 已提交
1577 1578

					/* store the fd */
1579
					lobj_fd = lo_open(conn, lobj_oid, INV_WRITE);
B
Bruce Momjian 已提交
1580 1581
					if (lobj_fd < 0)
					{
B
Byron Nikolaidis 已提交
1582
						stmt->errornumber = STMT_EXEC_ERROR;
B
Bruce Momjian 已提交
1583
						stmt->errormsg = "Couldnt open (in-line) large object for writing.";
B
Byron Nikolaidis 已提交
1584 1585 1586 1587
						SC_log_error(func, "", stmt);
						return SQL_ERROR;
					}

1588
					retval = lo_write(conn, lobj_fd, buffer, used);
1589

1590
					lo_close(conn, lobj_fd);
1591

B
Bruce Momjian 已提交
1592
					/* commit transaction if needed */
1593
					if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
B
Bruce Momjian 已提交
1594 1595 1596
					{
						QResultClass *res;
						char		ok;
1597

1598
						res = CC_send_query(conn, "COMMIT", NULL);
B
Bruce Momjian 已提交
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
						if (!res)
						{
							stmt->errormsg = "Could not commit (in-line) a transaction";
							stmt->errornumber = STMT_EXEC_ERROR;
							SC_log_error(func, "", stmt);
							return SQL_ERROR;
						}
						ok = QR_command_successful(res);
						QR_Destructor(res);
						if (!ok)
						{
							stmt->errormsg = "Could not commit (in-line) a transaction";
							stmt->errornumber = STMT_EXEC_ERROR;
							SC_log_error(func, "", stmt);
							return SQL_ERROR;
						}
1615

1616
						CC_set_no_trans(conn);
B
Bruce Momjian 已提交
1617 1618
					}
				}
1619

B
Bruce Momjian 已提交
1620 1621 1622 1623 1624 1625
				/*
				 * the oid of the large object -- just put that in for the
				 * parameter marker -- the data has already been sent to
				 * the large object
				 */
				sprintf(param_string, "'%d'", lobj_oid);
1626
				CVT_APPEND_STR(param_string);
1627

B
Bruce Momjian 已提交
1628 1629 1630 1631 1632 1633 1634
				break;

				/*
				 * because of no conversion operator for bool and int4,
				 * SQL_BIT
				 */
				/* must be quoted (0 or 1 is ok to use inside the quotes) */
1635

B
Bruce Momjian 已提交
1636 1637 1638 1639
			case SQL_REAL:
				if (buf)
					my_strcpy(param_string, sizeof(param_string), buf, used);
				sprintf(tmp, "'%s'::float4", param_string);
1640
				CVT_APPEND_STR(tmp);
B
Bruce Momjian 已提交
1641 1642 1643 1644 1645 1646
				break;
			case SQL_FLOAT:
			case SQL_DOUBLE:
				if (buf)
					my_strcpy(param_string, sizeof(param_string), buf, used);
				sprintf(tmp, "'%s'::float8", param_string);
1647
				CVT_APPEND_STR(tmp);
B
Bruce Momjian 已提交
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
				break;
			case SQL_NUMERIC:
				if (buf)
				{
					cbuf[0] = '\'';
					my_strcpy(cbuf + 1, sizeof(cbuf) - 12, buf, used);	/* 12 = 1('\'') +
																		 * strlen("'::numeric")
																		 * + 1('\0') */
					strcat(cbuf, "'::numeric");
				}
				else
					sprintf(cbuf, "'%s'::numeric", param_string);
1660
				CVT_APPEND_STR(cbuf);
B
Bruce Momjian 已提交
1661 1662 1663
				break;
			default:			/* a numeric type or SQL_BIT */
				if (param_sqltype == SQL_BIT)
1664
					CVT_APPEND_CHAR('\'');		/* Open Quote */
B
Bruce Momjian 已提交
1665 1666 1667

				if (buf)
				{
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
					switch (used)
					{
						case SQL_NULL_DATA:
							break;
						case SQL_NTS:
							CVT_APPEND_STR(buf);
							break;
						default:
							CVT_APPEND_DATA(buf, used);
					}
B
Bruce Momjian 已提交
1678 1679
				}
				else
1680
					CVT_APPEND_STR(param_string);
B
Bruce Momjian 已提交
1681 1682

				if (param_sqltype == SQL_BIT)
1683
					CVT_APPEND_CHAR('\'');		/* Close Quote */
B
Bruce Momjian 已提交
1684 1685

				break;
1686
		}
B
Bruce Momjian 已提交
1687
	}							/* end, for */
1688

B
Bruce Momjian 已提交
1689
	/* make sure new_statement is always null-terminated */
1690
	CVT_TERMINATE;
1691

1692
	if (conn->DriverToDataSource != NULL)
B
Bruce Momjian 已提交
1693 1694 1695
	{
		int			length = strlen(new_statement);

1696
		conn->DriverToDataSource(conn->translation_option,
B
Bruce Momjian 已提交
1697 1698 1699 1700
									   SQL_CHAR,
									   new_statement, length,
									   new_statement, length, NULL,
									   NULL, 0, NULL);
B
Byron Nikolaidis 已提交
1701 1702
	}

1703
#ifdef	DRIVER_CURSOR_IMPLEMENT
H
Hiroshi Inoue 已提交
1704
	if (search_from_pos)
1705 1706
		stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
#endif /* DRIVER_CURSOR_IMPLEMENT */
1707 1708 1709 1710 1711
	if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
	{
		char fetchstr[128];	
		sprintf(fetchstr, ";fetch backward in %s;close %s;",
				stmt->cursor_name, stmt->cursor_name);
1712 1713
		if (begin_first && CC_is_in_autocommit(conn))
			strcat(fetchstr, "COMMIT;");
1714 1715 1716 1717
		CVT_APPEND_STR(fetchstr);
		stmt->inaccurate_result = TRUE;
	}

1718 1719 1720
	return SQL_SUCCESS;
}

1721

1722
static char *
1723
mapFunction(const char *func)
1724
{
B
Bruce Momjian 已提交
1725
	int			i;
1726 1727

	for (i = 0; mapFuncs[i][0]; i++)
B
Bruce Momjian 已提交
1728
		if (!stricmp(mapFuncs[i][0], func))
1729 1730 1731 1732
			return mapFuncs[i][1];

	return NULL;
}
1733

1734 1735 1736 1737

/*
 * convert_escape()
 *
1738 1739
 * This function returns a pointer to static memory!
 */
1740 1741 1742
char *
convert_escape(char *value)
{
B
Bruce Momjian 已提交
1743 1744
	static char escape[1024];
	char		key[33];
1745

1746
	/* Separate off the key, skipping leading and trailing whitespace */
B
Bruce Momjian 已提交
1747 1748
	while ((*value != '\0') && isspace((unsigned char) *value))
		value++;
1749
	sscanf(value, "%32s", key);
B
Bruce Momjian 已提交
1750 1751 1752 1753
	while ((*value != '\0') && (!isspace((unsigned char) *value)))
		value++;
	while ((*value != '\0') && isspace((unsigned char) *value))
		value++;
1754

1755
	mylog("convert_escape: key='%s', val='%s'\n", key, value);
1756

B
Bruce Momjian 已提交
1757 1758
	if ((strcmp(key, "d") == 0) ||
		(strcmp(key, "t") == 0) ||
1759 1760
		(strcmp(key, "oj") == 0) ||		/* {oj syntax support for 7.1
										 * servers */
B
Bruce Momjian 已提交
1761 1762
		(strcmp(key, "ts") == 0))
	{
1763
		/* Literal; return the escape part as-is */
B
Bruce Momjian 已提交
1764
		strncpy(escape, value, sizeof(escape) - 1);
1765
	}
B
Bruce Momjian 已提交
1766 1767
	else if (strcmp(key, "fn") == 0)
	{
1768

B
Bruce Momjian 已提交
1769 1770 1771
		/*
		 * Function invocation Separate off the func name, skipping
		 * trailing whitespace.
1772
		 */
B
Bruce Momjian 已提交
1773 1774 1775
		char	   *funcEnd = value;
		char		svchar;
		char	   *mapFunc;
1776 1777

		while ((*funcEnd != '\0') && (*funcEnd != '(') &&
B
Bruce Momjian 已提交
1778
			   (!isspace((unsigned char) *funcEnd)))
1779
			funcEnd++;
1780 1781 1782 1783
		svchar = *funcEnd;
		*funcEnd = '\0';
		sscanf(value, "%32s", key);
		*funcEnd = svchar;
1784 1785
		while ((*funcEnd != '\0') && isspace((unsigned char) *funcEnd))
			funcEnd++;
1786

B
Bruce Momjian 已提交
1787 1788 1789
		/*
		 * We expect left parenthesis here, else return fn body as-is
		 * since it is one of those "function constants".
1790
		 */
B
Bruce Momjian 已提交
1791 1792 1793
		if (*funcEnd != '(')
		{
			strncpy(escape, value, sizeof(escape) - 1);
1794
			return escape;
1795
		}
1796
		mapFunc = mapFunction(key);
B
Bruce Momjian 已提交
1797 1798

		/*
1799 1800
		 * We could have mapFunction() return key if not in table...
		 * - thomas 2000-04-03
1801
		 */
B
Bruce Momjian 已提交
1802 1803
		if (mapFunc == NULL)
		{
1804
			/* If unrecognized function name, return fn body as-is */
B
Bruce Momjian 已提交
1805
			strncpy(escape, value, sizeof(escape) - 1);
1806 1807 1808 1809
			return escape;
		}
		/* copy mapped name and remaining input string */
		strcpy(escape, mapFunc);
B
Bruce Momjian 已提交
1810
		strncat(escape, funcEnd, sizeof(escape) - 1 - strlen(mapFunc));
1811
	}
B
Bruce Momjian 已提交
1812 1813
	else
	{
1814
		/* Bogus key, leave untranslated */
1815 1816 1817 1818 1819 1820 1821
		return NULL;
	}

	return escape;
}


1822 1823
BOOL
convert_money(const char *s, char *sout, size_t soutmax)
1824
{
1825
	size_t		i = 0, out = 0;
1826

1827
	for (i = 0; s[i]; i++)
B
Bruce Momjian 已提交
1828
	{
1829
		if (s[i] == '$' || s[i] == ',' || s[i] == ')')
B
Bruce Momjian 已提交
1830
			;					/* skip these characters */
1831
		else
1832 1833 1834 1835 1836 1837 1838 1839
		{
			if (out + 1 >= soutmax)
				return FALSE; /* sout is too short */
			if (s[i] == '(')
				sout[out++] = '-';
			else
				sout[out++] = s[i];
		}
1840
	}
1841 1842
	sout[out] = '\0';
	return TRUE;
1843 1844 1845
}


1846 1847 1848 1849
/*
 *	This function parses a character string for date/time info and fills in SIMPLE_TIME
 *	It does not zero out SIMPLE_TIME in case it is desired to initialize it with a value
 */
1850
char
B
Bruce Momjian 已提交
1851
parse_datetime(char *buf, SIMPLE_TIME *st)
1852
{
B
Bruce Momjian 已提交
1853 1854 1855 1856 1857 1858 1859 1860
	int			y,
				m,
				d,
				hh,
				mm,
				ss;
	int			nf;

1861 1862
	y = m = d = hh = mm = ss = 0;

1863 1864 1865 1866 1867 1868 1869 1870
	/* escape sequence ? */
	if (buf[0] == '{')
	{
		while (*(++buf) && *buf != '\'');
		if (!(*buf))
			return FALSE;
		buf++;
	}
B
Bruce Momjian 已提交
1871 1872
	if (buf[4] == '-')			/* year first */
		nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh, &mm, &ss);
1873
	else
B
Bruce Momjian 已提交
1874
		nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh, &mm, &ss);
1875

B
Bruce Momjian 已提交
1876 1877
	if (nf == 5 || nf == 6)
	{
1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
		st->y = y;
		st->m = m;
		st->d = d;
		st->hh = hh;
		st->mm = mm;
		st->ss = ss;

		return TRUE;
	}

B
Bruce Momjian 已提交
1888
	if (buf[4] == '-')			/* year first */
1889 1890 1891 1892
		nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
	else
		nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);

B
Bruce Momjian 已提交
1893 1894
	if (nf == 3)
	{
1895 1896 1897 1898 1899 1900 1901 1902
		st->y = y;
		st->m = m;
		st->d = d;

		return TRUE;
	}

	nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
B
Bruce Momjian 已提交
1903 1904
	if (nf == 2 || nf == 3)
	{
1905 1906 1907 1908 1909 1910 1911 1912 1913
		st->hh = hh;
		st->mm = mm;
		st->ss = ss;

		return TRUE;
	}

	return FALSE;
}
1914

1915

1916
/*	Change linefeed to carriage-return/linefeed */
1917
int
1918
convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
1919
{
B
Bruce Momjian 已提交
1920 1921
	size_t		i = 0,
				out = 0;
1922

1923 1924 1925 1926
	if (max == 0)
		max = 0xffffffff;
	*changed = FALSE;
	for (i = 0; si[i] && out < max - 1; i++)
B
Bruce Momjian 已提交
1927 1928 1929 1930 1931 1932
	{
		if (si[i] == '\n')
		{
			/* Only add the carriage-return if needed */
			if (i > 0 && si[i - 1] == '\r')
			{
1933 1934 1935 1936
				if (dst)
					dst[out++] = si[i];
				else
					out++;
B
Byron Nikolaidis 已提交
1937 1938
				continue;
			}
1939
			*changed = TRUE;
B
Byron Nikolaidis 已提交
1940

1941 1942 1943 1944 1945 1946 1947
			if (dst)
			{
				dst[out++] = '\r';
				dst[out++] = '\n';
			}
			else
				out += 2;
1948 1949
		}
		else
1950 1951 1952 1953 1954 1955
		{
			if (dst)
				dst[out++] = si[i];
			else
				out++;
		}
1956
	}
1957 1958
	if (dst)
		dst[out] = '\0';
1959
	return out;
1960 1961
}

1962 1963 1964 1965 1966

/*
 *	Change carriage-return/linefeed to just linefeed
 *	Plus, escape any special characters.
 */
1967
int
1968
convert_special_chars(const char *si, char *dst, int used)
1969
{
B
Bruce Momjian 已提交
1970 1971 1972
	size_t		i = 0,
				out = 0,
				max;
1973
	char	   *p = NULL;
1974 1975 1976 1977 1978 1979


	if (used == SQL_NTS)
		max = strlen(si);
	else
		max = used;
1980 1981 1982 1983 1984
	if (dst)
	{
		p = dst;
		p[0] = '\0';
	}
H
Hiroshi Inoue 已提交
1985 1986 1987
#ifdef MULTIBYTE
	multibyte_init();
#endif
1988

B
Bruce Momjian 已提交
1989 1990
	for (i = 0; i < max; i++)
	{
1991 1992 1993 1994 1995 1996 1997 1998 1999
#ifdef MULTIBYTE
		if (multibyte_char_check(si[i]) != 0)
		{
			if (p)
				p[out] = si[i];
			out++;
			continue;
		}
#endif
2000
		if (si[i] == '\r' && si[i + 1] == '\n')
2001
			continue;
B
Byron Nikolaidis 已提交
2002
		else if (si[i] == '\'' || si[i] == '\\')
2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
		{
			if (p)
				p[out++] = '\\';
			else
				out++;
		}
		if (p)
			p[out++] = si[i];
		else
			out++;
2013
	}
2014 2015 2016
	if (p)
		p[out] = '\0';
	return out;
2017 2018
}

2019

2020 2021
/*	!!! Need to implement this function !!!  */
int
2022
convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax)
2023
{
2024 2025 2026
	mylog("convert_pgbinary_to_char: value = '%s'\n", value);

	strncpy_null(rgbValue, value, cbValueMax);
2027 2028 2029
	return 0;
}

2030

2031
static unsigned int
2032
conv_from_octal(const unsigned char *s)
2033
{
B
Bruce Momjian 已提交
2034 2035
	int			i,
				y = 0;
2036

B
Bruce Momjian 已提交
2037 2038
	for (i = 1; i <= 3; i++)
		y += (s[i] - 48) * (int) pow(8, 3 - i);
2039 2040

	return y;
2041

2042 2043
}

2044

2045
static unsigned int
2046
conv_from_hex(const unsigned char *s)
B
Byron Nikolaidis 已提交
2047
{
B
Bruce Momjian 已提交
2048 2049 2050
	int			i,
				y = 0,
				val;
2051

B
Bruce Momjian 已提交
2052 2053 2054 2055 2056 2057 2058 2059
	for (i = 1; i <= 2; i++)
	{
		if (s[i] >= 'a' && s[i] <= 'f')
			val = s[i] - 'a' + 10;
		else if (s[i] >= 'A' && s[i] <= 'F')
			val = s[i] - 'A' + 10;
		else
			val = s[i] - '0';
B
Byron Nikolaidis 已提交
2060

B
Bruce Momjian 已提交
2061
		y += val * (int) pow(16, 2 - i);
B
Byron Nikolaidis 已提交
2062 2063 2064 2065 2066
	}

	return y;
}

2067

B
Bruce Momjian 已提交
2068
/*	convert octal escapes to bytes */
2069
int
2070
convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax)
2071
{
2072
	size_t		i, ilen = strlen(value);
B
Bruce Momjian 已提交
2073
	int			o = 0;
2074

B
Bruce Momjian 已提交
2075

2076
	for (i = 0; i < ilen;)
B
Bruce Momjian 已提交
2077 2078 2079
	{
		if (value[i] == '\\')
		{
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089
			if (value[i + 1] == '\\')
			{
				rgbValue[o] = value[i];
				i += 2;
			}
			else
			{
				rgbValue[o] = conv_from_octal(&value[i]);
				i += 4;
			}
2090
		}
B
Bruce Momjian 已提交
2091
		else
2092 2093 2094 2095
			rgbValue[o] = value[i++];
		mylog("convert_from_pgbinary: i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]);
		o++;
	}
2096

B
Bruce Momjian 已提交
2097
	rgbValue[o] = '\0';			/* extra protection */
2098

2099 2100 2101 2102
	return o;
}


2103
static char *
2104 2105
conv_to_octal(unsigned char val)
{
B
Bruce Momjian 已提交
2106 2107
	int			i;
	static char x[6];
2108 2109 2110 2111 2112

	x[0] = '\\';
	x[1] = '\\';
	x[5] = '\0';

B
Bruce Momjian 已提交
2113 2114
	for (i = 4; i > 1; i--)
	{
2115 2116 2117 2118 2119 2120 2121
		x[i] = (val & 7) + 48;
		val >>= 3;
	}

	return x;
}

2122

B
Bruce Momjian 已提交
2123
/*	convert non-ascii bytes to octal escape sequences */
2124
int
2125
convert_to_pgbinary(const unsigned char *in, char *out, int len)
2126
{
B
Bruce Momjian 已提交
2127 2128
	int			i,
				o = 0;
2129

B
Bruce Momjian 已提交
2130 2131
	for (i = 0; i < len; i++)
	{
2132
		mylog("convert_to_pgbinary: in[%d] = %d, %c\n", i, in[i], in[i]);
B
Bruce Momjian 已提交
2133
		if (isalnum(in[i]) || in[i] == ' ')
2134
			out[o++] = in[i];
B
Bruce Momjian 已提交
2135 2136 2137
		else
		{
			strcpy(&out[o], conv_to_octal(in[i]));
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147
			o += 5;
		}
	}

	mylog("convert_to_pgbinary: returning %d, out='%.*s'\n", o, o, out);

	return o;
}


B
Byron Nikolaidis 已提交
2148
void
2149
encode(const char *in, char *out)
B
Byron Nikolaidis 已提交
2150
{
2151
	unsigned int i, ilen = strlen(in),
B
Bruce Momjian 已提交
2152
				o = 0;
B
Byron Nikolaidis 已提交
2153

2154
	for (i = 0; i < ilen; i++)
B
Bruce Momjian 已提交
2155 2156 2157
	{
		if (in[i] == '+')
		{
B
Byron Nikolaidis 已提交
2158 2159 2160
			sprintf(&out[o], "%%2B");
			o += 3;
		}
B
Bruce Momjian 已提交
2161
		else if (isspace((unsigned char) in[i]))
B
Byron Nikolaidis 已提交
2162
			out[o++] = '+';
B
Bruce Momjian 已提交
2163 2164
		else if (!isalnum((unsigned char) in[i]))
		{
2165
			sprintf(&out[o], "%%%02x", (unsigned char) in[i]);
B
Byron Nikolaidis 已提交
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175
			o += 3;
		}
		else
			out[o++] = in[i];
	}
	out[o++] = '\0';
}


void
2176
decode(const char *in, char *out)
B
Byron Nikolaidis 已提交
2177
{
2178
	unsigned int i, ilen = strlen(in),
B
Bruce Momjian 已提交
2179
				o = 0;
B
Byron Nikolaidis 已提交
2180

2181
	for (i = 0; i < ilen; i++)
B
Bruce Momjian 已提交
2182
	{
B
Byron Nikolaidis 已提交
2183 2184
		if (in[i] == '+')
			out[o++] = ' ';
B
Bruce Momjian 已提交
2185 2186
		else if (in[i] == '%')
		{
B
Byron Nikolaidis 已提交
2187
			sprintf(&out[o++], "%c", conv_from_hex(&in[i]));
B
Bruce Momjian 已提交
2188
			i += 2;
B
Byron Nikolaidis 已提交
2189 2190 2191 2192 2193 2194 2195 2196
		}
		else
			out[o++] = in[i];
	}
	out[o++] = '\0';
}


2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212
/*-------
 *	1. get oid (from 'value')
 *	2. open the large object
 *	3. read from the large object (handle multiple GetData)
 *	4. close when read less than requested?  -OR-
 *		lseek/read each time
 *		handle case where application receives truncated and
 *		decides not to continue reading.
 *
 *	CURRENTLY, ONLY LONGVARBINARY is handled, since that is the only
 *	data type currently mapped to a PG_TYPE_LO.  But, if any other types
 *	are desired to map to a large object (PG_TYPE_LO), then that would
 *	need to be handled here.  For example, LONGVARCHAR could possibly be
 *	mapped to PG_TYPE_LO someday, instead of PG_TYPE_TEXT as it is now.
 *-------
 */
2213
int
H
Hiroshi Inoue 已提交
2214
convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
B
Bruce Momjian 已提交
2215
		   SDWORD cbValueMax, SDWORD *pcbValue)
2216
{
B
Bruce Momjian 已提交
2217 2218 2219 2220
	Oid			oid;
	int			retval,
				result,
				left = -1;
T
Tom Lane 已提交
2221
	BindInfoClass *bindInfo = NULL;
2222 2223
	ConnectionClass	*conn = SC_get_conn(stmt);
	ConnInfo	*ci = &(conn->connInfo);
2224

2225
	/* If using SQLGetData, then current_col will be set */
B
Bruce Momjian 已提交
2226 2227
	if (stmt->current_col >= 0)
	{
2228 2229 2230
		bindInfo = &stmt->bindings[stmt->current_col];
		left = bindInfo->data_left;
	}
2231

B
Bruce Momjian 已提交
2232 2233 2234 2235
	/*
	 * if this is the first call for this column, open the large object
	 * for reading
	 */
2236

B
Bruce Momjian 已提交
2237 2238
	if (!bindInfo || bindInfo->data_left == -1)
	{
B
Byron Nikolaidis 已提交
2239
		/* begin transaction if needed */
2240
		if (!CC_is_in_trans(conn))
B
Bruce Momjian 已提交
2241
		{
B
Byron Nikolaidis 已提交
2242
			QResultClass *res;
B
Bruce Momjian 已提交
2243
			char		ok;
B
Byron Nikolaidis 已提交
2244

2245
			res = CC_send_query(conn, "BEGIN", NULL);
B
Bruce Momjian 已提交
2246 2247
			if (!res)
			{
B
Byron Nikolaidis 已提交
2248 2249 2250 2251 2252 2253
				stmt->errormsg = "Could not begin (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}
			ok = QR_command_successful(res);
			QR_Destructor(res);
B
Bruce Momjian 已提交
2254 2255
			if (!ok)
			{
B
Byron Nikolaidis 已提交
2256 2257 2258 2259 2260
				stmt->errormsg = "Could not begin (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}

2261
			CC_set_in_trans(conn);
B
Byron Nikolaidis 已提交
2262 2263
		}

2264
		oid = atoi(value);
2265
		stmt->lobj_fd = lo_open(conn, oid, INV_READ);
B
Bruce Momjian 已提交
2266 2267
		if (stmt->lobj_fd < 0)
		{
2268
			stmt->errornumber = STMT_EXEC_ERROR;
2269
			stmt->errormsg = "Couldnt open large object for reading.";
2270 2271
			return COPY_GENERAL_ERROR;
		}
2272

B
Bruce Momjian 已提交
2273
		/* Get the size */
2274
		retval = lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_END);
B
Bruce Momjian 已提交
2275 2276
		if (retval >= 0)
		{
2277
			left = lo_tell(conn, stmt->lobj_fd);
2278 2279 2280
			if (bindInfo)
				bindInfo->data_left = left;

B
Bruce Momjian 已提交
2281
			/* return to beginning */
2282
			lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET);
2283 2284
		}
	}
2285
	mylog("lo data left = %d\n", left);
2286

B
Bruce Momjian 已提交
2287
	if (left == 0)
2288
		return COPY_NO_DATA_FOUND;
2289

B
Bruce Momjian 已提交
2290 2291
	if (stmt->lobj_fd < 0)
	{
2292 2293 2294 2295
		stmt->errornumber = STMT_EXEC_ERROR;
		stmt->errormsg = "Large object FD undefined for multiple read.";
		return COPY_GENERAL_ERROR;
	}
2296

2297
	retval = lo_read(conn, stmt->lobj_fd, (char *) rgbValue, cbValueMax);
B
Bruce Momjian 已提交
2298 2299
	if (retval < 0)
	{
2300
		lo_close(conn, stmt->lobj_fd);
B
Byron Nikolaidis 已提交
2301 2302

		/* commit transaction if needed */
2303
		if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
B
Bruce Momjian 已提交
2304
		{
B
Byron Nikolaidis 已提交
2305
			QResultClass *res;
B
Bruce Momjian 已提交
2306
			char		ok;
B
Byron Nikolaidis 已提交
2307

2308
			res = CC_send_query(conn, "COMMIT", NULL);
B
Bruce Momjian 已提交
2309 2310
			if (!res)
			{
B
Byron Nikolaidis 已提交
2311 2312 2313 2314 2315 2316
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}
			ok = QR_command_successful(res);
			QR_Destructor(res);
B
Bruce Momjian 已提交
2317 2318
			if (!ok)
			{
B
Byron Nikolaidis 已提交
2319 2320 2321 2322 2323
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}

2324
			CC_set_no_trans(conn);
B
Byron Nikolaidis 已提交
2325 2326
		}

2327 2328 2329 2330 2331 2332 2333
		stmt->lobj_fd = -1;

		stmt->errornumber = STMT_EXEC_ERROR;
		stmt->errormsg = "Error reading from large object.";
		return COPY_GENERAL_ERROR;
	}

2334 2335 2336 2337 2338 2339 2340
	if (retval < left)
		result = COPY_RESULT_TRUNCATED;
	else
		result = COPY_OK;

	if (pcbValue)
		*pcbValue = left < 0 ? SQL_NO_TOTAL : left;
2341

B
Bruce Momjian 已提交
2342
	if (bindInfo && bindInfo->data_left > 0)
2343
		bindInfo->data_left -= retval;
2344

B
Bruce Momjian 已提交
2345 2346
	if (!bindInfo || bindInfo->data_left == 0)
	{
2347
		lo_close(conn, stmt->lobj_fd);
B
Byron Nikolaidis 已提交
2348 2349

		/* commit transaction if needed */
2350
		if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
B
Bruce Momjian 已提交
2351
		{
B
Byron Nikolaidis 已提交
2352
			QResultClass *res;
B
Bruce Momjian 已提交
2353
			char		ok;
B
Byron Nikolaidis 已提交
2354

2355
			res = CC_send_query(conn, "COMMIT", NULL);
B
Bruce Momjian 已提交
2356 2357
			if (!res)
			{
B
Byron Nikolaidis 已提交
2358 2359 2360 2361 2362 2363
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}
			ok = QR_command_successful(res);
			QR_Destructor(res);
B
Bruce Momjian 已提交
2364 2365
			if (!ok)
			{
B
Byron Nikolaidis 已提交
2366 2367 2368 2369 2370
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}

2371
			CC_set_no_trans(conn);
B
Byron Nikolaidis 已提交
2372 2373
		}

B
Bruce Momjian 已提交
2374
		stmt->lobj_fd = -1;		/* prevent further reading */
2375
	}
2376 2377

	return result;
2378
}