statement.c 27.3 KB
Newer Older
1 2
/*-------
 * Module:			statement.c
3
 *
4 5
 * Description:		This module contains functions related to creating
 *					and manipulating a statement.
6
 *
7
 * Classes:			StatementClass (Functions prefix: "SC_")
8
 *
9
 * API functions:	SQLAllocStmt, SQLFreeStmt
10
 *
11
 * Comments:		See "notice.txt" for copyright and license information.
12
 *-------
13
 */
14 15 16 17 18 19 20

#include "statement.h"
#include "bind.h"
#include "connection.h"
#include "qresult.h"
#include "convert.h"
#include "environ.h"
21

22
#include <stdio.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
23
#include <string.h>
24
#include <ctype.h>
25

26
#ifndef WIN32
Byron Nikolaidis's avatar
Byron Nikolaidis committed
27 28 29
#include "iodbc.h"
#include "isql.h"
#else
30 31
#include <windows.h>
#include <sql.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
32
#endif
33
#include "pgapifunc.h"
34

35

36 37
#ifndef WIN32
#ifndef HAVE_STRICMP
38
#define stricmp(s1,s2)		strcasecmp(s1,s2)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
39 40 41
#define strnicmp(s1,s2,n)	strncasecmp(s1,s2,n)
#endif
#endif
42
#define PRN_NULLCHECK
Byron Nikolaidis's avatar
Byron Nikolaidis committed
43

44

45
/*	Map sql commands to statement types */
46 47 48 49 50 51 52 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
static struct
{
	int			type;
	char	   *s;
}			Statement_Type[] =

{
	{
		STMT_TYPE_SELECT, "SELECT"
	},
	{
		STMT_TYPE_INSERT, "INSERT"
	},
	{
		STMT_TYPE_UPDATE, "UPDATE"
	},
	{
		STMT_TYPE_DELETE, "DELETE"
	},
	{
		STMT_TYPE_CREATE, "CREATE"
	},
	{
		STMT_TYPE_ALTER, "ALTER"
	},
	{
		STMT_TYPE_DROP, "DROP"
	},
	{
		STMT_TYPE_GRANT, "GRANT"
	},
	{
		STMT_TYPE_REVOKE, "REVOKE"
	},
Hiroshi Inoue's avatar
Hiroshi Inoue committed
80 81 82
	{
		STMT_TYPE_PROCCALL, "{"
	},
83 84 85
	{
		0, NULL
	}
86 87
};

88

89
RETCODE SQL_API
90
PGAPI_AllocStmt(HDBC hdbc,
91
			 HSTMT FAR *phstmt)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
92
{
93
	static char *func = "PGAPI_AllocStmt";
94 95
	ConnectionClass *conn = (ConnectionClass *) hdbc;
	StatementClass *stmt;
96

97 98
	mylog("%s: entering...\n", func);

99 100
	if (!conn)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
101
		CC_log_error(func, "", NULL);
102
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
103
	}
104 105 106

	stmt = SC_Constructor();

107
	mylog("**** PGAPI_AllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt);
108

109 110
	if (!stmt)
	{
111 112 113
		conn->errornumber = CONN_STMT_ALLOC_ERROR;
		conn->errormsg = "No more memory to allocate a further SQL-statement";
		*phstmt = SQL_NULL_HSTMT;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
114
		CC_log_error(func, "", conn);
115 116 117
		return SQL_ERROR;
	}

118 119 120 121
	if (!CC_add_statement(conn, stmt))
	{
		conn->errormsg = "Maximum number of connections exceeded.";
		conn->errornumber = CONN_STMT_ALLOC_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
122
		CC_log_error(func, "", conn);
123
		SC_Destructor(stmt);
124
		*phstmt = SQL_NULL_HSTMT;
125 126
		return SQL_ERROR;
	}
127 128 129

	*phstmt = (HSTMT) stmt;

130
	/* Copy default statement options based from Connection options */
131 132
	stmt->options = conn->stmtOptions;

133
	stmt->stmt_size_limit = CC_get_max_query_len(conn);
134
	/* Save the handle for later */
135 136
	stmt->phstmt = phstmt;

137
	return SQL_SUCCESS;
138 139 140
}


141
RETCODE SQL_API
142
PGAPI_FreeStmt(HSTMT hstmt,
143
			UWORD fOption)
144
{
145
	static char *func = "PGAPI_FreeStmt";
146
	StatementClass *stmt = (StatementClass *) hstmt;
147

148
	mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption);
149

150 151
	if (!stmt)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
152
		SC_log_error(func, "", NULL);
153
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
154
	}
155
	SC_clear_error(stmt);
156

