convert.c 41.6 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

B
Byron Nikolaidis 已提交
20
#ifdef HAVE_CONFIG_H
21
#include "config.h"
B
Byron Nikolaidis 已提交
22 23
#endif

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

B
 
Byron Nikolaidis 已提交
28 29
#include "psqlodbc.h"

H
Hiroshi Inoue 已提交
30 31 32 33
#ifdef MULTIBYTE
#include "multibyte.h"
#endif

34
#ifndef WIN32
B
Byron Nikolaidis 已提交
35 36 37 38
#include "iodbc.h"
#include "isql.h"
#include "isqlext.h"
#else
39
#include <windows.h>
40
#include <sql.h>
41
#include <sqlext.h>
B
Byron Nikolaidis 已提交
42 43
#endif

44
#include <time.h>
45
#include <math.h>
46
#include <stdlib.h>
47 48
#include "convert.h"
#include "statement.h"
B
Byron Nikolaidis 已提交
49
#include "qresult.h"
50 51
#include "bind.h"
#include "pgtypes.h"
52 53 54
#include "lobj.h"
#include "connection.h"

55 56
#ifndef WIN32
#ifndef HAVE_STRICMP
B
Byron Nikolaidis 已提交
57 58 59 60 61
#define stricmp(s1,s2) strcasecmp(s1,s2)
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
#endif
#ifndef SCHAR
typedef signed char SCHAR;
B
Bruce Momjian 已提交
62

B
Byron Nikolaidis 已提交
63 64 65
#endif
#endif

66 67
extern GLOBAL_VALUES globals;

68 69 70 71
/*
 *	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
72
 *	- thomas 2000-04-03
73
 */
B
Bruce Momjian 已提交
74 75 76 77
char	   *mapFuncs[][2] = {
/*	{ "ASCII",		 "ascii"	  }, */
	{"CHAR", "chr"},
	{"CONCAT", "textcat"},
B
Bruce Momjian 已提交
78
/*	{ "DIFFERENCE",  "difference" }, */
B
Bruce Momjian 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
/*	{ "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 已提交
121
/*	{ "DAYOFMONTH",  "dayofmonth" }, */
B
Bruce Momjian 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
/*	{ "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}
138 139
};

B
Bruce Momjian 已提交
140
char	   *mapFunction(char *func);
141 142
unsigned int conv_from_octal(unsigned char *s);
unsigned int conv_from_hex(unsigned char *s);
B
Bruce Momjian 已提交
143
char	   *conv_to_octal(unsigned char val);
144

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
/*---------
 *			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
 *---------
 */
162 163 164 165 166



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

B
Bruce Momjian 已提交
171 172
	return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) bic->buffer,
							 (SDWORD) bic->buflen, (SDWORD *) bic->used);
173 174
}

175

176 177
/*	This is called by SQLGetData() */
int
B
Bruce Momjian 已提交
178
copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
B
Bruce Momjian 已提交
179
					   PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
180
{
B
Bruce Momjian 已提交
181 182
	Int4		len = 0,
				copy_len = 0;
183
	SIMPLE_TIME st;
B
Bruce Momjian 已提交
184 185 186 187 188 189 190 191 192 193
	time_t		t = time(NULL);
	struct tm  *tim;
	int			pcbValueOffset,
				rgbValueOffset;
	char	   *rgbValueBindRow,
			   *ptr;
	int			bind_row = stmt->bind_row;
	int			bind_size = stmt->options.bind_size;
	int			result = COPY_OK;
	char		tempBuf[TEXT_FIELD_SIZE + 5];
194

195 196 197 198 199
	/*---------
	 *	rgbValueOffset is *ONLY* for character and binary data.
	 *	pcbValueOffset is for computing any pcbValue location
	 *---------
	 */
200

B
Bruce Momjian 已提交
201
	if (bind_size > 0)
202
		pcbValueOffset = rgbValueOffset = (bind_size * bind_row);
B
Bruce Momjian 已提交
203 204
	else
	{
205 206
		pcbValueOffset = bind_row * sizeof(SDWORD);
		rgbValueOffset = bind_row * cbValueMax;
207

208
	}
209 210 211

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

B
Bruce Momjian 已提交
212
	/* Initialize current date */
213 214 215 216 217
	tim = localtime(&t);
	st.m = tim->tm_mon + 1;
	st.d = tim->tm_mday;
	st.y = tim->tm_year + 1900;

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

B
Bruce Momjian 已提交
220 221
	if (!value)
	{
222

223
		/*
224 225
		 * handle a null just by returning SQL_NULL_DATA in pcbValue, and
		 * doing nothing to the buffer.
226
		 */
B
Bruce Momjian 已提交
227
		if (pcbValue)
228
			*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA;
B
Byron Nikolaidis 已提交
229 230 231
		return COPY_OK;
	}

B
Bruce Momjian 已提交
232 233 234 235 236 237 238 239 240
	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 已提交
241 242
	}

243
	/*
244
	 * First convert any specific postgres types into more useable data.
245
	 *
246 247
	 * NOTE: Conversions from PG char/varchar of a date/time/timestamp value
	 * to SQL_C_DATE,SQL_C_TIME, SQL_C_TIMESTAMP not supported
248
	 */
B
Bruce Momjian 已提交
249 250
	switch (field_type)
	{
251 252 253 254 255

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

B
Bruce Momjian 已提交
260 261 262
		case PG_TYPE_TIME:
			sscanf(value, "%2d:%2d:%2d", &st.hh, &st.mm, &st.ss);
			break;
263

B
Bruce Momjian 已提交
264 265 266 267 268 269
		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
270
			{
271

272
				/*
273 274
				 * The timestamp is invalid so set something conspicuous,
				 * like the epoch
275
				 */
B
Bruce Momjian 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
				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:
			{					/* change T/F to 1/0 */
				char	   *s = (char *) value;

				if (s[0] == 'T' || s[0] == 't')
					s[0] = '1';
				else
					s[0] = '0';
			}
			break;

298
			/* This is for internal use by SQLStatistics() */
B
Bruce Momjian 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
		case PG_TYPE_INT2VECTOR:
			{
				int			nval,
							i;
				char	   *vp;

				/* 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 已提交
333

334
#if 0
B
Bruce Momjian 已提交
335 336 337 338 339 340 341 342 343
				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]);
344
#endif
B
Byron Nikolaidis 已提交
345

B
Bruce Momjian 已提交
346 347 348
				/* There is no corresponding fCType for this. */
				if (pcbValue)
					*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
B
Byron Nikolaidis 已提交
349

B
Bruce Momjian 已提交
350 351 352
				return COPY_OK; /* dont go any further or the data will be
								 * trashed */
			}
B
Byron Nikolaidis 已提交
353

B
Bruce Momjian 已提交
354 355 356 357 358
			/*
			 * This is a large object OID, which is used to store
			 * LONGVARBINARY objects.
			 */
		case PG_TYPE_LO:
B
Byron Nikolaidis 已提交
359

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

B
Bruce Momjian 已提交
362
		default:
B
Byron Nikolaidis 已提交
363

B
Bruce Momjian 已提交
364 365 366
			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 已提交
367 368
	}

B
Bruce Momjian 已提交
369 370 371
	/* Change default into something useable */
	if (fCType == SQL_C_DEFAULT)
	{
B
Byron Nikolaidis 已提交
372 373 374 375 376
		fCType = pgtype_to_ctype(stmt, field_type);

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

377 378
	rgbValueBindRow = (char *) rgbValue + rgbValueOffset;

B
Bruce Momjian 已提交
379 380 381
	if (fCType == SQL_C_CHAR)
	{
		/* Special character formatting as required */
382

B
Bruce Momjian 已提交
383 384 385 386 387 388 389 390 391 392 393
		/*
		 * 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;
394

B
Bruce Momjian 已提交
395 396 397 398 399
			case PG_TYPE_TIME:
				len = 8;
				if (cbValueMax > len)
					sprintf(rgbValueBindRow, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
				break;
400

B
Bruce Momjian 已提交
401 402 403 404 405 406 407 408
			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;
409

B
Bruce Momjian 已提交
410 411 412 413 414 415 416 417
			case PG_TYPE_BOOL:
				len = 1;
				if (cbValueMax > len)
				{
					strcpy(rgbValueBindRow, value);
					mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n", rgbValueBindRow);
				}
				break;
418

B
Bruce Momjian 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
				/*
				 * 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") */
				len = convert_pgbinary_to_char(value, rgbValueBindRow, cbValueMax);

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

B
Bruce Momjian 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
			default:
				/* convert linefeeds to carriage-return/linefeed */
				len = convert_linefeeds(value, tempBuf, sizeof(tempBuf));
				ptr = tempBuf;

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

				if (stmt->current_col >= 0)
				{
					if (stmt->bindings[stmt->current_col].data_left == 0)
						return COPY_NO_DATA_FOUND;
					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;
					}
					else
						stmt->bindings[stmt->current_col].data_left = strlen(ptr);
457 458
				}

B
Bruce Momjian 已提交
459 460 461
				if (cbValueMax > 0)
				{
					copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len;
462

B
Bruce Momjian 已提交
463 464
					/* Copy the data */
					strncpy_null(rgbValueBindRow, ptr, copy_len + 1);
465

B
Bruce Momjian 已提交
466 467 468
					/* Adjust data_left for next time */
					if (stmt->current_col >= 0)
						stmt->bindings[stmt->current_col].data_left -= copy_len;
469 470
				}

B
Bruce Momjian 已提交
471 472 473 474 475 476
				/*
				 * Finally, check for truncation so that proper status can
				 * be returned
				 */
				if (len >= cbValueMax)
					result = COPY_RESULT_TRUNCATED;
477 478


B
Bruce Momjian 已提交
479 480
				mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
				break;
B
Byron Nikolaidis 已提交
481
		}
482 483


B
Bruce Momjian 已提交
484 485 486
	}
	else
	{
487

B
Bruce Momjian 已提交
488 489 490 491 492
		/*
		 * 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 已提交
493 494 495
		if (field_type == PG_TYPE_MONEY)
			convert_money(value);

B
Bruce Momjian 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
		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;
512

B
Bruce Momjian 已提交
513 514 515 516 517 518 519 520 521 522 523 524 525 526
			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 已提交
527

B
Bruce Momjian 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
			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;
546

B
Bruce Momjian 已提交
547 548 549 550 551 552
			case SQL_C_BIT:
				len = 1;
				if (bind_size > 0)
					*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
				else
					*((UCHAR *) rgbValue + bind_row) = atoi(value);
553

B
Bruce Momjian 已提交
554 555 556 557 558
				/*
				 * mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n",
				 * atoi(value), cbValueMax, *((UCHAR *)rgbValue));
				 */
				break;
559

B
Bruce Momjian 已提交
560 561 562 563 564 565 566 567
			case SQL_C_STINYINT:
			case SQL_C_TINYINT:
				len = 1;
				if (bind_size > 0)
					*(SCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
				else
					*((SCHAR *) rgbValue + bind_row) = atoi(value);
				break;
568

B
Bruce Momjian 已提交
569 570 571 572 573 574 575
			case SQL_C_UTINYINT:
				len = 1;
				if (bind_size > 0)
					*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
				else
					*((UCHAR *) rgbValue + bind_row) = atoi(value);
				break;
576

B
Bruce Momjian 已提交
577 578 579 580 581 582 583
			case SQL_C_FLOAT:
				len = 4;
				if (bind_size > 0)
					*(SFLOAT *) ((char *) rgbValue + (bind_row * bind_size)) = (float) atof(value);
				else
					*((SFLOAT *) rgbValue + bind_row) = (float) atof(value);
				break;
584

B
Bruce Momjian 已提交
585 586 587 588 589 590 591
			case SQL_C_DOUBLE:
				len = 8;
				if (bind_size > 0)
					*(SDOUBLE *) ((char *) rgbValue + (bind_row * bind_size)) = atof(value);
				else
					*((SDOUBLE *) rgbValue + bind_row) = atof(value);
				break;
592

B
Bruce Momjian 已提交
593 594 595 596 597 598 599 600
			case SQL_C_SSHORT:
			case SQL_C_SHORT:
				len = 2;
				if (bind_size > 0)
					*(SWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
				else
					*((SWORD *) rgbValue + bind_row) = atoi(value);
				break;
601

B
Bruce Momjian 已提交
602 603 604 605 606 607 608
			case SQL_C_USHORT:
				len = 2;
				if (bind_size > 0)
					*(UWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
				else
					*((UWORD *) rgbValue + bind_row) = atoi(value);
				break;
609

B
Bruce Momjian 已提交
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
			case SQL_C_SLONG:
			case SQL_C_LONG:
				len = 4;
				if (bind_size > 0)
					*(SDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(value);
				else
					*((SDWORD *) rgbValue + bind_row) = atol(value);
				break;

			case SQL_C_ULONG:
				len = 4;
				if (bind_size > 0)
					*(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(value);
				else
					*((UDWORD *) rgbValue + bind_row) = atol(value);
				break;
626

B
Bruce Momjian 已提交
627
			case SQL_C_BINARY:
628

B
Bruce Momjian 已提交
629 630
				/* truncate if necessary */
				/* convert octal escapes to bytes */
631

B
Bruce Momjian 已提交
632 633
				len = convert_from_pgbinary(value, tempBuf, sizeof(tempBuf));
				ptr = tempBuf;
634

B
Bruce Momjian 已提交
635 636 637 638 639
				if (stmt->current_col >= 0)
				{
					/* No more data left for this column */
					if (stmt->bindings[stmt->current_col].data_left == 0)
						return COPY_NO_DATA_FOUND;
640

B
Bruce Momjian 已提交
641 642 643 644 645 646 647 648 649
					/*
					 * 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;
					}
650

B
Bruce Momjian 已提交
651 652 653
					/* First call to SQLGetData so initialize data_left */
					else
						stmt->bindings[stmt->current_col].data_left = len;
654

B
Bruce Momjian 已提交
655
				}
656

B
Bruce Momjian 已提交
657 658 659
				if (cbValueMax > 0)
				{
					copy_len = (len > cbValueMax) ? cbValueMax : len;
660

B
Bruce Momjian 已提交
661 662
					/* Copy the data */
					memcpy(rgbValueBindRow, ptr, copy_len);
663

B
Bruce Momjian 已提交
664 665 666
					/* Adjust data_left for next time */
					if (stmt->current_col >= 0)
						stmt->bindings[stmt->current_col].data_left -= copy_len;
667
				}
668

B
Bruce Momjian 已提交
669 670 671 672 673 674
				/*
				 * Finally, check for truncation so that proper status can
				 * be returned
				 */
				if (len > cbValueMax)
					result = COPY_RESULT_TRUNCATED;
675

B
Bruce Momjian 已提交
676 677 678 679 680
				mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
				break;

			default:
				return COPY_UNSUPPORTED_TYPE;
B
Byron Nikolaidis 已提交
681 682
		}
	}
683

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

688
	return result;
689

690 691
}

692

693 694 695 696 697
/*
 *	This function inserts parameters into an SQL statements.
 *	It will also modify a SELECT statement for use with declare/fetch cursors.
 *	This function no longer does any dynamic memory allocation!
 */
698
int
B
Bruce Momjian 已提交
699
copy_statement_with_parameters(StatementClass *stmt)
700
{
B
Bruce Momjian 已提交
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
	static char *func = "copy_statement_with_parameters";
	unsigned int opos,
				npos,
				oldstmtlen;
	char		param_string[128],
				tmp[256],
				cbuf[TEXT_FIELD_SIZE + 5];
	int			param_number;
	Int2		param_ctype,
				param_sqltype;
	char	   *old_statement = stmt->statement;
	char	   *new_statement = stmt->stmt_with_params;
	SIMPLE_TIME st;
	time_t		t = time(NULL);
	struct tm  *tim;
	SDWORD		used;
	char	   *buffer,
			   *buf;
	char		in_quote = FALSE;
	Oid			lobj_oid;
	int			lobj_fd,
				retval;


	if (!old_statement)
	{
B
Byron Nikolaidis 已提交
727
		SC_log_error(func, "No statement string", stmt);
728
		return SQL_ERROR;
B
Byron Nikolaidis 已提交
729
	}
730

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

B
Bruce Momjian 已提交
733
	/* Initialize current date */
734 735 736 737 738
	tim = localtime(&t);
	st.m = tim->tm_mon + 1;
	st.d = tim->tm_mday;
	st.y = tim->tm_year + 1900;

B
Bruce Momjian 已提交
739 740
	/* If the application hasn't set a cursor name, then generate one */
	if (stmt->cursor_name[0] == '\0')
741
		sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
742

B
Bruce Momjian 已提交
743 744 745
	/* For selects, prepend a declare cursor to the statement */
	if (stmt->statement_type == STMT_TYPE_SELECT && globals.use_declarefetch)
	{
746
		sprintf(new_statement, "declare %s cursor for ", stmt->cursor_name);
747 748
		npos = strlen(new_statement);
	}
B
Bruce Momjian 已提交
749 750
	else
	{
751 752 753 754
		new_statement[0] = '0';
		npos = 0;
	}

B
Bruce Momjian 已提交
755
	param_number = -1;
756

757
	oldstmtlen = strlen(old_statement);
H
Hiroshi Inoue 已提交
758
#ifdef MULTIBYTE
B
Bruce Momjian 已提交
759
	multibyte_init();
H
Hiroshi Inoue 已提交
760
#endif
761

B
Bruce Momjian 已提交
762 763 764 765 766
	for (opos = 0; opos < oldstmtlen; opos++)
	{
		/* Squeeze carriage-return/linefeed pairs to linefeed only */
		if (old_statement[opos] == '\r' && opos + 1 < oldstmtlen &&
			old_statement[opos + 1] == '\n')
767 768
			continue;

B
Bruce Momjian 已提交
769 770 771 772
		/*
		 * Handle literals (date, time, timestamp) and ODBC scalar
		 * functions
		 */
H
Hiroshi Inoue 已提交
773
#ifdef MULTIBYTE
B
Bruce Momjian 已提交
774 775
		else if (multibyte_char_check(old_statement[opos]) == 0 && old_statement[opos] == '{')
		{
H
Hiroshi Inoue 已提交
776
#else
B
Bruce Momjian 已提交
777 778
		else if (old_statement[opos] == '{')
		{
H
Hiroshi Inoue 已提交
779
#endif
B
Bruce Momjian 已提交
780 781 782
			char	   *esc;
			char	   *begin = &old_statement[opos + 1];

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

H
Hiroshi Inoue 已提交
786
#else
B
Bruce Momjian 已提交
787
			char	   *end = strchr(begin, '}');
788

H
Hiroshi Inoue 已提交
789
#endif
790

B
Bruce Momjian 已提交
791
			if (!end)
792 793 794 795 796
				continue;

			*end = '\0';

			esc = convert_escape(begin);
B
Bruce Momjian 已提交
797 798
			if (esc)
			{
799 800 801
				memcpy(&new_statement[npos], esc, strlen(esc));
				npos += strlen(esc);
			}
B
Bruce Momjian 已提交
802 803 804
			else
			{					/* it's not a valid literal so just copy */
				*end = '}';
805 806 807
				new_statement[npos++] = old_statement[opos];
				continue;
			}
808

809
			opos += end - begin + 1;
810 811 812
			*end = '}';
			continue;
		}
813

B
Bruce Momjian 已提交
814 815 816 817 818
		/*
		 * 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.
		 */
819
		else if (old_statement[opos] == '?' && !in_quote)
B
Bruce Momjian 已提交
820 821 822
			;					/* ok */
		else
		{
823 824 825
			if (old_statement[opos] == '\'')
				in_quote = (in_quote ? FALSE : TRUE);

826 827 828 829
			new_statement[npos++] = old_statement[opos];
			continue;
		}

830 831 832
		/*
		 * Its a '?' parameter alright
		 */
833 834
		param_number++;

B
Bruce Momjian 已提交
835
		if (param_number >= stmt->parameters_allocated)
836 837 838 839 840 841 842 843 844 845 846 847 848 849
		{
			if (stmt->pre_executing)
			{
				strcpy(&new_statement[npos], "NULL");
				npos += 4;
				stmt->inaccurate_result = TRUE;
				continue;
			}
			else
			{
				new_statement[npos++] = '?';
				continue;
			}
		}
850

B
Bruce Momjian 已提交
851 852 853
		/* Assign correct buffers based on data at exec param or not */
		if (stmt->parameters[param_number].data_at_exec)
		{
854 855 856
			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 已提交
857 858
		else
		{
859 860 861 862
			used = stmt->parameters[param_number].used ? *stmt->parameters[param_number].used : SQL_NTS;
			buffer = stmt->parameters[param_number].buffer;
		}

B
Bruce Momjian 已提交
863 864 865
		/* Handle NULL parameter data */
		if (used == SQL_NULL_DATA)
		{
866 867 868 869 870
			strcpy(&new_statement[npos], "NULL");
			npos += 4;
			continue;
		}

B
Bruce Momjian 已提交
871 872 873 874 875 876
		/*
		 * If no buffer, and it's not null, then what the hell is it? Just
		 * leave it alone then.
		 */
		if (!buffer)
		{
877 878 879 880 881 882 883 884 885 886 887 888
			if (stmt->pre_executing)
			{
				strcpy(&new_statement[npos], "NULL");
				npos += 4;
				stmt->inaccurate_result = TRUE;
				continue;
			}
			else
			{
				new_statement[npos++] = '?';
				continue;
			}
889
		}
890 891 892

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

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

B
Bruce Momjian 已提交
896
		/* replace DEFAULT with something we can use */
B
Bruce Momjian 已提交
897
		if (param_ctype == SQL_C_DEFAULT)
898 899 900 901 902 903
			param_ctype = sqltype_to_default_ctype(param_sqltype);

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

B
Bruce Momjian 已提交
904 905 906 907 908 909 910
		/* Convert input C type to a neutral format */
		switch (param_ctype)
		{
			case SQL_C_BINARY:
			case SQL_C_CHAR:
				buf = buffer;
				break;
911

B
Bruce Momjian 已提交
912
			case SQL_C_DOUBLE:
913
				sprintf(param_string, "%.15g",
B
Bruce Momjian 已提交
914 915
						*((SDOUBLE *) buffer));
				break;
916

B
Bruce Momjian 已提交
917
			case SQL_C_FLOAT:
918
				sprintf(param_string, "%.6g",
B
Bruce Momjian 已提交
919 920
						*((SFLOAT *) buffer));
				break;
921

B
Bruce Momjian 已提交
922 923 924 925 926
			case SQL_C_SLONG:
			case SQL_C_LONG:
				sprintf(param_string, "%ld",
						*((SDWORD *) buffer));
				break;
927

B
Bruce Momjian 已提交
928 929 930 931 932
			case SQL_C_SSHORT:
			case SQL_C_SHORT:
				sprintf(param_string, "%d",
						*((SWORD *) buffer));
				break;
933

B
Bruce Momjian 已提交
934 935 936 937 938
			case SQL_C_STINYINT:
			case SQL_C_TINYINT:
				sprintf(param_string, "%d",
						*((SCHAR *) buffer));
				break;
939

B
Bruce Momjian 已提交
940 941 942 943
			case SQL_C_ULONG:
				sprintf(param_string, "%lu",
						*((UDWORD *) buffer));
				break;
944

B
Bruce Momjian 已提交
945 946 947 948
			case SQL_C_USHORT:
				sprintf(param_string, "%u",
						*((UWORD *) buffer));
				break;
949

B
Bruce Momjian 已提交
950 951 952 953
			case SQL_C_UTINYINT:
				sprintf(param_string, "%u",
						*((UCHAR *) buffer));
				break;
954

B
Bruce Momjian 已提交
955 956 957
			case SQL_C_BIT:
				{
					int			i = *((UCHAR *) buffer);
958

B
Bruce Momjian 已提交
959 960 961
					sprintf(param_string, "%d", i ? 1 : 0);
					break;
				}
962

B
Bruce Momjian 已提交
963 964 965
			case SQL_C_DATE:
				{
					DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
966

B
Bruce Momjian 已提交
967 968 969
					st.m = ds->month;
					st.d = ds->day;
					st.y = ds->year;
970

B
Bruce Momjian 已提交
971 972
					break;
				}
973

B
Bruce Momjian 已提交
974 975 976
			case SQL_C_TIME:
				{
					TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
977

B
Bruce Momjian 已提交
978 979 980
					st.hh = ts->hour;
					st.mm = ts->minute;
					st.ss = ts->second;
981

B
Bruce Momjian 已提交
982 983
					break;
				}
984

B
Bruce Momjian 已提交
985 986 987
			case SQL_C_TIMESTAMP:
				{
					TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
988

B
Bruce Momjian 已提交
989 990 991 992 993 994
					st.m = tss->month;
					st.d = tss->day;
					st.y = tss->year;
					st.hh = tss->hour;
					st.mm = tss->minute;
					st.ss = tss->second;
995

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

B
Bruce Momjian 已提交
998
					break;
999

B
Bruce Momjian 已提交
1000 1001 1002 1003 1004 1005 1006 1007 1008
				}
			default:
				/* error */
				stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
				stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
				new_statement[npos] = '\0';		/* just in case */
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
		}
1009

B
Bruce Momjian 已提交
1010 1011 1012 1013
		/*
		 * Now that the input data is in a neutral format, convert it to
		 * the desired output format (sqltype)
		 */
1014

B
Bruce Momjian 已提交
1015 1016 1017 1018 1019
		switch (param_sqltype)
		{
			case SQL_CHAR:
			case SQL_VARCHAR:
			case SQL_LONGVARCHAR:
1020

B
Bruce Momjian 已提交
1021
				new_statement[npos++] = '\'';	/* Open Quote */
1022

B
Bruce Momjian 已提交
1023 1024 1025 1026 1027 1028
				/* it was a SQL_C_CHAR */
				if (buf)
				{
					convert_special_chars(buf, &new_statement[npos], used);
					npos += strlen(&new_statement[npos]);
				}
1029

B
Bruce Momjian 已提交
1030 1031 1032 1033 1034 1035
				/* it was a numeric type */
				else if (param_string[0] != '\0')
				{
					strcpy(&new_statement[npos], param_string);
					npos += strlen(param_string);
				}
1036

B
Bruce Momjian 已提交
1037 1038 1039 1040 1041
				/* 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);
1042

B
Bruce Momjian 已提交
1043 1044 1045
					strcpy(&new_statement[npos], tmp);
					npos += strlen(tmp);
				}
1046

B
Bruce Momjian 已提交
1047
				new_statement[npos++] = '\'';	/* Close Quote */
1048

B
Bruce Momjian 已提交
1049
				break;
1050

B
Bruce Momjian 已提交
1051 1052 1053 1054 1055 1056
			case SQL_DATE:
				if (buf)
				{				/* copy char data to time */
					my_strcpy(cbuf, sizeof(cbuf), buf, used);
					parse_datetime(cbuf, &st);
				}
1057

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

B
Bruce Momjian 已提交
1060 1061 1062
				strcpy(&new_statement[npos], tmp);
				npos += strlen(tmp);
				break;
1063

B
Bruce Momjian 已提交
1064 1065 1066 1067 1068 1069
			case SQL_TIME:
				if (buf)
				{				/* copy char data to time */
					my_strcpy(cbuf, sizeof(cbuf), buf, used);
					parse_datetime(cbuf, &st);
				}
1070

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

B
Bruce Momjian 已提交
1073 1074 1075
				strcpy(&new_statement[npos], tmp);
				npos += strlen(tmp);
				break;
1076

B
Bruce Momjian 已提交
1077
			case SQL_TIMESTAMP:
1078

B
Bruce Momjian 已提交
1079 1080 1081 1082 1083
				if (buf)
				{
					my_strcpy(cbuf, sizeof(cbuf), buf, used);
					parse_datetime(cbuf, &st);
				}
1084

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

B
Bruce Momjian 已提交
1088 1089
				strcpy(&new_statement[npos], tmp);
				npos += strlen(tmp);
1090

B
Bruce Momjian 已提交
1091
				break;
1092

B
Bruce Momjian 已提交
1093 1094 1095 1096
			case SQL_BINARY:
			case SQL_VARBINARY:/* non-ascii characters should be
								 * converted to octal */
				new_statement[npos++] = '\'';	/* Open Quote */
1097

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

B
Bruce Momjian 已提交
1100
				npos += convert_to_pgbinary(buf, &new_statement[npos], used);
1101

B
Bruce Momjian 已提交
1102
				new_statement[npos++] = '\'';	/* Close Quote */
B
Byron Nikolaidis 已提交
1103

B
Bruce Momjian 已提交
1104
				break;
1105

B
Bruce Momjian 已提交
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
			case SQL_LONGVARBINARY:

				if (stmt->parameters[param_number].data_at_exec)
					lobj_oid = stmt->parameters[param_number].lobj_oid;
				else
				{
					/* begin transaction if needed */
					if (!CC_is_in_trans(stmt->hdbc))
					{
						QResultClass *res;
						char		ok;

						res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
						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;
						}
1135

B
Bruce Momjian 已提交
1136 1137
						CC_set_in_trans(stmt->hdbc);
					}
B
Byron Nikolaidis 已提交
1138

B
Bruce Momjian 已提交
1139 1140 1141 1142
					/* store the oid */
					lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
					if (lobj_oid == 0)
					{
B
Byron Nikolaidis 已提交
1143
						stmt->errornumber = STMT_EXEC_ERROR;
B
Bruce Momjian 已提交
1144
						stmt->errormsg = "Couldnt create (in-line) large object.";
B
Byron Nikolaidis 已提交
1145 1146 1147
						SC_log_error(func, "", stmt);
						return SQL_ERROR;
					}
B
Bruce Momjian 已提交
1148 1149 1150 1151 1152

					/* store the fd */
					lobj_fd = lo_open(stmt->hdbc, lobj_oid, INV_WRITE);
					if (lobj_fd < 0)
					{
B
Byron Nikolaidis 已提交
1153
						stmt->errornumber = STMT_EXEC_ERROR;
B
Bruce Momjian 已提交
1154
						stmt->errormsg = "Couldnt open (in-line) large object for writing.";
B
Byron Nikolaidis 已提交
1155 1156 1157 1158
						SC_log_error(func, "", stmt);
						return SQL_ERROR;
					}

B
Bruce Momjian 已提交
1159
					retval = lo_write(stmt->hdbc, lobj_fd, buffer, used);
1160

B
Bruce Momjian 已提交
1161
					lo_close(stmt->hdbc, lobj_fd);
1162

B
Bruce Momjian 已提交
1163 1164 1165 1166 1167
					/* commit transaction if needed */
					if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
					{
						QResultClass *res;
						char		ok;
1168

B
Bruce Momjian 已提交
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
						res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
						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;
						}
1186

B
Bruce Momjian 已提交
1187 1188 1189
						CC_set_no_trans(stmt->hdbc);
					}
				}
1190

B
Bruce Momjian 已提交
1191 1192 1193 1194 1195 1196
				/*
				 * 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);
1197 1198 1199
				strcpy(&new_statement[npos], param_string);
				npos += strlen(param_string);

B
Bruce Momjian 已提交
1200 1201 1202 1203 1204 1205 1206
				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) */
1207

B
Bruce Momjian 已提交
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 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
			case SQL_REAL:
				if (buf)
					my_strcpy(param_string, sizeof(param_string), buf, used);
				sprintf(tmp, "'%s'::float4", param_string);
				strcpy(&new_statement[npos], tmp);
				npos += strlen(tmp);
				break;
			case SQL_FLOAT:
			case SQL_DOUBLE:
				if (buf)
					my_strcpy(param_string, sizeof(param_string), buf, used);
				sprintf(tmp, "'%s'::float8", param_string);
				strcpy(&new_statement[npos], tmp);
				npos += strlen(tmp);
				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);
				my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos - 1, cbuf, strlen(cbuf));
				npos += strlen(&new_statement[npos]);
				break;
			default:			/* a numeric type or SQL_BIT */
				if (param_sqltype == SQL_BIT)
					new_statement[npos++] = '\'';		/* Open Quote */

				if (buf)
				{
					my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos, buf, used);
					npos += strlen(&new_statement[npos]);
				}
				else
				{
					strcpy(&new_statement[npos], param_string);
					npos += strlen(param_string);
				}

				if (param_sqltype == SQL_BIT)
					new_statement[npos++] = '\'';		/* Close Quote */

				break;
1256
		}
B
Bruce Momjian 已提交
1257
	}							/* end, for */
1258

B
Bruce Momjian 已提交
1259
	/* make sure new_statement is always null-terminated */
1260 1261
	new_statement[npos] = '\0';

B
Bruce Momjian 已提交
1262 1263 1264 1265 1266 1267 1268 1269 1270
	if (stmt->hdbc->DriverToDataSource != NULL)
	{
		int			length = strlen(new_statement);

		stmt->hdbc->DriverToDataSource(stmt->hdbc->translation_option,
									   SQL_CHAR,
									   new_statement, length,
									   new_statement, length, NULL,
									   NULL, 0, NULL);
B
Byron Nikolaidis 已提交
1271 1272
	}

1273 1274 1275
	return SQL_SUCCESS;
}