157 158
	if (fOption == SQL_DROP)
	{
159 160 161
		ConnectionClass *conn = stmt->hdbc;

		/* Remove the statement from the connection's statement list */
162 163 164 165
		if (conn)
		{
			if (!CC_remove_statement(conn, stmt))
			{
166 167
				stmt->errornumber = STMT_SEQUENCE_ERROR;
				stmt->errormsg = "Statement is currently executing a transaction.";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
168
				SC_log_error(func, "", stmt);
169 170
				return SQL_ERROR;		/* stmt may be executing a
										 * transaction */
171 172
			}

173 174 175
			/* Free any cursors and discard any result info */
			if (stmt->result)
			{
176 177 178 179 180 181 182
				QR_Destructor(stmt->result);
				stmt->result = NULL;
			}
		}

		/* Destroy the statement and free any results, cursors, etc. */
		SC_Destructor(stmt);
183 184
	}
	else if (fOption == SQL_UNBIND)
185
		SC_unbind_cols(stmt);
186 187
	else if (fOption == SQL_CLOSE)
	{
188

189 190 191 192
		/*
		 * this should discard all the results, but leave the statement
		 * itself in place (it can be executed again)
		 */
193 194 195
		if (!SC_recycle_statement(stmt))
		{
			/* errormsg passed in above */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
196
			SC_log_error(func, "", stmt);
197
			return SQL_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
198
		}
199 200
	}
	else if (fOption == SQL_RESET_PARAMS)
201
		SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
202 203
	else
	{
204
		stmt->errormsg = "Invalid option passed to PGAPI_FreeStmt.";
205
		stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
206
		SC_log_error(func, "", stmt);
207 208
		return SQL_ERROR;
	}
209

210
	return SQL_SUCCESS;
211 212 213
}


214
/*
215 216
 * StatementClass implementation
 */
217
void
Bruce Momjian's avatar
Bruce Momjian committed
218
InitializeStatementOptions(StatementOptions *opt)
219
{
220 221
	opt->maxRows = 0;			/* driver returns all rows */
	opt->maxLength = 0;			/* driver returns all data for char/binary */
222
	opt->rowset_size = 1;
223
	opt->keyset_size = 0;		/* fully keyset driven is the default */
224 225 226 227
	opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
	opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
	opt->bind_size = 0;			/* default is to bind by column */
	opt->retrieve_data = SQL_RD_ON;
228
	opt->use_bookmarks = SQL_UB_OFF;
229
}
230

231

232
StatementClass *
233
SC_Constructor(void)
234
{
235
	StatementClass *rv;
236 237

	rv = (StatementClass *) malloc(sizeof(StatementClass));
238 239 240
	if (rv)
	{
		rv->hdbc = NULL;		/* no connection associated yet */
241
		rv->phstmt = NULL;
242 243 244 245
		rv->result = NULL;
		rv->manual_result = FALSE;
		rv->prepare = FALSE;
		rv->status = STMT_ALLOCATED;
246 247
		rv->internal = FALSE;

248 249 250
		rv->errormsg = NULL;
		rv->errornumber = 0;
		rv->errormsg_created = FALSE;
251
		rv->errormsg_malloced = FALSE;
252

253
		rv->statement = NULL;
254 255
		rv->stmt_with_params = NULL;
		rv->stmt_size_limit = -1;
256
		rv->statement_type = STMT_TYPE_UNKNOWN;
257

258 259
		rv->bindings = NULL;
		rv->bindings_allocated = 0;
260

261 262 263
		rv->bookmark.buffer = NULL;
		rv->bookmark.used = NULL;

264 265
		rv->parameters_allocated = 0;
		rv->parameters = 0;
266

267
		rv->currTuple = -1;
268
		rv->rowset_start = -1;
269
		rv->current_col = -1;
270 271 272 273
		rv->bind_row = 0;
		rv->last_fetch_count = 0;
		rv->save_rowset_size = -1;

274 275 276
		rv->data_at_exec = -1;
		rv->current_exec_param = -1;
		rv->put_data = FALSE;
277

278 279
		rv->lobj_fd = -1;
		rv->cursor_name[0] = '\0';
Byron Nikolaidis's avatar
Byron Nikolaidis committed
280

281
		/* Parse Stuff */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
282 283 284 285 286
		rv->ti = NULL;
		rv->fi = NULL;
		rv->ntab = 0;
		rv->nfld = 0;
		rv->parse_status = STMT_PARSE_NONE;
287

288
		/* Clear Statement Options -- defaults will be set in AllocStmt */
289
		memset(&rv->options, 0, sizeof(StatementOptions));
290 291 292

		rv->pre_executing = FALSE;
		rv->inaccurate_result = FALSE;
293
		rv->miscinfo = 0;
294 295 296 297
	}
	return rv;
}