1276

1277 1278 1279
char *
mapFunction(char *func)
{
B
Bruce Momjian 已提交
1280
	int			i;
1281 1282

	for (i = 0; mapFuncs[i][0]; i++)
B
Bruce Momjian 已提交
1283
		if (!stricmp(mapFuncs[i][0], func))
1284 1285 1286 1287
			return mapFuncs[i][1];

	return NULL;
}
1288

1289 1290 1291 1292

/*
 * convert_escape()
 *
1293 1294
 * This function returns a pointer to static memory!
 */
1295 1296 1297
char *
convert_escape(char *value)
{
B
Bruce Momjian 已提交
1298 1299
	static char escape[1024];
	char		key[33];
1300

1301
	/* Separate off the key, skipping leading and trailing whitespace */
B
Bruce Momjian 已提交
1302 1303
	while ((*value != '\0') && isspace((unsigned char) *value))
		value++;
1304
	sscanf(value, "%32s", key);
B
Bruce Momjian 已提交
1305 1306 1307 1308
	while ((*value != '\0') && (!isspace((unsigned char) *value)))
		value++;
	while ((*value != '\0') && isspace((unsigned char) *value))
		value++;
1309

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

B
Bruce Momjian 已提交
1312 1313
	if ((strcmp(key, "d") == 0) ||
		(strcmp(key, "t") == 0) ||
1314 1315
		(strcmp(key, "oj") == 0) ||		/* {oj syntax support for 7.1
										 * servers */
B
Bruce Momjian 已提交
1316 1317
		(strcmp(key, "ts") == 0))
	{
1318
		/* Literal; return the escape part as-is */
B
Bruce Momjian 已提交
1319
		strncpy(escape, value, sizeof(escape) - 1);
1320
	}
B
Bruce Momjian 已提交
1321 1322
	else if (strcmp(key, "fn") == 0)
	{
1323

B
Bruce Momjian 已提交
1324 1325 1326
		/*
		 * Function invocation Separate off the func name, skipping
		 * trailing whitespace.
1327
		 */
B
Bruce Momjian 已提交
1328 1329 1330
		char	   *funcEnd = value;
		char		svchar;
		char	   *mapFunc;
1331 1332

		while ((*funcEnd != '\0') && (*funcEnd != '(') &&
B
Bruce Momjian 已提交
1333
			   (!isspace((unsigned char) *funcEnd)))
1334
			funcEnd++;
1335 1336 1337 1338
		svchar = *funcEnd;
		*funcEnd = '\0';
		sscanf(value, "%32s", key);
		*funcEnd = svchar;
1339 1340
		while ((*funcEnd != '\0') && isspace((unsigned char) *funcEnd))
			funcEnd++;
1341

B
Bruce Momjian 已提交
1342 1343 1344
		/*
		 * We expect left parenthesis here, else return fn body as-is
		 * since it is one of those "function constants".
1345
		 */
B
Bruce Momjian 已提交
1346 1347 1348
		if (*funcEnd != '(')
		{
			strncpy(escape, value, sizeof(escape) - 1);
1349
			return escape;
1350
		}
1351
		mapFunc = mapFunction(key);
B
Bruce Momjian 已提交
1352 1353 1354 1355

		/*
		 * We could have mapFunction() return key if not in table... -
		 * thomas 2000-04-03
1356
		 */
B
Bruce Momjian 已提交
1357 1358
		if (mapFunc == NULL)
		{
1359
			/* If unrecognized function name, return fn body as-is */
B
Bruce Momjian 已提交
1360
			strncpy(escape, value, sizeof(escape) - 1);
1361 1362 1363 1364
			return escape;
		}
		/* copy mapped name and remaining input string */
		strcpy(escape, mapFunc);
B
Bruce Momjian 已提交
1365
		strncat(escape, funcEnd, sizeof(escape) - 1 - strlen(mapFunc));
1366
	}
B
Bruce Momjian 已提交
1367 1368
	else
	{
1369
		/* Bogus key, leave untranslated */
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
		return NULL;
	}

	return escape;
}


char *
convert_money(char *s)
{
B
Bruce Momjian 已提交
1380 1381
	size_t		i = 0,
				out = 0;
1382

B
Bruce Momjian 已提交
1383 1384
	for (i = 0; i < strlen(s); i++)
	{
1385
		if (s[i] == '$' || s[i] == ',' || s[i] == ')')
B
Bruce Momjian 已提交
1386
			;					/* skip these characters */
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
		else if (s[i] == '(')
			s[out++] = '-';
		else
			s[out++] = s[i];
	}
	s[out] = '\0';
	return s;
}


1397 1398 1399 1400
/*
 *	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
 */
1401
char
B
Bruce Momjian 已提交
1402
parse_datetime(char *buf, SIMPLE_TIME *st)
1403
{
B
Bruce Momjian 已提交
1404 1405 1406 1407 1408 1409 1410 1411
	int			y,
				m,
				d,
				hh,
				mm,
				ss;
	int			nf;

1412 1413
	y = m = d = hh = mm = ss = 0;

B
Bruce Momjian 已提交
1414 1415
	if (buf[4] == '-')			/* year first */
		nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh, &mm, &ss);
1416
	else
B
Bruce Momjian 已提交
1417
		nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh, &mm, &ss);
1418

B
Bruce Momjian 已提交
1419 1420
	if (nf == 5 || nf == 6)
	{
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
		st->y = y;
		st->m = m;
		st->d = d;
		st->hh = hh;
		st->mm = mm;
		st->ss = ss;

		return TRUE;
	}