298

299
char
Bruce Momjian's avatar
Bruce Momjian committed
300
SC_Destructor(StatementClass *self)
301 302
{
	mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, self->result, self->hdbc);
303
	SC_clear_error(self);
304 305
	if (STMT_EXECUTING == self->status)
	{
306 307 308 309 310
		self->errornumber = STMT_SEQUENCE_ERROR;
		self->errormsg = "Statement is currently executing a transaction.";
		return FALSE;
	}

311 312 313 314
	if (self->result)
	{
		if (!self->hdbc)
			self->result->conn = NULL;	/* prevent any dbase activity */
315 316 317 318 319 320

		QR_Destructor(self->result);
	}

	if (self->statement)
		free(self->statement);
321 322 323 324 325
	if (self->stmt_with_params)
	{
		free(self->stmt_with_params);
		self->stmt_with_params = NULL;
	}
326 327 328

	SC_free_params(self, STMT_FREE_PARAMS_ALL);

329 330
	/*
	 * the memory pointed to by the bindings is not deallocated by the
331 332
	 * driver but by the application that uses that driver, so we don't
	 * have to care
333
	 */
334 335 336 337
	/* about that here. */
	if (self->bindings)
		free(self->bindings);

338 339 340 341 342 343
	/* Free the parsed table information */
	if (self->ti)
	{
		int			i;

		for (i = 0; i < self->ntab; i++)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
344 345 346 347 348
			free(self->ti[i]);

		free(self->ti);
	}

349 350 351 352 353 354
	/* Free the parsed field information */
	if (self->fi)
	{
		int			i;

		for (i = 0; i < self->nfld; i++)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
355 356 357 358
			free(self->fi[i]);
		free(self->fi);
	}

359 360
	free(self);

361 362
	mylog("SC_Destructor: EXIT\n");

363 364 365
	return TRUE;
}

366 367 368 369 370

/*
 *	Free parameters and free the memory from the
 *	data-at-execution parameters that was allocated in SQLPutData.
 */
371
void
Bruce Momjian's avatar
Bruce Momjian committed
372
SC_free_params(StatementClass *self, char option)
373
{
374
	int			i;
375 376 377

	mylog("SC_free_params:  ENTER, self=%d\n", self);

378
	if (!self->parameters)
379 380
		return;

381 382 383 384 385 386
	for (i = 0; i < self->parameters_allocated; i++)
	{
		if (self->parameters[i].data_at_exec == TRUE)
		{
			if (self->parameters[i].EXEC_used)
			{
387 388 389 390
				free(self->parameters[i].EXEC_used);
				self->parameters[i].EXEC_used = NULL;
			}

391 392
			if (self->parameters[i].EXEC_buffer)
			{
393 394
				if (self->parameters[i].SQLType != SQL_LONGVARBINARY)
					free(self->parameters[i].EXEC_buffer);
395 396 397 398 399 400 401 402
				self->parameters[i].EXEC_buffer = NULL;
			}
		}
	}
	self->data_at_exec = -1;
	self->current_exec_param = -1;
	self->put_data = FALSE;

403 404
	if (option == STMT_FREE_PARAMS_ALL)
	{
405 406 407 408
		free(self->parameters);
		self->parameters = NULL;
		self->parameters_allocated = 0;
	}
409

410 411
	mylog("SC_free_params:  EXIT\n");
}
412 413


414
int
415 416
statement_type(char *statement)
{
417
	int			i;
418

419 420 421 422
	/* ignore leading whitespace in query string */
	while (*statement && isspace((unsigned char) *statement))
		statement++;

423
	for (i = 0; Statement_Type[i].s; i++)
424
		if (!strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s)))
425 426 427
			return Statement_Type[i].type;

	return STMT_TYPE_OTHER;
428 429
}

Byron Nikolaidis's avatar
Byron Nikolaidis committed
430

431 432 433 434
/*
 *	Called from SQLPrepare if STMT_PREMATURE, or
 *	from SQLExecute if STMT_FINISHED, or
 *	from SQLFreeStmt(SQL_CLOSE)
435
 */
436
char
Bruce Momjian's avatar
Bruce Momjian committed
437
SC_recycle_statement(StatementClass *self)
438
{
439
	ConnectionClass *conn;
440

441
	mylog("recycle statement: self= %u\n", self);
442

443
	SC_clear_error(self);
444 445 446
	/* This would not happen */
	if (self->status == STMT_EXECUTING)
	{
447 448 449 450 451
		self->errornumber = STMT_SEQUENCE_ERROR;
		self->errormsg = "Statement is currently executing a transaction.";
		return FALSE;
	}

452 453 454 455 456
	switch (self->status)
	{
		case STMT_ALLOCATED:
			/* this statement does not need to be recycled */
			return TRUE;
457

458 459
		case STMT_READY:
			break;
460

461
		case STMT_PREMATURE:
462

463 464 465 466 467 468 469 470
			/*
			 * Premature execution of the statement might have caused the
			 * start of a transaction. If so, we have to rollback that
			 * transaction.
			 */
			conn = SC_get_conn(self);
			if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
			{
471 472
				if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature) 
					CC_abort(conn);
473 474 475 476 477 478 479 480 481 482
			}
			break;

		case STMT_FINISHED:
			break;

		default:
			self->errormsg = "An internal error occured while recycling statements";
			self->errornumber = STMT_INTERNAL_ERROR;
			return FALSE;
483
	}
484

485 486 487 488 489 490
	/* Free the parsed table information */
	if (self->ti)
	{
		int			i;

		for (i = 0; i < self->ntab; i++)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
491 492 493 494 495 496 497
			free(self->ti[i]);

		free(self->ti);
		self->ti = NULL;
		self->ntab = 0;
	}

498 499 500 501 502 503
	/* Free the parsed field information */
	if (self->fi)
	{
		int			i;

		for (i = 0; i < self->nfld; i++)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
504 505 506 507 508 509
			free(self->fi[i]);
		free(self->fi);
		self->fi = NULL;
		self->nfld = 0;
	}
	self->parse_status = STMT_PARSE_NONE;
510

511 512 513
	/* Free any cursors */
	if (self->result)
	{
514 515 516
		QR_Destructor(self->result);
		self->result = NULL;
	}
517
	self->inaccurate_result = FALSE;
518

519 520 521
	/*
	 * Reset only parameters that have anything to do with results
	 */
522
	self->status = STMT_READY;
523
	self->manual_result = FALSE;/* very important */
524

525
	self->currTuple = -1;
526
	self->rowset_start = -1;
527
	self->current_col = -1;
528 529
	self->bind_row = 0;
	self->last_fetch_count = 0;
530

531 532
	if (self->errormsg_malloced && self->errormsg)
		free(self->errormsg);
533 534 535
	self->errormsg = NULL;
	self->errornumber = 0;
	self->errormsg_created = FALSE;
536
	self->errormsg_malloced = FALSE;
537 538 539

	self->lobj_fd = -1;

540 541
	/*
	 * Free any data at exec params before the statement is executed
542 543
	 * again.  If not, then there will be a memory leak when the next
	 * SQLParamData/SQLPutData is called.
544
	 */
545
	SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
546 547 548 549

	return TRUE;
}

550

551
/* Pre-execute a statement (SQLPrepare/SQLDescribeCol) */
552
void
Bruce Momjian's avatar
Bruce Momjian committed
553
SC_pre_execute(StatementClass *self)
554 555 556
{
	mylog("SC_pre_execute: status = %d\n", self->status);

557 558
	if (self->status == STMT_READY)
	{
559 560
		mylog("              preprocess: status = READY\n");

561
		self->miscinfo = 0;
562 563
		if (self->statement_type == STMT_TYPE_SELECT)
		{
564 565
			char		old_pre_executing = self->pre_executing;

566 567 568
			self->pre_executing = TRUE;
			self->inaccurate_result = FALSE;

569
			PGAPI_Execute(self);
570

571 572 573 574 575 576 577 578
			self->pre_executing = old_pre_executing;

			if (self->status == STMT_FINISHED)
			{
				mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
				self->status = STMT_PREMATURE;
			}
		}
579
		if (!SC_is_pre_executable(self))
580
		{
581 582 583
			self->result = QR_Constructor();
			QR_set_status(self->result, PGRES_TUPLES_OK);
			self->inaccurate_result = TRUE;
584 585
			self->status = STMT_PREMATURE;
		}
586
	}
587 588
}

589

590
/* This is only called from SQLFreeStmt(SQL_UNBIND) */
591
char
Bruce Momjian's avatar
Bruce Momjian committed
592
SC_unbind_cols(StatementClass *self)
593
{
594
	Int2		lf;
595

596 597
	for (lf = 0; lf < self->bindings_allocated; lf++)
	{
598
		self->bindings[lf].data_left = -1;
599 600 601 602 603 604
		self->bindings[lf].buflen = 0;
		self->bindings[lf].buffer = NULL;
		self->bindings[lf].used = NULL;
		self->bindings[lf].returntype = SQL_C_CHAR;
	}

605 606 607
	self->bookmark.buffer = NULL;
	self->bookmark.used = NULL;

608
	return 1;
609 610
}

611