B
Bruce Momjian 已提交
1431
	if (buf[4] == '-')			/* year first */
1432 1433 1434 1435
		nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
	else
		nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);

B
Bruce Momjian 已提交
1436 1437
	if (nf == 3)
	{
1438 1439 1440 1441 1442 1443 1444 1445
		st->y = y;
		st->m = m;
		st->d = d;

		return TRUE;
	}

	nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
B
Bruce Momjian 已提交
1446 1447
	if (nf == 2 || nf == 3)
	{
1448 1449 1450 1451 1452 1453 1454 1455 1456
		st->hh = hh;
		st->mm = mm;
		st->ss = ss;

		return TRUE;
	}

	return FALSE;
}
1457

1458

1459
/*	Change linefeed to carriage-return/linefeed */
1460
int
1461 1462
convert_linefeeds(char *si, char *dst, size_t max)
{
B
Bruce Momjian 已提交
1463 1464
	size_t		i = 0,
				out = 0;
1465

B
Bruce Momjian 已提交
1466 1467 1468 1469 1470 1471 1472
	for (i = 0; i < strlen(si) && out < max - 1; i++)
	{
		if (si[i] == '\n')
		{
			/* Only add the carriage-return if needed */
			if (i > 0 && si[i - 1] == '\r')
			{
1473
				dst[out++] = si[i];
B
Byron Nikolaidis 已提交
1474 1475 1476
				continue;
			}

1477 1478
			dst[out++] = '\r';
			dst[out++] = '\n';
1479 1480
		}
		else
1481
			dst[out++] = si[i];
1482
	}
1483 1484
	dst[out] = '\0';
	return out;
1485 1486
}