612
void
Bruce Momjian's avatar
Bruce Momjian committed
613
SC_clear_error(StatementClass *self)
614
{
615 616
	if (self->errormsg_malloced && self->errormsg)
		free(self->errormsg);
617 618 619
	self->errornumber = 0;
	self->errormsg = NULL;
	self->errormsg_created = FALSE;
620
	self->errormsg_malloced = FALSE;
621 622 623
}


624 625 626 627
/*
 *	This function creates an error msg which is the concatenation
 *	of the result, statement, connection, and socket messages.
 */
628
char *
Bruce Momjian's avatar
Bruce Momjian committed
629
SC_create_errormsg(StatementClass *self)
630
{
631 632 633 634
	QResultClass *res = self->result;
	ConnectionClass *conn = self->hdbc;
	int			pos;
	static char msg[4096];
635 636 637 638 639 640 641 642 643

	msg[0] = '\0';

	if (res && res->message)
		strcpy(msg, res->message);

	else if (self->errormsg)
		strcpy(msg, self->errormsg);

644 645
	if (conn)
	{
646 647
		SocketClass *sock = conn->sock;

648 649
		if (conn->errormsg && conn->errormsg[0] != '\0')
		{
650 651 652 653
			pos = strlen(msg);
			sprintf(&msg[pos], ";\n%s", conn->errormsg);
		}

654 655
		if (sock && sock->errormsg && sock->errormsg[0] != '\0')
		{
656 657 658 659
			pos = strlen(msg);
			sprintf(&msg[pos], ";\n%s", sock->errormsg);
		}
	}
660 661
	if (!msg[0] && res && QR_get_notice(res))
		return QR_get_notice(res);
662 663 664 665

	return msg;
}

666

667
char
Bruce Momjian's avatar
Bruce Momjian committed
668
SC_get_error(StatementClass *self, int *number, char **message)
669
{
670
	char		rv;
671

672
	/* Create a very informative errormsg if it hasn't been done yet. */
673 674
	if (!self->errormsg_created)
	{
675 676 677 678
		self->errormsg = SC_create_errormsg(self);
		self->errormsg_created = TRUE;
	}

679 680
	if (self->errornumber)
	{
681 682
		*number = self->errornumber;
		*message = self->errormsg;
683 684
		if (!self->errormsg_malloced)
			self->errormsg = NULL;
685 686 687 688 689 690 691 692
	}

	rv = (self->errornumber != 0);
	self->errornumber = 0;

	return rv;
}

693 694 695 696 697 698

/*
 *	Currently, the driver offers very simple bookmark support -- it is
 *	just the current row number.  But it could be more sophisticated
 *	someday, such as mapping a key to a 32 bit value
 */
699
unsigned long
Bruce Momjian's avatar
Bruce Momjian committed
700
SC_get_bookmark(StatementClass *self)
701
{
702
	return (self->currTuple + 1);
703
}
704

705

706
RETCODE
Bruce Momjian's avatar
Bruce Momjian committed
707
SC_fetch(StatementClass *self)
708
{
709 710 711
	static char *func = "SC_fetch";
	QResultClass *res = self->result;
	int			retval,
712 713 714 715
				result;
#ifdef	DRIVER_CURSOR_IMPLEMENT
	int		updret;
#endif /* DRIVER_CURSOR_IMPLEMENT */
716 717 718 719
	Int2		num_cols,
				lf;
	Oid			type;
	char	   *value;
720
	ColumnInfoClass *coli;
721
	/* TupleField *tupleField; */
722
	ConnInfo *ci = &(SC_get_conn(self)->connInfo);
723 724

	self->last_fetch_count = 0;
725
	coli = QR_get_fields(res);	/* the column info */
726

727
	mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
728

729
	if (self->manual_result || !SC_is_fetchcursor(self))
730 731 732 733
	{
		if (self->currTuple >= QR_get_num_tuples(res) - 1 ||
			(self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
		{
734

735 736 737 738
			/*
			 * if at the end of the tuples, return "no data found" and set
			 * the cursor past the end of the result set
			 */
739
			self->currTuple = QR_get_num_tuples(res);
740 741
			return SQL_NO_DATA_FOUND;
		}
742

743
		mylog("**** SC_fetch: manual_result\n");
744 745
		(self->currTuple)++;
	}
746 747
	else
	{
748
		/* read from the cache or the physical next tuple */
749
		retval = QR_next_tuple(res);
750 751
		if (retval < 0)
		{
752
			mylog("**** SC_fetch: end_tuples\n");
753 754 755
			return SQL_NO_DATA_FOUND;
		}
		else if (retval > 0)
756 757 758
			(self->currTuple)++;/* all is well */
		else
		{
759
			mylog("SC_fetch: error\n");
760 761 762 763 764 765 766 767 768 769 770 771
			self->errornumber = STMT_EXEC_ERROR;
			self->errormsg = "Error fetching next row";
			SC_log_error(func, "", self);
			return SQL_ERROR;
		}
	}

	num_cols = QR_NumResultCols(res);

	result = SQL_SUCCESS;
	self->last_fetch_count = 1;

772 773 774 775 776 777 778 779 780
	/*
	 * If the bookmark column was bound then return a bookmark. Since this
	 * is used with SQLExtendedFetch, and the rowset size may be greater
	 * than 1, and an application can use row or column wise binding, use
	 * the code in copy_and_convert_field() to handle that.
	 */
	if (self->bookmark.buffer)
	{
		char		buf[32];
781 782

		sprintf(buf, "%ld", SC_get_bookmark(self));
783
		result = copy_and_convert_field(self, 0, buf,
784
			 SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
785 786
	}

787 788 789 790 791 792 793 794 795 796 797
#ifdef	DRIVER_CURSOR_IMPLEMENT
	updret = 0;
	if (self->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
	{
		if (!QR_get_value_backend_row(res, self->currTuple, num_cols - 1))
			updret = SQL_ROW_DELETED;
		num_cols -= 2;
	}
	if (!self->options.retrieve_data) /* data isn't required */
		return updret ? updret + 10 : SQL_SUCCESS;
#endif /* DRIVER_CURSOR_IMPLEMENT */
798 799
	for (lf = 0; lf < num_cols; lf++)
	{
800 801
		mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);

802
		/* reset for SQLGetData */
803 804
		self->bindings[lf].data_left = -1;

805 806
		if (self->bindings[lf].buffer != NULL)
		{
807
			/* this column has a binding */
808

809
			/* type = QR_get_field_type(res, lf); */
810
			type = CI_get_oid(coli, lf);	/* speed things up */
811 812 813

			mylog("type = %d\n", type);

814 815
			if (self->manual_result)
			{
816 817 818
				value = QR_get_value_manual(res, self->currTuple, lf);
				mylog("manual_result\n");
			}
819
			else if (SC_is_fetchcursor(self))
820
				value = QR_get_value_backend(res, lf);
821
			else
822 823
				value = QR_get_value_backend_row(res, self->currTuple, lf);

824
			mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
825 826 827 828 829

			retval = copy_and_convert_field_bindinfo(self, type, value, lf);

			mylog("copy_and_convert: retval = %d\n", retval);

830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
			switch (retval)
			{
				case COPY_OK:
					break;		/* OK, do next bound column */

				case COPY_UNSUPPORTED_TYPE:
					self->errormsg = "Received an unsupported type from Postgres.";
					self->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
					SC_log_error(func, "", self);
					result = SQL_ERROR;
					break;

				case COPY_UNSUPPORTED_CONVERSION:
					self->errormsg = "Couldn't handle the necessary data type conversion.";
					self->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
					SC_log_error(func, "", self);
					result = SQL_ERROR;
					break;

				case COPY_RESULT_TRUNCATED:
					self->errornumber = STMT_TRUNCATED;
851 852 853 854
					self->errormsg = "Fetched item was truncated.";
					qlog("The %dth item was truncated\n", lf + 1);   
					qlog("The buffer size = %d", self->bindings[lf].buflen);
					qlog(" and the value is '%s'\n", value);
855 856 857
					result = SQL_SUCCESS_WITH_INFO;
					break;

858
					/* error msg already filled in */
859
				case COPY_GENERAL_ERROR:
860 861 862 863
					SC_log_error(func, "", self);
					result = SQL_ERROR;
					break;

864
					/* This would not be meaningful in SQLFetch. */
865 866 867 868 869 870 871 872 873
				case COPY_NO_DATA_FOUND:
					break;

				default:
					self->errormsg = "Unrecognized return value from copy_and_convert_field.";
					self->errornumber = STMT_INTERNAL_ERROR;
					SC_log_error(func, "", self);
					result = SQL_ERROR;
					break;
874 875 876 877
			}
		}
	}

878 879 880 881
#ifdef	DRIVER_CURSOR_IMPLEMENT
	if (updret)
		result = updret + 10;
#endif /* DRIVER_CURSOR_IMPLEMENT */
882 883 884 885
	return result;
}


886 887
RETCODE
SC_execute(StatementClass *self)
888
{
889 890 891 892 893 894 895 896 897
	static char *func = "SC_execute";
	ConnectionClass *conn;
	QResultClass *res;
	char		ok,
				was_ok,
				was_nonfatal;
	Int2		oldstatus,
				numcols;
	QueryInfo	qi;
898
	ConnInfo *ci;
899 900 901


	conn = SC_get_conn(self);
902
	ci = &(conn->connInfo);
903

904 905
	/* Begin a transaction if one is not already in progress */

906
	/*
907 908 909 910 911 912 913 914
	 * Basically we don't have to begin a transaction in autocommit mode
	 * because Postgres backend runs in autocomit mode. We issue "BEGIN"
	 * in the following cases. 1) we use declare/fetch and the statement
	 * is SELECT (because declare/fetch must be called in a transaction).
	 * 2) we are in autocommit off state and the statement isn't of type
	 * OTHER.
	 */
	if (!self->internal && !CC_is_in_trans(conn) &&
915
	    (SC_is_fetchcursor(self) ||
916
	     (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
917
	{
918
		mylog("   about to begin a transaction on statement = %u\n", self);
919
		res = CC_send_query(conn, "BEGIN", NULL);
920 921
		if (QR_aborted(res))
		{
922 923
			self->errormsg = "Could not begin a transaction";
			self->errornumber = STMT_EXEC_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
924
			SC_log_error(func, "", self);
925 926
			return SQL_ERROR;
		}
927 928 929

		ok = QR_command_successful(res);

930
		mylog("SC_exec: begin ok = %d, status = %d\n", ok, QR_get_status(res));
931

932
		QR_Destructor(res);
933

934 935
		if (!ok)
		{
936 937
			self->errormsg = "Could not begin a transaction";
			self->errornumber = STMT_EXEC_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
938
			SC_log_error(func, "", self);
939 940 941 942 943 944 945 946 947 948
			return SQL_ERROR;
		}
		else
			CC_set_in_trans(conn);
	}

	oldstatus = conn->status;
	conn->status = CONN_EXECUTING;
	self->status = STMT_EXECUTING;

949 950 951 952 953 954 955 956 957 958
	/* If it's a SELECT statement, use a cursor. */

	/*
	 * Note that the declare cursor has already been prepended to the
	 * statement
	 */
	/* in copy_statement... */
	if (self->statement_type == STMT_TYPE_SELECT)
	{
		char		fetch[128];
959 960 961

		mylog("       Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);

962
		/* send the declare/select */
963
		self->result = CC_send_query(conn, self->stmt_with_params, NULL);
964

965
		if (SC_is_fetchcursor(self) && self->result != NULL &&
966 967
			QR_command_successful(self->result))
		{
968 969
			QR_Destructor(self->result);

970 971 972 973
			/*
			 * That worked, so now send the fetch to start getting data
			 * back
			 */
974 975
			qi.result_in = NULL;
			qi.cursor = self->cursor_name;
976
			qi.row_size = ci->drivers.fetch_max;
977

978 979 980 981 982 983 984
			/*
			 * Most likely the rowset size will not be set by the
			 * application until after the statement is executed, so might
			 * as well use the cache size. The qr_next_tuple() function
			 * will correct for any discrepancies in sizes and adjust the
			 * cache accordingly.
			 */
985
			sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
986

987
			self->result = CC_send_query(conn, fetch, &qi);
988 989 990
		}
		mylog("     done sending the query:\n");
	}
991
	else
992 993
	{
		/* not a SELECT statement so don't use a cursor */
994
		mylog("      it's NOT a select statement: stmt=%u\n", self);
995
		self->result = CC_send_query(conn, self->stmt_with_params, NULL);
996

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
		/*
		 * We shouldn't send COMMIT. Postgres backend does the autocommit
		 * if neccessary. (Zoltan, 04/26/2000)
		 */

		/*
		 * Above seems wrong. Even in case of autocommit, started
		 * transactions must be committed. (Hiroshi, 02/11/2001)
		 */
		if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
		{
			res = CC_send_query(conn, "COMMIT", NULL);
1009 1010
			QR_Destructor(res);
			CC_set_no_trans(conn);
1011
		}
1012 1013 1014 1015 1016
	}

	conn->status = oldstatus;
	self->status = STMT_FINISHED;

1017 1018 1019
	/* Check the status of the result */
	if (self->result)
	{
1020 1021
		was_ok = QR_command_successful(self->result);
		was_nonfatal = QR_command_nonfatal(self->result);
1022

1023
		if (was_ok)
1024 1025 1026
			self->errornumber = STMT_OK;
		else
			self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND;
1027

1028 1029
		/* set cursor before the first tuple in the list */
		self->currTuple = -1;
1030
		self->current_col = -1;
1031
		self->rowset_start = -1;
1032

1033 1034
		/* see if the query did return any result columns */
		numcols = QR_NumResultCols(self->result);
1035

1036
		/* now allocate the array to hold the binding info */
1037 1038
		if (numcols > 0)
		{
1039
			extend_bindings(self, numcols);
1040 1041
			if (self->bindings == NULL)
			{
1042 1043
				self->errornumber = STMT_NO_MEMORY_ERROR;
				self->errormsg = "Could not get enough free memory to store the binding information";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1044
				SC_log_error(func, "", self);
1045 1046 1047
				return SQL_ERROR;
			}
		}
1048 1049
		/* issue "ABORT" when query aborted */
		if (QR_get_aborted(self->result) && !self->internal)
1050
			CC_abort(conn);
1051 1052
	}
	else
1053 1054
	{
		/* Bad Error -- The error message will be in the Connection */
1055 1056
		if (self->statement_type == STMT_TYPE_CREATE)
		{
1057 1058
			self->errornumber = STMT_CREATE_TABLE_ERROR;
			self->errormsg = "Error creating the table";
1059 1060 1061 1062 1063 1064 1065

			/*
			 * This would allow the table to already exists, thus
			 * appending rows to it.  BUT, if the table didn't have the
			 * same attributes, it would fail. return
			 * SQL_SUCCESS_WITH_INFO;
			 */
1066
		}
1067 1068
		else
		{
1069
			self->errornumber = STMT_EXEC_ERROR;
1070 1071
			self->errormsg = "Error while executing the query";
		}
1072

1073
		if (!self->internal)
1074
			CC_abort(conn);
1075 1076
	}

Hiroshi Inoue's avatar
Hiroshi Inoue committed
1077 1078 1079 1080
	if (self->statement_type == STMT_TYPE_PROCCALL &&
	    (self->errornumber == STMT_OK ||
	     self->errornumber == STMT_INFO_ONLY) &&
	    self->parameters &&
1081
	    self->parameters[0].buffer &&
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1082 1083 1084 1085
	    self->parameters[0].paramType == SQL_PARAM_OUTPUT)
	{	/* get the return value of the procedure call */
		RETCODE	ret;
		HSTMT hstmt = (HSTMT) self;
1086 1087 1088 1089 1090 1091 1092 1093 1094
		ret = SC_fetch(hstmt);
		if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
		{ 
			ret = PGAPI_GetData(hstmt, 1, self->parameters[0].CType, self->parameters[0].buffer, self->parameters[0].buflen, self->parameters[0].used);
			if (ret != SQL_SUCCESS) 
			{
				self->errornumber = STMT_EXEC_ERROR;
				self->errormsg = "GetData to Procedure return failed.";
			}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1095 1096 1097 1098 1099 1100 1101
		}
		else
		{
			self->errornumber = STMT_EXEC_ERROR;
			self->errormsg = "SC_fetch to get a Procedure return failed.";
		}
	}
1102 1103
	if (self->errornumber == STMT_OK)
		return SQL_SUCCESS;
1104 1105
	else if (self->errornumber == STMT_INFO_ONLY)
		return SQL_SUCCESS_WITH_INFO;
1106 1107
	else
	{
1108
		self->errormsg = "Error while executing the query";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1109
		SC_log_error(func, "", self);
1110
		return SQL_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1111 1112 1113
	}
}

1114

Byron Nikolaidis's avatar
Byron Nikolaidis committed
1115
void
Bruce Momjian's avatar
Bruce Momjian committed
1116
SC_log_error(char *func, char *desc, StatementClass *self)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1117
{
1118 1119 1120
#ifdef PRN_NULLCHECK
#define nullcheck(a) (a ? a : "(NULL)")
#endif
1121 1122
	if (self)
	{
1123 1124
		qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
		mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1125 1126 1127 1128 1129
		qlog("                 ------------------------------------------------------------\n");
		qlog("                 hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, self->result);
		qlog("                 manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal);
		qlog("                 bindings=%u, bindings_allocated=%d\n", self->bindings, self->bindings_allocated);
		qlog("                 parameters=%u, parameters_allocated=%d\n", self->parameters, self->parameters_allocated);
1130 1131
		qlog("                 statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
		qlog("                 stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1132 1133
		qlog("                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
		qlog("                 currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
1134
		qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, self->options.rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
1135
		qlog("                 cursor_name='%s'\n", nullcheck(self->cursor_name));
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1136 1137 1138

		qlog("                 ----------------QResult Info -------------------------------\n");

1139 1140 1141 1142 1143 1144 1145 1146
		if (self->result)
		{
			QResultClass *res = self->result;

			qlog("                 fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
			qlog("                 fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor));
			qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
			qlog("                 status=%d, inTuples=%d\n", res->status, res->inTuples);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1147
		}
1148

1149
		/* Log the connection error if there is one */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1150 1151 1152 1153
		CC_log_error(func, desc, self->hdbc);
	}
	else
		qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
1154
#undef PRN_NULLCHECK
1155
}