1487 1488 1489 1490 1491

/*
 *	Change carriage-return/linefeed to just linefeed
 *	Plus, escape any special characters.
 */
1492 1493 1494
char *
convert_special_chars(char *si, char *dst, int used)
{
B
Bruce Momjian 已提交
1495 1496 1497 1498 1499
	size_t		i = 0,
				out = 0,
				max;
	static char sout[TEXT_FIELD_SIZE + 5];
	char	   *p;
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511

	if (dst)
		p = dst;
	else
		p = sout;

	p[0] = '\0';

	if (used == SQL_NTS)
		max = strlen(si);
	else
		max = used;
H
Hiroshi Inoue 已提交
1512 1513 1514
#ifdef MULTIBYTE
	multibyte_init();
#endif
1515

B
Bruce Momjian 已提交
1516 1517 1518
	for (i = 0; i < max; i++)
	{
		if (si[i] == '\r' && i + 1 < strlen(si) && si[i + 1] == '\n')
1519
			continue;
H
Hiroshi Inoue 已提交
1520 1521 1522
#ifdef MULTIBYTE
		else if (multibyte_char_check(si[i]) == 0 && (si[i] == '\'' || si[i] == '\\'))
#else
B
Byron Nikolaidis 已提交
1523
		else if (si[i] == '\'' || si[i] == '\\')
H
Hiroshi Inoue 已提交
1524
#endif
1525 1526 1527 1528 1529 1530 1531 1532
			p[out++] = '\\';

		p[out++] = si[i];
	}
	p[out] = '\0';
	return p;
}

1533

1534 1535 1536 1537
/*	!!! Need to implement this function !!!  */
int
convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax)
{
1538 1539 1540
	mylog("convert_pgbinary_to_char: value = '%s'\n", value);

	strncpy_null(rgbValue, value, cbValueMax);
1541 1542 1543
	return 0;
}

1544

1545 1546 1547
unsigned int
conv_from_octal(unsigned char *s)
{
B
Bruce Momjian 已提交
1548 1549
	int			i,
				y = 0;
1550

B
Bruce Momjian 已提交
1551 1552
	for (i = 1; i <= 3; i++)
		y += (s[i] - 48) * (int) pow(8, 3 - i);
1553 1554

	return y;
1555

1556 1557
}

1558

B
Byron Nikolaidis 已提交
1559 1560 1561
unsigned int
conv_from_hex(unsigned char *s)
{
B
Bruce Momjian 已提交
1562 1563 1564
	int			i,
				y = 0,
				val;
1565

B
Bruce Momjian 已提交
1566 1567 1568 1569 1570 1571 1572 1573
	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 已提交
1574

B
Bruce Momjian 已提交
1575
		y += val * (int) pow(16, 2 - i);
B
Byron Nikolaidis 已提交
1576 1577 1578 1579 1580
	}

	return y;
}

1581

B
Bruce Momjian 已提交
1582
/*	convert octal escapes to bytes */
1583 1584 1585
int
convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax)
{
B
Bruce Momjian 已提交
1586 1587
	size_t		i;
	int			o = 0;
1588

B
Bruce Momjian 已提交
1589 1590 1591 1592 1593

	for (i = 0; i < strlen(value);)
	{
		if (value[i] == '\\')
		{
1594 1595 1596
			rgbValue[o] = conv_from_octal(&value[i]);
			i += 4;
		}
B
Bruce Momjian 已提交
1597
		else
1598 1599 1600 1601
			rgbValue[o] = value[i++];
		mylog("convert_from_pgbinary: i=%d, rgbValue[%d] = %d, %c\n", i, o, rgbValue[o], rgbValue[o]);
		o++;
	}
1602

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

1605 1606 1607 1608 1609 1610 1611
	return o;
}


char *
conv_to_octal(unsigned char val)
{
B
Bruce Momjian 已提交
1612 1613
	int			i;
	static char x[6];
1614 1615 1616 1617 1618

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

B
Bruce Momjian 已提交
1619 1620
	for (i = 4; i > 1; i--)
	{
1621 1622 1623 1624 1625 1626 1627
		x[i] = (val & 7) + 48;
		val >>= 3;
	}

	return x;
}

1628

B
Bruce Momjian 已提交
1629
/*	convert non-ascii bytes to octal escape sequences */
1630 1631 1632
int
convert_to_pgbinary(unsigned char *in, char *out, int len)
{
B
Bruce Momjian 已提交
1633 1634
	int			i,
				o = 0;
1635

B
Bruce Momjian 已提交
1636 1637
	for (i = 0; i < len; i++)
	{
1638
		mylog("convert_to_pgbinary: in[%d] = %d, %c\n", i, in[i], in[i]);
B
Bruce Momjian 已提交
1639
		if (isalnum(in[i]) || in[i] == ' ')
1640
			out[o++] = in[i];
B
Bruce Momjian 已提交
1641 1642 1643
		else
		{
			strcpy(&out[o], conv_to_octal(in[i]));
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
			o += 5;
		}
	}

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

	return o;
}


B
Byron Nikolaidis 已提交
1654 1655 1656
void
encode(char *in, char *out)
{
B
Bruce Momjian 已提交
1657 1658
	unsigned int i,
				o = 0;
B
Byron Nikolaidis 已提交
1659

B
Bruce Momjian 已提交
1660 1661 1662 1663
	for (i = 0; i < strlen(in); i++)
	{
		if (in[i] == '+')
		{
B
Byron Nikolaidis 已提交
1664 1665 1666
			sprintf(&out[o], "%%2B");
			o += 3;
		}
B
Bruce Momjian 已提交
1667
		else if (isspace((unsigned char) in[i]))
B
Byron Nikolaidis 已提交
1668
			out[o++] = '+';
B
Bruce Momjian 已提交
1669 1670
		else if (!isalnum((unsigned char) in[i]))
		{
1671
			sprintf(&out[o], "%%%02x", (unsigned char) in[i]);
B
Byron Nikolaidis 已提交
1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
			o += 3;
		}
		else
			out[o++] = in[i];
	}
	out[o++] = '\0';
}


void
decode(char *in, char *out)
{
B
Bruce Momjian 已提交
1684 1685
	unsigned int i,
				o = 0;
B
Byron Nikolaidis 已提交
1686

B
Bruce Momjian 已提交
1687 1688
	for (i = 0; i < strlen(in); i++)
	{
B
Byron Nikolaidis 已提交
1689 1690
		if (in[i] == '+')
			out[o++] = ' ';
B
Bruce Momjian 已提交
1691 1692
		else if (in[i] == '%')
		{
B
Byron Nikolaidis 已提交
1693
			sprintf(&out[o++], "%c", conv_from_hex(&in[i]));
B
Bruce Momjian 已提交
1694
			i += 2;
B
Byron Nikolaidis 已提交
1695 1696 1697 1698 1699 1700 1701 1702
		}
		else
			out[o++] = in[i];
	}
	out[o++] = '\0';
}


1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
/*-------
 *	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.
 *-------
 */
1719
int
B
Bruce Momjian 已提交
1720
convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue,
B
Bruce Momjian 已提交
1721
		   SDWORD cbValueMax, SDWORD *pcbValue)
1722
{
B
Bruce Momjian 已提交
1723 1724 1725 1726
	Oid			oid;
	int			retval,
				result,
				left = -1;
T
Tom Lane 已提交
1727
	BindInfoClass *bindInfo = NULL;
1728 1729


1730
	/* If using SQLGetData, then current_col will be set */
B
Bruce Momjian 已提交
1731 1732
	if (stmt->current_col >= 0)
	{
1733 1734 1735
		bindInfo = &stmt->bindings[stmt->current_col];
		left = bindInfo->data_left;
	}
1736

B
Bruce Momjian 已提交
1737 1738 1739 1740
	/*
	 * if this is the first call for this column, open the large object
	 * for reading
	 */
1741

B
Bruce Momjian 已提交
1742 1743
	if (!bindInfo || bindInfo->data_left == -1)
	{
B
Byron Nikolaidis 已提交
1744
		/* begin transaction if needed */
B
Bruce Momjian 已提交
1745 1746
		if (!CC_is_in_trans(stmt->hdbc))
		{
B
Byron Nikolaidis 已提交
1747
			QResultClass *res;
B
Bruce Momjian 已提交
1748
			char		ok;
B
Byron Nikolaidis 已提交
1749 1750

			res = CC_send_query(stmt->hdbc, "BEGIN", NULL);
B
Bruce Momjian 已提交
1751 1752
			if (!res)
			{
B
Byron Nikolaidis 已提交
1753 1754 1755 1756 1757 1758
				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 已提交
1759 1760
			if (!ok)
			{
B
Byron Nikolaidis 已提交
1761 1762 1763 1764 1765 1766 1767 1768
				stmt->errormsg = "Could not begin (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}

			CC_set_in_trans(stmt->hdbc);
		}

1769 1770
		oid = atoi(value);
		stmt->lobj_fd = lo_open(stmt->hdbc, oid, INV_READ);
B
Bruce Momjian 已提交
1771 1772
		if (stmt->lobj_fd < 0)
		{
1773
			stmt->errornumber = STMT_EXEC_ERROR;
1774
			stmt->errormsg = "Couldnt open large object for reading.";
1775 1776
			return COPY_GENERAL_ERROR;
		}
1777

B
Bruce Momjian 已提交
1778
		/* Get the size */
1779
		retval = lo_lseek(stmt->hdbc, stmt->lobj_fd, 0L, SEEK_END);
B
Bruce Momjian 已提交
1780 1781
		if (retval >= 0)
		{
1782 1783 1784 1785
			left = lo_tell(stmt->hdbc, stmt->lobj_fd);
			if (bindInfo)
				bindInfo->data_left = left;

B
Bruce Momjian 已提交
1786
			/* return to beginning */
1787 1788 1789 1790
			lo_lseek(stmt->hdbc, stmt->lobj_fd, 0L, SEEK_SET);
		}
	}

B
Bruce Momjian 已提交
1791
	if (left == 0)
1792
		return COPY_NO_DATA_FOUND;
1793

B
Bruce Momjian 已提交
1794 1795
	if (stmt->lobj_fd < 0)
	{
1796 1797 1798 1799
		stmt->errornumber = STMT_EXEC_ERROR;
		stmt->errormsg = "Large object FD undefined for multiple read.";
		return COPY_GENERAL_ERROR;
	}
1800

1801
	retval = lo_read(stmt->hdbc, stmt->lobj_fd, (char *) rgbValue, cbValueMax);
B
Bruce Momjian 已提交
1802 1803
	if (retval < 0)
	{
1804
		lo_close(stmt->hdbc, stmt->lobj_fd);
B
Byron Nikolaidis 已提交
1805 1806

		/* commit transaction if needed */
B
Bruce Momjian 已提交
1807 1808
		if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
		{
B
Byron Nikolaidis 已提交
1809
			QResultClass *res;
B
Bruce Momjian 已提交
1810
			char		ok;
B
Byron Nikolaidis 已提交
1811 1812

			res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
B
Bruce Momjian 已提交
1813 1814
			if (!res)
			{
B
Byron Nikolaidis 已提交
1815 1816 1817 1818 1819 1820
				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 已提交
1821 1822
			if (!ok)
			{
B
Byron Nikolaidis 已提交
1823 1824 1825 1826 1827 1828 1829 1830
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}

			CC_set_no_trans(stmt->hdbc);
		}

1831 1832 1833 1834 1835 1836 1837
		stmt->lobj_fd = -1;

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

1838 1839 1840 1841 1842 1843 1844
	if (retval < left)
		result = COPY_RESULT_TRUNCATED;
	else
		result = COPY_OK;

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

B
Bruce Momjian 已提交
1846
	if (bindInfo && bindInfo->data_left > 0)
1847
		bindInfo->data_left -= retval;
1848

B
Bruce Momjian 已提交
1849 1850
	if (!bindInfo || bindInfo->data_left == 0)
	{
1851
		lo_close(stmt->hdbc, stmt->lobj_fd);
B
Byron Nikolaidis 已提交
1852 1853

		/* commit transaction if needed */
B
Bruce Momjian 已提交
1854 1855
		if (!globals.use_declarefetch && CC_is_in_autocommit(stmt->hdbc))
		{
B
Byron Nikolaidis 已提交
1856
			QResultClass *res;
B
Bruce Momjian 已提交
1857
			char		ok;
B
Byron Nikolaidis 已提交
1858 1859

			res = CC_send_query(stmt->hdbc, "COMMIT", NULL);
B
Bruce Momjian 已提交
1860 1861
			if (!res)
			{
B
Byron Nikolaidis 已提交
1862 1863 1864 1865 1866 1867
				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 已提交
1868 1869
			if (!ok)
			{
B
Byron Nikolaidis 已提交
1870 1871 1872 1873 1874 1875 1876 1877
				stmt->errormsg = "Could not commit (in-line) a transaction";
				stmt->errornumber = STMT_EXEC_ERROR;
				return COPY_GENERAL_ERROR;
			}

			CC_set_no_trans(stmt->hdbc);
		}

B
Bruce Momjian 已提交
1878
		stmt->lobj_fd = -1;		/* prevent further reading */
1879
	}
1880 1881

	return result;
1882
}