1 /*------
2  * Module:			statement.c
3  *
4  * Description:		This module contains functions related to creating
5  *					and manipulating a statement.
6  *
7  * Classes:			StatementClass (Functions prefix: "SC_")
8  *
9  * API functions:	SQLAllocStmt, SQLFreeStmt
10  *
11  * Comments:		See "readme.txt" for copyright and license information.
12  *-------
13  */
14 
15 #ifdef	WIN_MULTITHREAD_SUPPORT
16 #ifndef	_WIN32_WINNT
17 #define	_WIN32_WINNT	0x0400
18 #endif /* _WIN32_WINNT */
19 #endif /* WIN_MULTITHREAD_SUPPORT */
20 
21 #include "statement.h"
22 #include "misc.h" // strncpy_null
23 
24 #include "bind.h"
25 #include "connection.h"
26 #include "multibyte.h"
27 #include "qresult.h"
28 #include "convert.h"
29 #include "environ.h"
30 #include "loadlib.h"
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 
36 #include "pgapifunc.h"
37 
38 
39 /*	Map sql commands to statement types */
40 static const struct
41 {
42 	int			type;
43 	char	   *s;
44 }	Statement_Type[] =
45 
46 {
47 	{
48 		STMT_TYPE_SELECT, "SELECT"
49 	}
50 	,{
51 		STMT_TYPE_INSERT, "INSERT"
52 	}
53 	,{
54 		STMT_TYPE_UPDATE, "UPDATE"
55 	}
56 	,{
57 		STMT_TYPE_DELETE, "DELETE"
58 	}
59 	,{
60 		STMT_TYPE_PROCCALL, "CALL"
61 	}
62 	,{
63 		STMT_TYPE_PROCCALL, "{"
64 	}
65 	,{
66 		STMT_TYPE_SET, "SET"
67 	}
68 	,{
69 		STMT_TYPE_RESET, "RESET"
70 	}
71 	,{
72 		STMT_TYPE_CREATE, "CREATE"
73 	}
74 	,{
75 		STMT_TYPE_DECLARE, "DECLARE"
76 	}
77 	,{
78 		STMT_TYPE_FETCH, "FETCH"
79 	}
80 	,{
81 		STMT_TYPE_MOVE, "MOVE"
82 	}
83 	,{
84 		STMT_TYPE_CLOSE, "CLOSE"
85 	}
86 	,{
87 		STMT_TYPE_PREPARE, "PREPARE"
88 	}
89 	,{
90 		STMT_TYPE_EXECUTE, "EXECUTE"
91 	}
92 	,{
93 		STMT_TYPE_DEALLOCATE, "DEALLOCATE"
94 	}
95 	,{
96 		STMT_TYPE_DROP, "DROP"
97 	}
98 	,{
99 		STMT_TYPE_START, "BEGIN"
100 	}
101 	,{
102 		STMT_TYPE_START, "START"
103 	}
104 	,{
105 		STMT_TYPE_TRANSACTION, "SAVEPOINT"
106 	}
107 	,{
108 		STMT_TYPE_TRANSACTION, "RELEASE"
109 	}
110 	,{
111 		STMT_TYPE_TRANSACTION, "COMMIT"
112 	}
113 	,{
114 		STMT_TYPE_TRANSACTION, "END"
115 	}
116 	,{
117 		STMT_TYPE_TRANSACTION, "ROLLBACK"
118 	}
119 	,{
120 		STMT_TYPE_TRANSACTION, "ABORT"
121 	}
122 	,{
123 		STMT_TYPE_LOCK, "LOCK"
124 	}
125 	,{
126 		STMT_TYPE_ALTER, "ALTER"
127 	}
128 	,{
129 		STMT_TYPE_GRANT, "GRANT"
130 	}
131 	,{
132 		STMT_TYPE_REVOKE, "REVOKE"
133 	}
134 	,{
135 		STMT_TYPE_COPY, "COPY"
136 	}
137 	,{
138 		STMT_TYPE_ANALYZE, "ANALYZE"
139 	}
140 	,{
141 		STMT_TYPE_NOTIFY, "NOTIFY"
142 	}
143 	,{
144 		STMT_TYPE_EXPLAIN, "EXPLAIN"
145 	}
146 
147 	/*
148 	 * Special-commands that cannot be run in a transaction block. This isn't
149 	 * as granular as it could be. VACUUM can never be run in a transaction
150 	 * block, but some variants of REINDEX and CLUSTER can be. CHECKPOINT
151 	 * doesn't throw an error if you do, but it cannot be rolled back so
152 	 * there's no point in beginning a new transaction for it.
153 	 */
154 	,{
155 		STMT_TYPE_SPECIAL, "VACUUM"
156 	}
157 	,{
158 		STMT_TYPE_SPECIAL, "REINDEX"
159 	}
160 	,{
161 		STMT_TYPE_SPECIAL, "CLUSTER"
162 	}
163 	,{
164 		STMT_TYPE_SPECIAL, "CHECKPOINT"
165 	}
166 
167 	,{
168 		STMT_TYPE_WITH, "WITH"
169 	}
170 	,{
171 		0, NULL
172 	}
173 };
174 
175 static QResultClass *libpq_bind_and_exec(StatementClass *stmt);
176 static void SC_set_errorinfo(StatementClass *self, QResultClass *res, int errkind);
177 static void SC_set_error_if_not_set(StatementClass *self, int errornumber, const char *errmsg, const char *func);
178 
179 
180 RETCODE		SQL_API
PGAPI_AllocStmt(HDBC hdbc,HSTMT * phstmt,UDWORD flag)181 PGAPI_AllocStmt(HDBC hdbc,
182 				HSTMT * phstmt, UDWORD flag)
183 {
184 	CSTR func = "PGAPI_AllocStmt";
185 	ConnectionClass *conn = (ConnectionClass *) hdbc;
186 	StatementClass *stmt;
187 	ARDFields	*ardopts;
188 
189 	MYLOG(0, "entering...\n");
190 
191 	if (!conn)
192 	{
193 		CC_log_error(func, "", NULL);
194 		return SQL_INVALID_HANDLE;
195 	}
196 
197 	stmt = SC_Constructor(conn);
198 
199 	MYLOG(0, "**** : hdbc = %p, stmt = %p\n", hdbc, stmt);
200 
201 	if (!stmt)
202 	{
203 		CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory to allocate a further SQL-statement", func);
204 		*phstmt = SQL_NULL_HSTMT;
205 		return SQL_ERROR;
206 	}
207 
208 	if (!CC_add_statement(conn, stmt))
209 	{
210 		CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of statements exceeded.", func);
211 		SC_Destructor(stmt);
212 		*phstmt = SQL_NULL_HSTMT;
213 		return SQL_ERROR;
214 	}
215 
216 	*phstmt = (HSTMT) stmt;
217 
218 	stmt->iflag = flag;
219 	/* Copy default statement options based from Connection options */
220 	if (0 != (PODBC_INHERIT_CONNECT_OPTIONS & flag))
221 	{
222 		stmt->options = stmt->options_orig = conn->stmtOptions;
223 		stmt->ardi.ardf = conn->ardOptions;
224 	}
225 	else
226 	{
227 		InitializeStatementOptions(&stmt->options_orig);
228 		stmt->options = stmt->options_orig;
229 		InitializeARDFields(&stmt->ardi.ardf);
230 	}
231 	ardopts = SC_get_ARDF(stmt);
232 	ARD_AllocBookmark(ardopts);
233 
234 	/* Save the handle for later */
235 	stmt->phstmt = phstmt;
236 
237 	return SQL_SUCCESS;
238 }
239 
240 
241 RETCODE		SQL_API
PGAPI_FreeStmt(HSTMT hstmt,SQLUSMALLINT fOption)242 PGAPI_FreeStmt(HSTMT hstmt,
243 			   SQLUSMALLINT fOption)
244 {
245 	CSTR func = "PGAPI_FreeStmt";
246 	StatementClass *stmt = (StatementClass *) hstmt;
247 
248 	MYLOG(0, "entering...hstmt=%p, fOption=%hi\n", hstmt, fOption);
249 
250 	if (!stmt)
251 	{
252 		SC_log_error(func, "", NULL);
253 		return SQL_INVALID_HANDLE;
254 	}
255 	SC_clear_error(stmt);
256 
257 	if (fOption == SQL_DROP)
258 	{
259 		ConnectionClass *conn = stmt->hdbc;
260 
261 		/* Remove the statement from the connection's statement list */
262 		if (conn)
263 		{
264 			QResultClass	*res;
265 
266 			if (STMT_EXECUTING == stmt->status)
267 			{
268 				SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
269 				return SQL_ERROR; /* stmt may be executing a transaction */
270 			}
271 			if (conn->unnamed_prepared_stmt == stmt)
272 				conn->unnamed_prepared_stmt = NULL;
273 
274 			/*
275 			 * Free any cursors and discard any result info.
276 			 * Don't detach the statement from the connection
277 			 * before freeing the associated cursors. Otherwise
278 			 * CC_cursor_count() would get wrong results.
279 			 */
280 			res = SC_get_Result(stmt);
281 			QR_Destructor(res);
282 			SC_init_Result(stmt);
283 			if (!CC_remove_statement(conn, stmt))
284 			{
285 				SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
286 				return SQL_ERROR;		/* stmt may be executing a
287 										 * transaction */
288 			}
289 		}
290 
291 		if (stmt->execute_delegate)
292 		{
293 			PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
294 			stmt->execute_delegate = NULL;
295 		}
296 		if (stmt->execute_parent)
297 			stmt->execute_parent->execute_delegate = NULL;
298 		/* Destroy the statement and free any results, cursors, etc. */
299 		SC_Destructor(stmt);
300 	}
301 	else if (fOption == SQL_UNBIND)
302 		SC_unbind_cols(stmt);
303 	else if (fOption == SQL_CLOSE)
304 	{
305 		/*
306 		 * this should discard all the results, but leave the statement
307 		 * itself in place (it can be executed again)
308 		 */
309 		stmt->transition_status = STMT_TRANSITION_ALLOCATED;
310 		if (stmt->execute_delegate)
311 		{
312 			PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
313 			stmt->execute_delegate = NULL;
314 		}
315 		if (!SC_recycle_statement(stmt))
316 		{
317 			return SQL_ERROR;
318 		}
319 		SC_set_Curres(stmt, NULL);
320 	}
321 	else if (fOption == SQL_RESET_PARAMS)
322 		SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
323 	else
324 	{
325 		SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to PGAPI_FreeStmt.", func);
326 		return SQL_ERROR;
327 	}
328 
329 	return SQL_SUCCESS;
330 }
331 
332 
333 /*
334  * StatementClass implementation
335  */
336 void
InitializeStatementOptions(StatementOptions * opt)337 InitializeStatementOptions(StatementOptions *opt)
338 {
339 	memset(opt, 0, sizeof(StatementOptions));
340 	opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
341 	opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
342 	opt->retrieve_data = SQL_RD_ON;
343 	opt->use_bookmarks = SQL_UB_OFF;
344 	opt->metadata_id = SQL_FALSE;
345 }
346 
SC_clear_parse_status(StatementClass * self,ConnectionClass * conn)347 static void SC_clear_parse_status(StatementClass *self, ConnectionClass *conn)
348 {
349 	self->parse_status = STMT_PARSE_NONE;
350 }
351 
SC_init_discard_output_params(StatementClass * self)352 static void SC_init_discard_output_params(StatementClass *self)
353 {
354 	ConnectionClass	*conn = SC_get_conn(self);
355 
356 	if (!conn)	return;
357 	self->discard_output_params = 0;
358 	if (!conn->connInfo.use_server_side_prepare)
359 		self->discard_output_params = 1;
360 }
361 
SC_init_parse_method(StatementClass * self)362 static void SC_init_parse_method(StatementClass *self)
363 {
364 	ConnectionClass	*conn = SC_get_conn(self);
365 
366 	self->parse_method = 0;
367 	if (!conn)	return;
368 	if (0 == (PODBC_EXTERNAL_STATEMENT & self->iflag))	return;
369 	if (self->catalog_result) return;
370 	if (conn->connInfo.drivers.parse)
371 		SC_set_parse_forced(self);
372 }
373 
374 StatementClass *
SC_Constructor(ConnectionClass * conn)375 SC_Constructor(ConnectionClass *conn)
376 {
377 	StatementClass *rv;
378 
379 	rv = (StatementClass *) malloc(sizeof(StatementClass));
380 	if (rv)
381 	{
382 		rv->hdbc = conn;
383 		rv->phstmt = NULL;
384 		rv->rhold.first = rv->rhold.last = NULL;
385 		rv->curres = NULL;
386 		rv->parsed = NULL;
387 		rv->catalog_result = FALSE;
388 		rv->prepare = NON_PREPARE_STATEMENT;
389 		rv->prepared = NOT_YET_PREPARED;
390 		rv->status = STMT_ALLOCATED;
391 		rv->external = FALSE;
392 		rv->iflag = 0;
393 		rv->plan_name = NULL;
394 		rv->transition_status = STMT_TRANSITION_UNALLOCATED;
395 		rv->multi_statement = -1; /* unknown */
396 		rv->num_params = -1; /* unknown */
397 		rv->processed_statements = NULL;
398 
399 		rv->__error_message = NULL;
400 		rv->__error_number = 0;
401 		rv->pgerror = NULL;
402 
403 		rv->statement = NULL;
404 		rv->stmt_with_params = NULL;
405 		rv->load_statement = NULL;
406 		rv->statement_type = STMT_TYPE_UNKNOWN;
407 
408 		rv->currTuple = -1;
409 		rv->rowset_start = 0;
410 		SC_set_rowset_start(rv, -1, FALSE);
411 		rv->current_col = -1;
412 		rv->bind_row = 0;
413 		rv->from_pos = rv->load_from_pos = rv->where_pos = -1;
414 		rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
415 		rv->save_rowset_size = -1;
416 
417 		rv->data_at_exec = -1;
418 		rv->current_exec_param = -1;
419 		rv->exec_start_row = -1;
420 		rv->exec_end_row = -1;
421 		rv->exec_current_row = -1;
422 		rv->put_data = FALSE;
423 		rv->ref_CC_error = FALSE;
424 		rv->join_info = 0;
425 		SC_init_parse_method(rv);
426 
427 		rv->lobj_fd = -1;
428 		INIT_NAME(rv->cursor_name);
429 
430 		/* Parse Stuff */
431 		rv->ti = NULL;
432 		rv->ntab = 0;
433 		rv->num_key_fields = -1; /* unknown */
434 		SC_clear_parse_status(rv, conn);
435 		rv->proc_return = -1;
436 		SC_init_discard_output_params(rv);
437 		rv->cancel_info = 0;
438 
439 		/* Clear Statement Options -- defaults will be set in AllocStmt */
440 		memset(&rv->options, 0, sizeof(StatementOptions));
441 		InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->ardi),
442 				rv, SQL_ATTR_APP_ROW_DESC);
443 		InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->apdi),
444 				rv, SQL_ATTR_APP_PARAM_DESC);
445 		InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->irdi),
446 				rv, SQL_ATTR_IMP_ROW_DESC);
447 		InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->ipdi),
448 				rv, SQL_ATTR_IMP_PARAM_DESC);
449 
450 		rv->miscinfo = 0;
451 		rv->execinfo = 0;
452 		rv->rb_or_tc = 0;
453 		SC_reset_updatable(rv);
454 		rv->diag_row_count = 0;
455 		rv->stmt_time = 0;
456 		rv->execute_delegate = NULL;
457 		rv->execute_parent = NULL;
458 		rv->allocated_callbacks = 0;
459 		rv->num_callbacks = 0;
460 		rv->callbacks = NULL;
461 		GetDataInfoInitialize(SC_get_GDTI(rv));
462 		PutDataInfoInitialize(SC_get_PDTI(rv));
463 		rv->use_server_side_prepare = conn->connInfo.use_server_side_prepare;
464 		rv->lock_CC_for_rb = FALSE;
465 		// for batch execution
466 		memset(&rv->stmt_deffered, 0, sizeof(rv->stmt_deffered));
467 		if ((rv->batch_size = conn->connInfo.batch_size) < 1)
468 			rv->batch_size = 1;
469 		rv->exec_type = DIRECT_EXEC;
470 		rv->count_of_deffered = 0;
471 		rv->has_notice = 0;
472 		INIT_STMT_CS(rv);
473 	}
474 	return rv;
475 }
476 
477 char
SC_Destructor(StatementClass * self)478 SC_Destructor(StatementClass *self)
479 {
480 	CSTR func	= "SC_Destructor";
481 	QResultClass	*res = SC_get_Result(self);
482 
483 	MYLOG(0, "entering self=%p, self->result=%p, self->hdbc=%p\n", self, res, self->hdbc);
484 	SC_clear_error(self);
485 	if (STMT_EXECUTING == self->status)
486 	{
487 		SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
488 		return FALSE;
489 	}
490 
491 	if (res)
492 	{
493 		if (!self->hdbc)
494 			res->conn = NULL;	/* prevent any dbase activity */
495 
496 		QR_Destructor(res);
497 	}
498 
499 	SC_initialize_stmts(self, TRUE);
500 
501         /* Free the parsed table information */
502 	SC_initialize_cols_info(self, FALSE, TRUE);
503 
504 	NULL_THE_NAME(self->cursor_name);
505 	/* Free the parsed field information */
506 	DC_Destructor((DescriptorClass *) SC_get_ARDi(self));
507 	DC_Destructor((DescriptorClass *) SC_get_APDi(self));
508 	DC_Destructor((DescriptorClass *) SC_get_IRDi(self));
509 	DC_Destructor((DescriptorClass *) SC_get_IPDi(self));
510 	GDATA_unbind_cols(SC_get_GDTI(self), TRUE);
511 	PDATA_free_params(SC_get_PDTI(self), STMT_FREE_PARAMS_ALL);
512 
513 	if (self->__error_message)
514 		free(self->__error_message);
515 	if (self->pgerror)
516 		ER_Destructor(self->pgerror);
517 	cancelNeedDataState(self);
518 	if (self->callbacks)
519 		free(self->callbacks);
520 	if (!PQExpBufferDataBroken(self->stmt_deffered))
521 		termPQExpBuffer(&self->stmt_deffered);
522 
523 	DELETE_STMT_CS(self);
524 	free(self);
525 
526 	MYLOG(0, "leaving\n");
527 
528 	return TRUE;
529 }
530 
531 void
SC_init_Result(StatementClass * self)532 SC_init_Result(StatementClass *self)
533 {
534 	self->rhold.first = self->rhold.last = NULL;
535 	self->curres = NULL;
536 	MYLOG(0, "leaving(%p)\n", self);
537 }
538 
539 void
SC_set_Result(StatementClass * self,QResultClass * first)540 SC_set_Result(StatementClass *self, QResultClass *first)
541 {
542 	if (first != self->rhold.first)
543 	{
544 		QResultClass *last = NULL, *res;
545 
546 		MYLOG(0, "(%p, %p)\n", self, first);
547 		QR_Destructor(self->parsed);
548 		self->parsed = NULL;
549 		QR_Destructor(self->rhold.first);
550 		for (res = first; res; res = QR_nextr(res))
551 			last = res;
552 		self->curres = first;
553 		self->rhold.first = first;
554 		self->rhold.last = last;
555 	}
556 }
557 
558 void
SC_set_ResultHold(StatementClass * self,QResultHold rhold)559 SC_set_ResultHold(StatementClass *self, QResultHold rhold)
560 {
561 	if (rhold.first != self->rhold.first)
562 	{
563 		MYLOG(0, "(%p, {%p, %p})\n", self, rhold.first, rhold.last);
564 		QR_Destructor(self->parsed);
565 		self->parsed = NULL;
566 		QR_Destructor(self->rhold.first);
567 		self->curres = rhold.first;
568 		self->rhold = rhold;
569 	}
570 	else if (rhold.last != self->rhold.last)
571 	{
572 		self->rhold.last = rhold.last;
573 		if (QR_nextr(rhold.last) != NULL)
574 			SC_set_error(self, STMT_INTERNAL_ERROR, "last Result is not the last result", __FUNCTION__);
575 	}
576 
577 }
578 
579 /*
580  *	Free parameters and free the memory from the
581  *	data-at-execution parameters that was allocated in SQLPutData.
582  */
583 void
SC_free_params(StatementClass * self,char option)584 SC_free_params(StatementClass *self, char option)
585 {
586 	if (option != STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY)
587 	{
588 		APD_free_params(SC_get_APDF(self), option);
589 		IPD_free_params(SC_get_IPDF(self), option);
590 	}
591 	PDATA_free_params(SC_get_PDTI(self), option);
592 	self->data_at_exec = -1;
593 	self->current_exec_param = -1;
594 	self->put_data = FALSE;
595 	if (option == STMT_FREE_PARAMS_ALL)
596 	{
597 		self->exec_start_row = -1;
598 		self->exec_end_row = -1;
599 		self->exec_current_row = -1;
600 	}
601 }
602 
603 
604 int
statement_type(const char * statement)605 statement_type(const char *statement)
606 {
607 	int			i;
608 
609 	/* ignore leading whitespace in query string */
610 	while (*statement && (isspace((UCHAR) *statement) || *statement == '('))
611 		statement++;
612 
613 	for (i = 0; Statement_Type[i].s; i++)
614 		if (!strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s)))
615 			return Statement_Type[i].type;
616 
617 	return STMT_TYPE_OTHER;
618 }
619 
620 void
SC_set_planname(StatementClass * stmt,const char * plan_name)621 SC_set_planname(StatementClass *stmt, const char *plan_name)
622 {
623 	if (stmt->plan_name)
624 		free(stmt->plan_name);
625 	if (plan_name && plan_name[0])
626 		stmt->plan_name = strdup(plan_name);
627 	else
628 		stmt->plan_name = NULL;
629 }
630 
631 void
SC_set_rowset_start(StatementClass * stmt,SQLLEN start,BOOL valid_base)632 SC_set_rowset_start(StatementClass *stmt, SQLLEN start, BOOL valid_base)
633 {
634 	QResultClass	*res = SC_get_Curres(stmt);
635 	SQLLEN		incr = start - stmt->rowset_start;
636 
637 MYLOG(DETAIL_LOG_LEVEL, "%p->SC_set_rowstart " FORMAT_LEN "->" FORMAT_LEN "(%s) ", stmt, stmt->rowset_start, start, valid_base ? "valid" : "unknown");
638 	if (res != NULL)
639 	{
640 		BOOL	valid = QR_has_valid_base(res);
641 MYPRINTF(DETAIL_LOG_LEVEL, ":(%p)QR is %s", res, QR_has_valid_base(res) ? "valid" : "unknown");
642 
643 		if (valid)
644 		{
645 			if (valid_base)
646 				QR_inc_rowstart_in_cache(res, incr);
647 			else
648 				QR_set_no_valid_base(res);
649 		}
650 		else if (valid_base)
651 		{
652 			QR_set_has_valid_base(res);
653 			if (start < 0)
654 				QR_set_rowstart_in_cache(res, -1);
655 			else
656 				QR_set_rowstart_in_cache(res, start);
657 		}
658 		if (!QR_get_cursor(res))
659 			res->key_base = start;
660 MYPRINTF(DETAIL_LOG_LEVEL, ":(%p)QR result=" FORMAT_LEN "(%s)", res, QR_get_rowstart_in_cache(res), QR_has_valid_base(res) ? "valid" : "unknown");
661 	}
662 	stmt->rowset_start = start;
663 MYPRINTF(DETAIL_LOG_LEVEL, ":stmt result=" FORMAT_LEN "\n", stmt->rowset_start);
664 }
665 void
SC_inc_rowset_start(StatementClass * stmt,SQLLEN inc)666 SC_inc_rowset_start(StatementClass *stmt, SQLLEN inc)
667 {
668 	SQLLEN	start = stmt->rowset_start + inc;
669 
670 	SC_set_rowset_start(stmt, start, TRUE);
671 }
672 int
SC_set_current_col(StatementClass * stmt,int col)673 SC_set_current_col(StatementClass *stmt, int col)
674 {
675 	if (col == stmt->current_col)
676 		return col;
677 	if (col >= 0)
678 		reset_a_getdata_info(SC_get_GDTI(stmt), col + 1);
679 	stmt->current_col = col;
680 
681 	return stmt->current_col;
682 }
683 
684 void
SC_set_prepared(StatementClass * stmt,int prepared)685 SC_set_prepared(StatementClass *stmt, int prepared)
686 {
687 	if (prepared == stmt->prepared)
688 		;
689 	else if (NOT_YET_PREPARED == prepared && PREPARED_PERMANENTLY == stmt->prepared)
690 	{
691 		ConnectionClass *conn = SC_get_conn(stmt);
692 
693 		if (conn)
694 		{
695 			ENTER_CONN_CS(conn);
696 			if (CONN_CONNECTED == conn->status)
697 			{
698 				if (CC_is_in_error_trans(conn))
699 				{
700 					CC_mark_a_object_to_discard(conn, 's',  stmt->plan_name);
701 				}
702 				else
703 				{
704 					QResultClass	*res;
705 					char dealloc_stmt[128];
706 
707 					SPRINTF_FIXED(dealloc_stmt, "DEALLOCATE \"%s\"", stmt->plan_name);
708 					res = CC_send_query(conn, dealloc_stmt, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
709 					QR_Destructor(res);
710 				}
711 			}
712 			LEAVE_CONN_CS(conn);
713 		}
714 	}
715 	if (NOT_YET_PREPARED == prepared)
716 		SC_set_planname(stmt, NULL);
717 	stmt->prepared = prepared;
718 }
719 
720 /*
721  * Initialize stmt_with_params and load_statement member pointer
722  * deallocating corresponding prepared plan. Also initialize
723  * statement member pointer if specified.
724  */
725 RETCODE
SC_initialize_stmts(StatementClass * self,BOOL initializeOriginal)726 SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
727 {
728 	ProcessedStmt *pstmt;
729 	ProcessedStmt *next_pstmt;
730 	ConnectionClass *conn = SC_get_conn(self);
731 
732 	if (self->lock_CC_for_rb)
733 	{
734 		if (conn)
735 			LEAVE_CONN_CS(conn);
736 		self->lock_CC_for_rb = FALSE;
737 	}
738 	if (initializeOriginal)
739 	{
740 		if (self->statement)
741 		{
742 			free(self->statement);
743 			self->statement = NULL;
744 		}
745 
746 		pstmt = self->processed_statements;
747 		while (pstmt)
748 		{
749 			if (pstmt->query)
750 				free(pstmt->query);
751 			next_pstmt = pstmt->next;
752 			free(pstmt);
753 			pstmt = next_pstmt;
754 		}
755 		self->processed_statements = NULL;
756 
757 		self->prepare = NON_PREPARE_STATEMENT;
758 		SC_set_prepared(self, NOT_YET_PREPARED);
759 		self->statement_type = STMT_TYPE_UNKNOWN; /* unknown */
760 		self->multi_statement = -1; /* unknown */
761 		self->num_params = -1; /* unknown */
762 		self->proc_return = -1; /* unknown */
763 		self->join_info = 0;
764 		SC_init_parse_method(self);
765 		SC_init_discard_output_params(self);
766 		if (conn)
767 			self->use_server_side_prepare = conn->connInfo.use_server_side_prepare;
768 	}
769 	if (self->stmt_with_params)
770 	{
771 		free(self->stmt_with_params);
772 		self->stmt_with_params = NULL;
773 	}
774 	if (self->load_statement)
775 	{
776 		free(self->load_statement);
777 		self->load_statement = NULL;
778 	}
779 	self->has_notice = 0;
780 
781 	return 0;
782 }
783 
SC_opencheck(StatementClass * self,const char * func)784 BOOL	SC_opencheck(StatementClass *self, const char *func)
785 {
786 	QResultClass	*res;
787 
788 	if (!self)
789 		return FALSE;
790 	if (self->status == STMT_EXECUTING)
791 	{
792 		SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
793 		return TRUE;
794 	}
795 	/*
796 	 * We can dispose the result of Describe-only any time.
797 	 */
798 	if (self->prepare && self->status == STMT_DESCRIBED)
799 	{
800 		MYLOG(0, "self->prepare && self->status == STMT_DESCRIBED\n");
801 		return FALSE;
802 	}
803 	if (res = SC_get_Curres(self), NULL != res)
804 	{
805 		if (QR_command_maybe_successful(res) && res->backend_tuples)
806 		{
807 			SC_set_error(self, STMT_SEQUENCE_ERROR, "The cursor is open.", func);
808 			return TRUE;
809 		}
810 	}
811 
812 	return	FALSE;
813 }
814 
815 RETCODE
SC_initialize_and_recycle(StatementClass * self)816 SC_initialize_and_recycle(StatementClass *self)
817 {
818 	SC_initialize_stmts(self, TRUE);
819 	if (!SC_recycle_statement(self))
820 		return SQL_ERROR;
821 
822 	return SQL_SUCCESS;
823 }
824 
825 void
SC_reset_result_for_rerun(StatementClass * self)826 SC_reset_result_for_rerun(StatementClass *self)
827 {
828 	QResultClass	*res;
829 	ColumnInfoClass	*flds;
830 
831 	if (!self)	return;
832 	if (res = SC_get_Result(self), NULL == res)
833 		return;
834 	flds = QR_get_fields(res);
835 	if (NULL == flds ||
836 	    0 == CI_get_num_fields(flds))
837 		SC_set_Result(self, NULL);
838 	else
839 	{
840 		QR_reset_for_re_execute(res);
841 		SC_set_Curres(self, NULL);
842 	}
843 }
844 
845 /*
846  *	Called from SQLPrepare if STMT_PREMATURE, or
847  *	from SQLExecute if STMT_FINISHED, or
848  *	from SQLFreeStmt(SQL_CLOSE)
849  */
850 char
SC_recycle_statement(StatementClass * self)851 SC_recycle_statement(StatementClass *self)
852 {
853 	CSTR	func = "SC_recycle_statement";
854 	ConnectionClass *conn;
855 
856 	MYLOG(0, "entering self=%p\n", self);
857 
858 	SC_clear_error(self);
859 	/* This would not happen */
860 	if (self->status == STMT_EXECUTING)
861 	{
862 		SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
863 		return FALSE;
864 	}
865 
866 	if (SC_get_conn(self)->unnamed_prepared_stmt == self)
867 		SC_get_conn(self)->unnamed_prepared_stmt = NULL;
868 
869 	conn = SC_get_conn(self);
870 	switch (self->status)
871 	{
872 		case STMT_ALLOCATED:
873 			/* this statement does not need to be recycled */
874 			return TRUE;
875 
876 		case STMT_READY:
877 			break;
878 
879 		case STMT_DESCRIBED:
880 			break;
881 
882 		case STMT_FINISHED:
883 			break;
884 
885 		default:
886 			SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements", func);
887 			return FALSE;
888 	}
889 
890 	switch (self->prepared)
891 	{
892 		case NOT_YET_PREPARED:
893 		case PREPARED_TEMPORARILY:
894 			/* Free the parsed table/field information */
895 			SC_initialize_cols_info(self, TRUE, TRUE);
896 
897 MYLOG(DETAIL_LOG_LEVEL, "SC_clear_parse_status\n");
898 			SC_clear_parse_status(self, conn);
899 			break;
900 	}
901 
902 	/* Free any cursors */
903 	if (SC_get_Result(self))
904 		SC_set_Result(self, NULL);
905 	QR_Destructor(self->parsed);
906 	self->parsed = NULL;
907 	self->miscinfo = 0;
908 	self->execinfo = 0;
909 	/* self->rbonerr = 0; Never clear the bits here */
910 
911 	/*
912 	 * Reset only parameters that have anything to do with results
913 	 */
914 	self->status = STMT_READY;
915 	self->catalog_result = FALSE;	/* not very important */
916 
917 	self->currTuple = -1;
918 	SC_set_rowset_start(self, -1, FALSE);
919 	SC_set_current_col(self, -1);
920 	self->bind_row = 0;
921 MYLOG(DETAIL_LOG_LEVEL, "statement=%p ommitted=0\n", self);
922 	self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
923 
924 	self->__error_message = NULL;
925 	self->__error_number = 0;
926 
927 	self->lobj_fd = -1;
928 
929 	SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
930 	SC_initialize_stmts(self, FALSE);
931 	cancelNeedDataState(self);
932 	self->cancel_info = 0;
933 	/*
934 	 *	reset the current attr setting to the original one.
935 	 */
936 	self->options.scroll_concurrency = self->options_orig.scroll_concurrency;
937 	self->options.cursor_type = self->options_orig.cursor_type;
938 	self->options.keyset_size = self->options_orig.keyset_size;
939 	self->options.maxLength = self->options_orig.maxLength;
940 	self->options.maxRows = self->options_orig.maxRows;
941 
942 	return TRUE;
943 }
944 
945 /*
946  *	Scan the query wholly or partially (if the next_cmd param specified).
947  *	Also count the number of parameters respectviely.
948  */
949 void
SC_scanQueryAndCountParams(const char * query,const ConnectionClass * conn,ssize_t * next_cmd,SQLSMALLINT * pcpar,po_ind_t * multi_st,po_ind_t * proc_return)950 SC_scanQueryAndCountParams(const char *query, const ConnectionClass *conn,
951 		ssize_t *next_cmd, SQLSMALLINT * pcpar,
952 		po_ind_t *multi_st, po_ind_t *proc_return)
953 {
954 	const	char *tstr, *tag = NULL;
955 	size_t	taglen = 0;
956 	char	tchar, bchar, escape_in_literal = '\0';
957 	char	in_literal = FALSE, in_ident_keyword = FALSE,
958 		in_dquote_identifier = FALSE,
959 		in_dollar_quote = FALSE, in_escape = FALSE,
960 		in_line_comment = FALSE, del_found = FALSE;
961 	int	comment_level = 0;
962 	po_ind_t multi = FALSE;
963 	SQLSMALLINT	num_p;
964 	encoded_str	encstr;
965 
966 	MYLOG(0, "entering...\n");
967 	num_p = 0;
968 	if (proc_return)
969 		*proc_return = 0;
970 	if (next_cmd)
971 		*next_cmd = -1;
972 	tstr = query;
973 	make_encoded_str(&encstr, conn, tstr);
974 	for (bchar = '\0', tchar = encoded_nextchar(&encstr); tchar; tchar = encoded_nextchar(&encstr))
975 	{
976 		if (MBCS_NON_ASCII(encstr)) /* multibyte char */
977 		{
978 			if ((UCHAR) tchar >= 0x80)
979 				bchar = tchar;
980 			if (in_dquote_identifier ||
981 			    in_literal ||
982 			    in_dollar_quote ||
983 			    in_escape ||
984 			    in_line_comment ||
985 			    comment_level > 0)
986 				;
987 			else
988 				in_ident_keyword = TRUE;
989 
990 			continue;
991 		}
992 		if (!multi && del_found)
993 		{
994 			if (IS_NOT_SPACE(tchar))
995 			{
996 				multi = TRUE;
997 				if (next_cmd)
998 					break;
999 			}
1000 		}
1001 		if (in_ident_keyword)
1002 		{
1003 			if (isalnum(tchar) ||
1004 			    DOLLAR_QUOTE == tchar ||
1005 			    '_' == tchar)
1006 			{
1007 				bchar = tchar;
1008 				continue;
1009 			}
1010 			in_ident_keyword = FALSE;
1011 		}
1012 
1013 		if (in_dollar_quote)
1014 		{
1015 			if (tchar == DOLLAR_QUOTE)
1016 			{
1017 				if (strncmp((const char *) ENCODE_PTR(encstr), tag, taglen) == 0)
1018 				{
1019 					in_dollar_quote = FALSE;
1020 					tag = NULL;
1021 					encoded_position_shift(&encstr, taglen - 1);
1022 				}
1023 			}
1024 		}
1025 		else if (in_literal)
1026 		{
1027 			if (in_escape)
1028 				in_escape = FALSE;
1029 			else if (tchar == escape_in_literal)
1030 				in_escape = TRUE;
1031 			else if (tchar == LITERAL_QUOTE)
1032 				in_literal = FALSE;
1033 		}
1034 		else if (in_dquote_identifier)
1035 		{
1036 			if (tchar == IDENTIFIER_QUOTE)
1037 				in_dquote_identifier = FALSE;
1038 		}
1039 		else if (in_line_comment)
1040 		{
1041 			if (PG_LINEFEED == tchar)
1042 				in_line_comment = FALSE;
1043 		}
1044 		else if (comment_level > 0)
1045 		{
1046 			if ('/' == tchar && '*' == ENCODE_PTR(encstr)[1])
1047 			{
1048 				tchar = encoded_nextchar(&encstr);
1049 				comment_level++;
1050 			}
1051 			else if ('*' == tchar && '/' == ENCODE_PTR(encstr)[1])
1052 			{
1053 				tchar = encoded_nextchar(&encstr);
1054 				comment_level--;
1055 			}
1056 		}
1057 		else if (isalnum(tchar))
1058 			in_ident_keyword = TRUE;
1059 		else
1060 		{
1061 			if (tchar == '?')
1062 			{
1063 				if (0 == num_p && bchar == '{')
1064 				{
1065 					if (proc_return)
1066 						*proc_return = 1;
1067 				}
1068 				num_p++;
1069 			}
1070 			else if (tchar == ';')
1071 			{
1072 				del_found = TRUE;
1073 				if (next_cmd)
1074 					*next_cmd = encstr.pos;
1075 			}
1076 			else if (tchar == DOLLAR_QUOTE)
1077 			{
1078 				const char *ptr = (const char *) ENCODE_PTR(encstr);
1079 				taglen = findTag(ptr, encstr.ccsc);
1080 				if (taglen > 0)
1081 				{
1082 					in_dollar_quote = TRUE;
1083 					tag = ptr;
1084 					encoded_position_shift(&encstr, taglen - 1);
1085 				}
1086 			}
1087 			else if (tchar == LITERAL_QUOTE)
1088 			{
1089 				in_literal = TRUE;
1090 				escape_in_literal = CC_get_escape(conn);
1091 				if (!escape_in_literal)
1092 				{
1093 					if (LITERAL_EXT == ENCODE_PTR(encstr)[-1])
1094 						escape_in_literal = ESCAPE_IN_LITERAL;
1095 				}
1096 			}
1097 			else if (tchar == IDENTIFIER_QUOTE)
1098 				in_dquote_identifier = TRUE;
1099 			else if ('-' == tchar)
1100 			{
1101 				if ('-' == ENCODE_PTR(encstr)[1])
1102 				{
1103 					tchar = encoded_nextchar(&encstr);
1104 					in_line_comment = TRUE;
1105 				}
1106 			}
1107 			else if ('/' == tchar)
1108 			{
1109 				if ('*' == ENCODE_PTR(encstr)[1])
1110 				{
1111 					tchar = encoded_nextchar(&encstr);
1112 					comment_level++;
1113 				}
1114 			}
1115 			if (IS_NOT_SPACE(tchar))
1116 				bchar = tchar;
1117 		}
1118 	}
1119 	if (pcpar)
1120 		*pcpar = num_p;
1121 	if (multi_st)
1122 		*multi_st = multi;
1123 
1124 	MYLOG(0, "leaving...num_p=%d multi=%d\n", num_p, multi);
1125 }
1126 
1127 /*
1128  * Describe the result set a statement will produce (for
1129  * SQLPrepare/SQLDescribeCol)
1130  *
1131  * returns # of fields if successful, -1 on error.
1132  */
1133 Int4
SC_describe(StatementClass * self)1134 SC_describe(StatementClass *self)
1135 {
1136 	Int4		num_fields = -1;
1137 	QResultClass	*res;
1138 	MYLOG(0, "entering status = %d\n", self->status);
1139 
1140 	res = SC_get_ExecdOrParsed(self);
1141 	if (NULL != res)
1142 	{
1143 		num_fields = QR_NumResultCols(res);
1144 		if (num_fields > 0 ||
1145 		    NULL != QR_get_command(res))
1146 			return num_fields;
1147 	}
1148 	if (self->status == STMT_READY)
1149 	{
1150 MYLOG(0, "              preprocess: status = READY\n");
1151 
1152 		self->miscinfo = 0;
1153 		self->execinfo = 0;
1154 
1155 		decideHowToPrepare(self, FALSE);
1156 		switch (SC_get_prepare_method(self))
1157 		{
1158 			case NAMED_PARSE_REQUEST:
1159 			case PARSE_TO_EXEC_ONCE:
1160 				if (SQL_SUCCESS != prepareParameters(self, FALSE))
1161 					return num_fields;
1162 				break;
1163 			case PARSE_REQ_FOR_INFO:
1164 				if (SQL_SUCCESS != prepareParameters(self, FALSE))
1165 					return num_fields;
1166 				self->status = STMT_DESCRIBED;
1167 				break;
1168 			default:
1169 				if (SQL_SUCCESS != prepareParameters(self, TRUE))
1170 					return num_fields;
1171 				self->status = STMT_DESCRIBED;
1172 				break;
1173 		}
1174 		if (res = SC_get_ExecdOrParsed(self), NULL != res)
1175 		{
1176 			num_fields = QR_NumResultCols(res);
1177 			return num_fields;
1178 		}
1179 	}
1180 	return num_fields;
1181 }
1182 
1183 
1184 /* This is only called from SQLFreeStmt(SQL_UNBIND) */
1185 char
SC_unbind_cols(StatementClass * self)1186 SC_unbind_cols(StatementClass *self)
1187 {
1188 	ARDFields	*opts = SC_get_ARDF(self);
1189 	GetDataInfo	*gdata = SC_get_GDTI(self);
1190 	BindInfoClass	*bookmark;
1191 
1192 	ARD_unbind_cols(opts, FALSE);
1193 	GDATA_unbind_cols(gdata, FALSE);
1194 	if (bookmark = opts->bookmark, bookmark != NULL)
1195 	{
1196 		bookmark->buffer = NULL;
1197 		bookmark->used = NULL;
1198 	}
1199 
1200 	return 1;
1201 }
1202 
1203 
1204 void
SC_clear_error(StatementClass * self)1205 SC_clear_error(StatementClass *self)
1206 {
1207 	QResultClass	*res;
1208 
1209 	self->__error_number = 0;
1210 	if (self->__error_message)
1211 	{
1212 		free(self->__error_message);
1213 		self->__error_message = NULL;
1214 	}
1215 	if (self->pgerror)
1216 	{
1217 		ER_Destructor(self->pgerror);
1218 		self->pgerror = NULL;
1219 	}
1220 	self->diag_row_count = 0;
1221 	if (res = SC_get_ExecdOrParsed(self), res)
1222 	{
1223 		QR_set_message(res, NULL);
1224 		QR_set_notice(res, NULL);
1225 		res->sqlstate[0] = '\0';
1226 	}
1227 	self->stmt_time = 0;
1228 	memset(&self->localtime, 0, sizeof(self->localtime));
1229 	self->localtime.tm_sec = -1;
1230 	SC_unref_CC_error(self);
1231 }
1232 
1233 
1234 /*
1235  *	This function creates an error info which is the concatenation
1236  *	of the result, statement, connection, and socket messages.
1237  */
1238 
1239 /*	Map sql commands to statement types */
1240 static const struct
1241 {
1242 	int		number;
1243 	const char ver3str[6];
1244 	const char ver2str[6];
1245 }	Statement_sqlstate[] =
1246 
1247 {
1248 	{ STMT_ERROR_IN_ROW, "01S01", "01S01" },
1249 	{ STMT_OPTION_VALUE_CHANGED, "01S02", "01S02" },
1250 	{ STMT_ROW_VERSION_CHANGED,  "01001", "01001" }, /* data changed */
1251 	{ STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
1252 	{ STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
1253 	{ STMT_INFO_ONLY, "00000", "00000" }, /* just an information that is returned, no error */
1254 
1255 	{ STMT_OK,  "00000", "00000" }, /* OK */
1256 	{ STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
1257 	{ STMT_STATUS_ERROR, "HY010", "S1010" },
1258 	{ STMT_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */
1259 	{ STMT_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */
1260 	{ STMT_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */
1261 	{ STMT_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */
1262 	{ STMT_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */
1263 	{ STMT_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */
1264 	{ STMT_STILL_EXECUTING, "HY010", "S1010" },
1265 	{ STMT_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not
1266 							  * capable' */
1267 	{ STMT_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" },
1268 	{ STMT_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" },
1269 	{ STMT_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
1270 	{ STMT_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
1271 	{ STMT_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
1272 	{ STMT_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
1273 	{ STMT_NO_CURSOR_NAME, "S1015", "S1015" },
1274 	{ STMT_INVALID_CURSOR_NAME, "34000", "34000" },
1275 	{ STMT_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */
1276 	{ STMT_ROW_OUT_OF_RANGE, "HY107", "S1107" },
1277 	{ STMT_OPERATION_CANCELLED, "HY008", "S1008" },
1278 	{ STMT_INVALID_CURSOR_POSITION, "HY109", "S1109" },
1279 	{ STMT_VALUE_OUT_OF_RANGE, "HY019", "22003" },
1280 	{ STMT_OPERATION_INVALID, "HY011", "S1011" },
1281 	{ STMT_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" },
1282 	{ STMT_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
1283 	{ STMT_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
1284 	{ STMT_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
1285 	{ STMT_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
1286 	{ STMT_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
1287 	{ STMT_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
1288 	{ STMT_COUNT_FIELD_INCORRECT, "07002", "07002" },
1289 	{ STMT_INVALID_NULL_ARG, "HY009", "S1009" },
1290 	{ STMT_NO_RESPONSE, "08S01", "08S01" },
1291 	{ STMT_COMMUNICATION_ERROR, "08S01", "08S01" }
1292 };
1293 
1294 static PG_ErrorInfo *
SC_create_errorinfo(const StatementClass * self,PG_ErrorInfo * pgerror_fail_safe)1295 SC_create_errorinfo(const StatementClass *self, PG_ErrorInfo *pgerror_fail_safe)
1296 {
1297 	QResultClass *res = SC_get_ExecdOrParsed(self);
1298 	ConnectionClass *conn = SC_get_conn(self);
1299 	Int4	errornum;
1300 	size_t		pos;
1301 	BOOL		resmsg = FALSE, detailmsg = FALSE, msgend = FALSE;
1302 	BOOL		looponce, loopend;
1303 	char		msg[4096], *wmsg;
1304 	char		*ermsg = NULL, *sqlstate = NULL;
1305 	PG_ErrorInfo	*pgerror;
1306 
1307 	if (self->pgerror)
1308 		return self->pgerror;
1309 	errornum = self->__error_number;
1310 	if (errornum == 0)
1311 		return	NULL;
1312 
1313 	looponce = (SC_get_Result(self) != res);
1314 	msg[0] = '\0';
1315 	for (loopend = FALSE; (NULL != res) && !loopend; res = QR_nextr(res))
1316 	{
1317 		if (looponce)
1318 			loopend = TRUE;
1319 		if ('\0' != res->sqlstate[0])
1320 		{
1321 			if (NULL != sqlstate && strnicmp(res->sqlstate, "00", 2) == 0)
1322 				continue;
1323 			sqlstate = res->sqlstate;
1324 			if (!QR_command_maybe_successful(res))
1325 				loopend = TRUE;
1326 			/*
1327 			if ('0' != sqlstate[0] ||
1328 			    '1' < sqlstate[1])
1329 				loopend = TRUE;
1330 			*/
1331 		}
1332 		if (NULL != res->message)
1333 		{
1334 			STRCPY_FIXED(msg, res->message);
1335 			detailmsg = resmsg = TRUE;
1336 		}
1337 		else if (NULL != res->messageref)
1338 		{
1339 			STRCPY_FIXED(msg, res->messageref);
1340 			detailmsg = resmsg = TRUE;
1341 		}
1342 		if (msg[0])
1343 			ermsg = msg;
1344 		else if (QR_get_notice(res))
1345 		{
1346 			char *notice = QR_get_notice(res);
1347 			size_t	len = strlen(notice);
1348 			if (len < sizeof(msg))
1349 			{
1350 				memcpy(msg, notice, len);
1351 				msg[len] = '\0';
1352 				ermsg = msg;
1353 			}
1354 			else
1355 			{
1356 				ermsg = notice;
1357 				msgend = TRUE;
1358 			}
1359 		}
1360 	}
1361 	if (!msgend && (wmsg = SC_get_errormsg(self)) && wmsg[0])
1362 	{
1363 		pos = strlen(msg);
1364 
1365 		snprintf(&msg[pos], sizeof(msg) - pos, "%s%s",
1366 				 detailmsg ? ";\n" : "",
1367 				 wmsg);
1368 		ermsg = msg;
1369 		detailmsg = TRUE;
1370 	}
1371 	if (!self->ref_CC_error)
1372 		msgend = TRUE;
1373 
1374 	if (conn && !msgend)
1375 	{
1376 		if (!resmsg && (wmsg = CC_get_errormsg(conn)) && wmsg[0] != '\0')
1377 		{
1378 			pos = strlen(msg);
1379 			snprintf(&msg[pos], sizeof(msg) - pos,
1380 					 ";\n%s", CC_get_errormsg(conn));
1381 		}
1382 
1383 		ermsg = msg;
1384 	}
1385 	pgerror = ER_Constructor(self->__error_number, ermsg);
1386 	if (!pgerror)
1387 	{
1388 		if (pgerror_fail_safe)
1389 		{
1390 			memset(pgerror_fail_safe, 0, sizeof(*pgerror_fail_safe));
1391 			pgerror = pgerror_fail_safe;
1392 			pgerror->status = self->__error_number;
1393 			pgerror->errorsize = sizeof(pgerror->__error_message);
1394 			STRCPY_FIXED(pgerror->__error_message, ermsg);
1395 			pgerror->recsize = -1;
1396 		}
1397 		else
1398 			return NULL;
1399 	}
1400 	if (sqlstate)
1401 		STRCPY_FIXED(pgerror->sqlstate, sqlstate);
1402 	else if (conn)
1403 	{
1404 		if (!msgend && conn->sqlstate[0])
1405 			STRCPY_FIXED(pgerror->sqlstate, conn->sqlstate);
1406 		else
1407 		{
1408 			EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
1409 
1410 			errornum -= LOWEST_STMT_ERROR;
1411 			if (errornum < 0 ||
1412 				errornum >= sizeof(Statement_sqlstate) / sizeof(Statement_sqlstate[0]))
1413 			{
1414 				errornum = 1 - LOWEST_STMT_ERROR;
1415 			}
1416 			STRCPY_FIXED(pgerror->sqlstate, EN_is_odbc3(env) ?
1417 				   Statement_sqlstate[errornum].ver3str :
1418 				   Statement_sqlstate[errornum].ver2str);
1419 		}
1420 	}
1421 
1422 	return pgerror;
1423 }
1424 
1425 
SC_get_ancestor(StatementClass * stmt)1426 StatementClass *SC_get_ancestor(StatementClass *stmt)
1427 {
1428 	StatementClass	*child = stmt, *parent;
1429 
1430 MYLOG(DETAIL_LOG_LEVEL, "entering stmt=%p\n", stmt);
1431 	for (child = stmt, parent = child->execute_parent; parent; child = parent, parent = child->execute_parent)
1432 	{
1433 		MYLOG(DETAIL_LOG_LEVEL, "parent=%p\n", parent);
1434 	}
1435 	return child;
1436 }
SC_reset_delegate(RETCODE retcode,StatementClass * stmt)1437 void SC_reset_delegate(RETCODE retcode, StatementClass *stmt)
1438 {
1439 	StatementClass	*delegate = stmt->execute_delegate;
1440 
1441 	if (!delegate)
1442 		return;
1443 	PGAPI_FreeStmt(delegate, SQL_DROP);
1444 }
1445 
1446 void
SC_set_error(StatementClass * self,int number,const char * message,const char * func)1447 SC_set_error(StatementClass *self, int number, const char *message, const char *func)
1448 {
1449 	if (self->__error_message)
1450 		free(self->__error_message);
1451 	self->__error_number = number;
1452 	self->__error_message = message ? strdup(message) : NULL;
1453 	if (func && number != STMT_OK && number != STMT_INFO_ONLY)
1454 		SC_log_error(func, "", self);
1455 }
1456 
1457 
1458 void
SC_set_errormsg(StatementClass * self,const char * message)1459 SC_set_errormsg(StatementClass *self, const char *message)
1460 {
1461 	if (self->__error_message)
1462 		free(self->__error_message);
1463 	self->__error_message = message ? strdup(message) : NULL;
1464 }
1465 
1466 
1467 void
SC_replace_error_with_res(StatementClass * self,int number,const char * message,const QResultClass * from_res,BOOL check)1468 SC_replace_error_with_res(StatementClass *self, int number, const char *message, const QResultClass *from_res, BOOL check)
1469 {
1470 	QResultClass	*self_res;
1471 	BOOL	repstate;
1472 
1473 MYLOG(DETAIL_LOG_LEVEL, "entering %p->%p check=%i\n", from_res ,self, check);
1474 	if (check)
1475 	{
1476 		if (0 == number)			return;
1477 		if (0 > number &&		/* SQL_SUCCESS_WITH_INFO */
1478 		    0 < self->__error_number)
1479 			return;
1480 	}
1481 	if (!from_res)
1482 		return;
1483 	self->__error_number = number;
1484 	if (!check || message)
1485 	{
1486 		if (self->__error_message)
1487 			free(self->__error_message);
1488 		self->__error_message = message ? strdup(message) : NULL;
1489 	}
1490 	if (self->pgerror)
1491 	{
1492 		ER_Destructor(self->pgerror);
1493 		self->pgerror = NULL;
1494 	}
1495 	self_res = SC_get_ExecdOrParsed(self);
1496 	if (!self_res) return;
1497 	if (self_res == from_res)	return;
1498 	QR_add_message(self_res, QR_get_message(from_res));
1499 	QR_add_notice(self_res, QR_get_notice(from_res));
1500 	repstate = FALSE;
1501 	if (!check)
1502 		repstate = TRUE;
1503 	else if (from_res->sqlstate[0])
1504 	{
1505 		if (!self_res->sqlstate[0] || strncmp(self_res->sqlstate, "00", 2) == 0)
1506 			repstate = TRUE;
1507 		else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
1508 			repstate = TRUE;
1509 	}
1510 	if (repstate)
1511 		STRCPY_FIXED(self_res->sqlstate, from_res->sqlstate);
1512 }
1513 
1514 void
SC_error_copy(StatementClass * self,const StatementClass * from,BOOL check)1515 SC_error_copy(StatementClass *self, const StatementClass *from, BOOL check)
1516 {
1517 	QResultClass	*self_res, *from_res;
1518 	BOOL	repstate;
1519 
1520 MYLOG(DETAIL_LOG_LEVEL, "entering %p->%p check=%i\n", from ,self, check);
1521 	if (!from)		return;	/* for safety */
1522 	if (self == from)	return; /* for safety */
1523 	if (check)
1524 	{
1525 		if (0 == from->__error_number)	/* SQL_SUCCESS */
1526 			return;
1527 		if (0 > from->__error_number &&	/* SQL_SUCCESS_WITH_INFO */
1528 		    0 < self->__error_number)
1529 			return;
1530 	}
1531 	self->__error_number = from->__error_number;
1532 	if (!check || from->__error_message)
1533 	{
1534 		if (self->__error_message)
1535 			free(self->__error_message);
1536 		self->__error_message = from->__error_message ? strdup(from->__error_message) : NULL;
1537 	}
1538 	if (self->pgerror)
1539 	{
1540 		ER_Destructor(self->pgerror);
1541 		self->pgerror = NULL;
1542 	}
1543 	self_res = SC_get_ExecdOrParsed(self);
1544 	from_res = SC_get_ExecdOrParsed(from);
1545 	if (!self_res || !from_res)
1546 		return;
1547 	QR_add_message(self_res, QR_get_message(from_res));
1548 	QR_add_notice(self_res, QR_get_notice(from_res));
1549 	repstate = FALSE;
1550 	if (!check)
1551 		repstate = TRUE;
1552 	else if (from_res->sqlstate[0])
1553 	{
1554 		if (!self_res->sqlstate[0] || strncmp(self_res->sqlstate, "00", 2) == 0)
1555 			repstate = TRUE;
1556 		else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
1557 			repstate = TRUE;
1558 	}
1559 	if (repstate)
1560 		STRCPY_FIXED(self_res->sqlstate, from_res->sqlstate);
1561 }
1562 
1563 
1564 void
SC_full_error_copy(StatementClass * self,const StatementClass * from,BOOL allres)1565 SC_full_error_copy(StatementClass *self, const StatementClass *from, BOOL allres)
1566 {
1567 	PG_ErrorInfo		*pgerror;
1568 
1569 MYLOG(DETAIL_LOG_LEVEL, "entering %p->%p\n", from ,self);
1570 	if (!from)		return;	/* for safety */
1571 	if (self == from)	return; /* for safety */
1572 	if (self->__error_message)
1573 	{
1574 		free(self->__error_message);
1575 		self->__error_message = NULL;
1576 	}
1577 	if (from->__error_message)
1578 		self->__error_message = strdup(from->__error_message);
1579 	self->__error_number = from->__error_number;
1580 	if (from->pgerror)
1581 	{
1582 		if (self->pgerror)
1583 			ER_Destructor(self->pgerror);
1584 		self->pgerror = ER_Dup(from->pgerror);
1585 		return;
1586 	}
1587 	else if (!allres)
1588 		return;
1589 	pgerror = SC_create_errorinfo(from, NULL);
1590 	if (!pgerror || !pgerror->__error_message[0])
1591 	{
1592 		ER_Destructor(pgerror);
1593 		return;
1594 	}
1595 	if (self->pgerror)
1596 		ER_Destructor(self->pgerror);
1597 	self->pgerror = pgerror;
1598 }
1599 
1600 /* Returns the next SQL error information. */
1601 RETCODE		SQL_API
PGAPI_StmtError(SQLHSTMT hstmt,SQLSMALLINT RecNumber,SQLCHAR * szSqlState,SQLINTEGER * pfNativeError,SQLCHAR * szErrorMsg,SQLSMALLINT cbErrorMsgMax,SQLSMALLINT * pcbErrorMsg,UWORD flag)1602 PGAPI_StmtError(SQLHSTMT	hstmt,
1603 				SQLSMALLINT RecNumber,
1604 				SQLCHAR * szSqlState,
1605 				SQLINTEGER * pfNativeError,
1606 				SQLCHAR * szErrorMsg,
1607 				SQLSMALLINT cbErrorMsgMax,
1608 				SQLSMALLINT * pcbErrorMsg,
1609 				UWORD flag)
1610 {
1611 	/* CC: return an error of a hdesc  */
1612 	PG_ErrorInfo		*pgerror, error;
1613 	StatementClass *stmt = (StatementClass *) hstmt;
1614 	int errnum = SC_get_errornumber(stmt);
1615 
1616 	if (pgerror = SC_create_errorinfo(stmt, &error), NULL == pgerror)
1617 		return SQL_NO_DATA_FOUND;
1618 	if (pgerror != &error)
1619 		stmt->pgerror = pgerror;
1620 	if (STMT_NO_MEMORY_ERROR == errnum &&
1621 	    !pgerror->__error_message[0])
1622 		STRCPY_FIXED(pgerror->__error_message, "Memory Allocation Error??");
1623 	return ER_ReturnError(pgerror, RecNumber, szSqlState,
1624 						  pfNativeError, szErrorMsg, cbErrorMsgMax,
1625 						  pcbErrorMsg, flag);
1626 }
1627 
1628 time_t
SC_get_time(StatementClass * stmt)1629 SC_get_time(StatementClass *stmt)
1630 {
1631 	if (!stmt)
1632 		return time(NULL);
1633 	if (0 == stmt->stmt_time)
1634 		stmt->stmt_time = time(NULL);
1635 	return stmt->stmt_time;
1636 }
1637 
1638 struct tm *
SC_get_localtime(StatementClass * stmt)1639 SC_get_localtime(StatementClass *stmt)
1640 {
1641 #ifndef HAVE_LOCALTIME_R
1642 	struct tm * tim;
1643 #endif /* HAVE_LOCALTIME_R */
1644 
1645 	if (stmt->localtime.tm_sec < 0)
1646 	{
1647 		SC_get_time(stmt);
1648 #ifdef HAVE_LOCALTIME_R
1649 		localtime_r(&stmt->stmt_time, &(stmt->localtime));
1650 #else
1651 		tim = localtime(&stmt->stmt_time);
1652 		stmt->localtime = *tim;
1653 #endif /* HAVE_LOCALTIME_R */
1654 	}
1655 
1656 	return &(stmt->localtime);
1657 }
1658 
1659 RETCODE
SC_fetch(StatementClass * self)1660 SC_fetch(StatementClass *self)
1661 {
1662 	CSTR func = "SC_fetch";
1663 	QResultClass *res = SC_get_Curres(self);
1664 	ARDFields	*opts;
1665 	GetDataInfo	*gdata;
1666 	int		retval;
1667 	RETCODE		result;
1668 
1669 	Int2		num_cols,
1670 				lf;
1671 	OID			type;
1672 	int		atttypmod;
1673 	char	   *value;
1674 	ColumnInfoClass *coli;
1675 	BindInfoClass	*bookmark;
1676 	BOOL		useCursor;
1677 	KeySet		*keyset = NULL;
1678 
1679 	/* TupleField *tupleField; */
1680 
1681 MYLOG(DETAIL_LOG_LEVEL, "entering statement=%p res=%p ommitted=0\n", self, res);
1682 	self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
1683 	if (!res)
1684 		return SQL_ERROR;
1685 	coli = QR_get_fields(res);	/* the column info */
1686 
1687 	MYLOG(0, "fetch_cursor=%d, %p->total_read=" FORMAT_LEN "\n", SC_is_fetchcursor(self), res, res->num_total_read);
1688 
1689 	useCursor = (SC_is_fetchcursor(self) && (NULL != QR_get_cursor(res)));
1690 	if (!useCursor)
1691 	{
1692 		if (self->currTuple >= (Int4) QR_get_num_total_tuples(res) - 1 ||
1693 			(self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
1694 		{
1695 			/*
1696 			 * if at the end of the tuples, return "no data found" and set
1697 			 * the cursor past the end of the result set
1698 			 */
1699 			self->currTuple = QR_get_num_total_tuples(res);
1700 			return SQL_NO_DATA_FOUND;
1701 		}
1702 
1703 		MYLOG(0, "**** : non-cursor_result\n");
1704 		(self->currTuple)++;
1705 	}
1706 	else
1707 	{
1708 		/* read from the cache or the physical next tuple */
1709 		retval = QR_next_tuple(res, self);
1710 		if (retval < 0)
1711 		{
1712 			MYLOG(0, "**** : end_tuples\n");
1713 			if (QR_get_cursor(res) &&
1714 			    SQL_CURSOR_FORWARD_ONLY == self->options.cursor_type &&
1715 			    QR_once_reached_eof(res))
1716 				QR_close(res);
1717 			return SQL_NO_DATA_FOUND;
1718 		}
1719 		else if (retval > 0)
1720 			(self->currTuple)++;	/* all is well */
1721 		else
1722 		{
1723 			SC_set_errorinfo(self, res, 1);
1724 			return SQL_ERROR;
1725 		}
1726 	}
1727 	if (QR_haskeyset(res))
1728 	{
1729 		SQLLEN	kres_ridx;
1730 
1731 		kres_ridx = GIdx2KResIdx(self->currTuple, self, res);
1732 		if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
1733 		{
1734 			UWORD	pstatus = res->keyset[kres_ridx].status;
1735 MYLOG(DETAIL_LOG_LEVEL, "SC_ pstatus[" FORMAT_LEN "]=%hx fetch_count=" FORMAT_LEN "\n", kres_ridx, pstatus, self->last_fetch_count);
1736 			if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
1737 				return SQL_SUCCESS_WITH_INFO;
1738 			if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
1739 				0 != (pstatus & CURS_OTHER_DELETED))
1740 			{
1741 				return SQL_SUCCESS_WITH_INFO;
1742 			}
1743 			if (0 != (CURS_NEEDS_REREAD & pstatus))
1744 			{
1745 				UWORD	qcount;
1746 
1747 				result = SC_pos_reload(self, self->currTuple, &qcount, 0);
1748 				if (SQL_ERROR == result)
1749 					return result;
1750 				pstatus &= ~CURS_NEEDS_REREAD;
1751 			}
1752 			keyset =  res->keyset + kres_ridx;
1753 		}
1754 	}
1755 
1756 	num_cols = QR_NumPublicResultCols(res);
1757 
1758 	result = SQL_SUCCESS;
1759 	self->last_fetch_count++;
1760 MYLOG(DETAIL_LOG_LEVEL, "stmt=%p ommitted++\n", self);
1761 	self->last_fetch_count_include_ommitted++;
1762 
1763 	opts = SC_get_ARDF(self);
1764 	/*
1765 	 * If the bookmark column was bound then return a bookmark. Since this
1766 	 * is used with SQLExtendedFetch, and the rowset size may be greater
1767 	 * than 1, and an application can use row or column wise binding, use
1768 	 * the code in copy_and_convert_field() to handle that.
1769 	 */
1770 	if ((bookmark = opts->bookmark) && bookmark->buffer)
1771 	{
1772 		SC_set_current_col(self, -1);
1773 		SC_Create_bookmark(self, bookmark, self->bind_row, self->currTuple, keyset);
1774 	}
1775 
1776 	if (self->options.retrieve_data == SQL_RD_OFF)		/* data isn't required */
1777 		return SQL_SUCCESS;
1778 	/* The following adjustment would be needed after SQLMoreResults() */
1779 	if (opts->allocated < num_cols)
1780 		extend_column_bindings(opts, num_cols);
1781 	gdata = SC_get_GDTI(self);
1782 	if (gdata->allocated != opts->allocated)
1783 		extend_getdata_info(gdata, opts->allocated, TRUE);
1784 	for (lf = 0; lf < num_cols; lf++)
1785 	{
1786 		MYLOG(0, "fetch: cols=%d, lf=%d, opts = %p, opts->bindings = %p, buffer[] = %p\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
1787 
1788 		/* reset for SQLGetData */
1789 		GETDATA_RESET(gdata->gdata[lf]);
1790 
1791 		if (NULL == opts->bindings)
1792 			continue;
1793 		if (opts->bindings[lf].buffer != NULL)
1794 		{
1795 			/* this column has a binding */
1796 
1797 			/* type = QR_get_field_type(res, lf); */
1798 			type = CI_get_oid(coli, lf);		/* speed things up */
1799 			atttypmod = CI_get_atttypmod(coli, lf);	/* speed things up */
1800 
1801 			MYLOG(0, "type = %d, atttypmod = %d\n", type, atttypmod);
1802 
1803 			if (useCursor)
1804 				value = QR_get_value_backend(res, lf);
1805 			else
1806 			{
1807 				SQLLEN	curt = GIdx2CacheIdx(self->currTuple, self, res);
1808 MYLOG(DETAIL_LOG_LEVEL, "%p->base=" FORMAT_LEN " curr=" FORMAT_LEN " st=" FORMAT_LEN " valid=%d\n", res, QR_get_rowstart_in_cache(res), self->currTuple, SC_get_rowset_start(self), QR_has_valid_base(res));
1809 MYLOG(DETAIL_LOG_LEVEL, "curt=" FORMAT_LEN "\n", curt);
1810 				value = QR_get_value_backend_row(res, curt, lf);
1811 			}
1812 
1813 			MYLOG(0, "value = '%s'\n", (value == NULL) ? "<NULL>" : value);
1814 
1815 			retval = copy_and_convert_field_bindinfo(self, type, atttypmod, value, lf);
1816 
1817 			MYLOG(0, "copy_and_convert: retval = %d\n", retval);
1818 
1819 			switch (retval)
1820 			{
1821 				case COPY_OK:
1822 					break;		/* OK, do next bound column */
1823 
1824 				case COPY_UNSUPPORTED_TYPE:
1825 					SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
1826 					result = SQL_ERROR;
1827 					break;
1828 
1829 				case COPY_UNSUPPORTED_CONVERSION:
1830 					SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
1831 					result = SQL_ERROR;
1832 					break;
1833 
1834 				case COPY_RESULT_TRUNCATED:
1835 					SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.", func);
1836 					MYLOG(DETAIL_LOG_LEVEL, "The %dth item was truncated\n", lf + 1);
1837 					MYLOG(DETAIL_LOG_LEVEL, "The buffer size = " FORMAT_LEN, opts->bindings[lf].buflen);
1838 					MYLOG(DETAIL_LOG_LEVEL, " and the value is '%s'\n", value);
1839 					result = SQL_SUCCESS_WITH_INFO;
1840 					break;
1841 
1842 				case COPY_INVALID_STRING_CONVERSION:    /* invalid string */
1843 					SC_set_error(self, STMT_STRING_CONVERSION_ERROR, "invalid string conversion occured.", func);
1844 					result = SQL_ERROR;
1845 					break;
1846 
1847 					/* error msg already filled in */
1848 				case COPY_GENERAL_ERROR:
1849 					result = SQL_ERROR;
1850 					break;
1851 
1852 					/* This would not be meaningful in SQLFetch. */
1853 				case COPY_NO_DATA_FOUND:
1854 					break;
1855 
1856 				default:
1857 					SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
1858 					result = SQL_ERROR;
1859 					break;
1860 			}
1861 		}
1862 	}
1863 
1864 	return result;
1865 }
1866 
1867 
1868 #include "dlg_specific.h"
1869 RETCODE
SC_execute(StatementClass * self)1870 SC_execute(StatementClass *self)
1871 {
1872 	CSTR func = "SC_execute";
1873 	ConnectionClass *conn;
1874 	IPDFields	*ipdopts;
1875 	char		was_ok, was_nonfatal;
1876 	Int2		oldstatus,
1877 				numcols;
1878 	QueryInfo	qi;
1879 	ConnInfo   *ci;
1880 	unsigned int	qflag = 0;
1881 	BOOL		is_in_trans, issue_begin, has_out_para;
1882 	BOOL		use_extended_protocol;
1883 	int		func_cs_count = 0, i;
1884 	BOOL		useCursor, isSelectType;
1885 	int		errnum_sav = STMT_OK, errnum;
1886 	char		*errmsg_sav = NULL;
1887 	SQLULEN		stmt_timeout;
1888 	QResultHold	rhold = {0};
1889 
1890 	conn = SC_get_conn(self);
1891 	ci = &(conn->connInfo);
1892 
1893 	errnum_sav = SC_get_errornumber(self);
1894 	errmsg_sav = SC_get_errormsg(self);
1895 	if (NULL != errmsg_sav)
1896 		errmsg_sav = strdup(errmsg_sav);
1897 	SC_set_error(self, STMT_OK, NULL, __FUNCTION__);
1898 
1899 	/* Begin a transaction if one is not already in progress */
1900 
1901 	/*
1902 	 * Basically we don't have to begin a transaction in autocommit mode
1903 	 * because Postgres backend runs in autocomit mode. We issue "BEGIN"
1904 	 * in the following cases. 1) we use declare/fetch and the statement
1905 	 * is SELECT (because declare/fetch must be called in a transaction).
1906 	 * 2) we are in autocommit off state and the statement isn't of type
1907 	 * OTHER.
1908 	 */
1909 #define	return	DONT_CALL_RETURN_FROM_HERE???
1910 	ENTER_INNER_CONN_CS(conn, func_cs_count);
1911 	oldstatus = conn->status;
1912 	if (CONN_EXECUTING == conn->status)
1913 	{
1914 		SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.", func);
1915 		MYLOG(0, "problem with connection\n");
1916 		goto cleanup;
1917 	}
1918 	is_in_trans = CC_is_in_trans(conn);
1919 	if ((useCursor = SC_is_fetchcursor(self)))
1920 	{
1921 		QResultClass *curres = SC_get_Curres(self);
1922 
1923 		if (NULL != curres &&
1924 		    curres->dataFilled)
1925 			useCursor = (NULL != QR_get_cursor(curres));
1926 	}
1927 	/* issue BEGIN ? */
1928 	issue_begin = TRUE;
1929 	if (!self->external)
1930 		issue_begin = FALSE;
1931 	else if (is_in_trans)
1932 	{
1933 		issue_begin = FALSE;
1934 		if (STMT_TYPE_START == self->statement_type &&
1935 		    CC_does_autocommit(conn))
1936 		{
1937 			CC_commit(conn);
1938 			is_in_trans = CC_is_in_trans(conn);
1939 		}
1940 	}
1941 	else if (CC_does_autocommit(conn) &&
1942 		 (!useCursor
1943 	    /* || SC_is_with_hold(self) thiw would lose the performance */
1944 		 ))
1945 		issue_begin = FALSE;
1946 	else if (self->statement_type == STMT_TYPE_SPECIAL)
1947 	{
1948 		/*
1949 		 * Some utility commands like VACUUM cannot be run in a transaction
1950 		 * block, so don't begin one even if auto-commit mode is disabled.
1951 		 *
1952 		 * An application should never issue an explicit BEGIN when
1953 		 * auto-commit mode is disabled (probably not even when it's enabled,
1954 		 * actually). We used to also suppress the implicit BEGIN when the
1955 		 * statement was of STMT_TYPE_START type, ie. if the application
1956 		 * issued an explicit BEGIN, but that actually seems like a bad idea.
1957 		 * First of all, if you issue a BEGIN twice the backend will give a
1958 		 * warning which can be helpful to spot mistakes in the application
1959 		 * (because it shouldn't be doing that).
1960 		 */
1961 		issue_begin = FALSE;
1962 	}
1963 	if (issue_begin)
1964 	{
1965 		MYLOG(0, "   about to begin a transaction on statement = %p\n", self);
1966 		qflag |= GO_INTO_TRANSACTION;
1967 	}
1968 
1969 	/*
1970 	 * If the session query timeout setting differs from the statement one,
1971 	 * change it.
1972 	 */
1973 	stmt_timeout = conn->connInfo.ignore_timeout ? 0 : self->options.stmt_timeout;
1974 	if (conn->stmt_timeout_in_effect != stmt_timeout)
1975 	{
1976 		char query[64];
1977 		QResultClass *res;
1978 
1979 		SPRINTF_FIXED(query, "SET statement_timeout = %d",
1980 				 (int) stmt_timeout * 1000);
1981 		res = CC_send_query(conn, query, NULL, 0, NULL);
1982 		if (QR_command_maybe_successful(res))
1983 			conn->stmt_timeout_in_effect = stmt_timeout;
1984 		QR_Destructor(res);
1985 	}
1986 
1987 	if (!SC_SetExecuting(self, TRUE))
1988 	{
1989 		SC_set_error(self, STMT_OPERATION_CANCELLED, "Cancel Reuest Accepted", func);
1990 		goto cleanup;
1991 	}
1992 	conn->status = CONN_EXECUTING;
1993 
1994 	/* If it's a SELECT statement, use a cursor. */
1995 
1996 	/*
1997 	 * Note that the declare cursor has already been prepended to the
1998 	 * statement
1999 	 */
2000 	/* in copy_statement... */
2001 	if (self->stmt_with_params)
2002 		use_extended_protocol = FALSE;
2003 	else
2004 	{
2005 		use_extended_protocol = TRUE;
2006 	}
2007 	isSelectType = (SC_may_use_cursor(self) || self->statement_type == STMT_TYPE_PROCCALL);
2008 	if (use_extended_protocol)
2009 	{
2010 		QResultClass *first;
2011 
2012 		if (issue_begin)
2013 			CC_begin(conn);
2014 
2015 		first = libpq_bind_and_exec(self);
2016 		if (!first)
2017 		{
2018 			if (SC_get_errornumber(self) <= 0)
2019 			{
2020 				SC_set_error(self, STMT_NO_RESPONSE, "Could not receive the response, communication down ??", func);
2021 			}
2022 			goto cleanup;
2023 		}
2024 		rhold.first = rhold.last = first;
2025 	}
2026 	else if (isSelectType)
2027 	{
2028 		char		fetch[128];
2029 		const char *appendq = NULL;
2030 		QueryInfo	*qryi = NULL;
2031 		QResultClass *first;
2032 
2033 		qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0);
2034 		MYLOG(0, "       Sending SELECT statement on stmt=%p, cursor_name='%s' qflag=%d," FORMAT_UINTEGER "\n", self, SC_cursor_name(self), qflag, self->options.scroll_concurrency);
2035 
2036 		/* send the declare/select */
2037 		if (useCursor)
2038 		{
2039 			qi.result_in = NULL;
2040 			qi.cursor = SC_cursor_name(self);
2041 			qi.fetch_size = qi.row_size = ci->drivers.fetch_max;
2042 			SPRINTF_FIXED(fetch,
2043 					 "fetch " FORMAT_LEN " in \"%s\"",
2044 					 qi.fetch_size, SC_cursor_name(self));
2045 			qryi = &qi;
2046 			appendq = fetch;
2047 			qflag &= (~READ_ONLY_QUERY); /* must be a SAVEPOINT after DECLARE */
2048 		}
2049 		rhold = CC_send_query_append(conn, self->stmt_with_params, qryi, qflag, SC_get_ancestor(self), appendq);
2050 		first = rhold.first;
2051 		if (useCursor && QR_command_maybe_successful(first))
2052 		{
2053 			/*
2054 			 * If we sent a DECLARE CURSOR + FETCH, throw away the result of
2055 			 * the DECLARE CURSOR statement, and only return the result of the
2056 			 * FETCH to the caller. However, if we received any NOTICEs as
2057 			 * part of the DECLARE CURSOR, carry those over.
2058 			 */
2059 			if (appendq)
2060 			{
2061 				QResultClass	*qres, *nres;
2062 
2063 				for (qres = first; qres;)
2064 				{
2065 					if (qres->command && strnicmp(qres->command, "fetch", 5) == 0)
2066 					{
2067 						break;
2068 					}
2069 					nres = QR_nextr(qres);
2070 					if (nres && QR_get_notice(qres) != NULL)
2071 					{
2072 						if (QR_command_successful(nres) &&
2073 							QR_command_nonfatal(qres))
2074 						{
2075 							QR_set_rstatus(nres, PORES_NONFATAL_ERROR);
2076 						}
2077 						QR_add_notice(nres, QR_get_notice(qres));
2078 					}
2079 					QR_detach(qres);
2080 					QR_Destructor(qres);
2081 					qres = nres;
2082 
2083 					/*
2084 					 * If we received fewer rows than requested, there are no
2085 					 * more rows to fetch.
2086 					 */
2087 					if (qres && qres->num_cached_rows < qi.row_size) /* check qres != NULL for safety */
2088 						QR_set_reached_eof(qres);
2089 				}
2090 				first = qres;
2091 				rhold.first = first;
2092 			}
2093 			if (first && SC_is_with_hold(self))
2094 				QR_set_withhold(first);
2095 		}
2096 		MYLOG(0, "     done sending the query:\n");
2097 	}
2098 	else
2099 	{
2100 		/* not a SELECT statement so don't use a cursor */
2101 		MYLOG(0, "      it's NOT a select statement: stmt=%p\n", self);
2102 		rhold = CC_send_query_append(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self), NULL);
2103 	}
2104 
2105 	if (!isSelectType)
2106 	{
2107 		/*
2108 		 * We shouldn't send COMMIT. Postgres backend does the autocommit
2109 		 * if neccessary. (Zoltan, 04/26/2000)
2110 		 */
2111 
2112 		/*
2113 		 * Above seems wrong. Even in case of autocommit, started
2114 		 * transactions must be committed. (Hiroshi, 02/11/2001)
2115 		 */
2116 		if (CC_is_in_trans(conn))
2117 		{
2118 			if (!is_in_trans)
2119 				CC_set_in_manual_trans(conn);
2120 			if (self->external && CC_does_autocommit(conn))
2121 				CC_commit(conn);
2122 		}
2123 	}
2124 
2125 	if (CONN_DOWN != conn->status)
2126 		conn->status = oldstatus;
2127 	self->status = STMT_FINISHED;
2128 MYLOG(0, "set %p STMT_FINISHED\n", self);
2129 	LEAVE_INNER_CONN_CS(func_cs_count, conn);
2130 
2131 	/* Check the status of the result */
2132 	if (rhold.first)
2133 	{
2134 		QResultClass *first = rhold.first;
2135 
2136 		was_ok = QR_command_successful(first);
2137 		was_nonfatal = QR_command_nonfatal(first);
2138 
2139 		if (0 < SC_get_errornumber(self))
2140 			;
2141 		else if (was_ok)
2142 		{
2143 			if (self->has_notice &&
2144 			    0 == SC_get_errornumber(self))
2145 				SC_set_errornumber(self, STMT_INFO_ONLY);
2146 		}
2147 		else if (was_nonfatal)
2148 		{
2149 			self->has_notice = 1;
2150 			if (0 == SC_get_errornumber(self))
2151 				SC_set_errornumber(self, STMT_INFO_ONLY);
2152 		}
2153 		else
2154 			SC_set_errorinfo(self, first, 0);
2155 		/* set cursor before the first tuple in the list */
2156 		self->currTuple = -1;
2157 		SC_set_current_col(self, -1);
2158 		SC_set_rowset_start(self, -1, FALSE);
2159 
2160 		/* issue "ABORT" when query aborted */
2161 		if (QR_get_aborted(first))
2162 		{
2163 		}
2164 		else
2165 		{
2166 			QResultClass	*tres;
2167 
2168 			/* see if the query did return any result columns */
2169 			for (tres = first, numcols = 0; !numcols && tres; tres = QR_nextr(tres))
2170 			{
2171 				numcols = QR_NumResultCols(tres);
2172 			}
2173 			/* now allocate the array to hold the binding info */
2174 			if (numcols > 0)
2175 			{
2176 				ARDFields	*opts = SC_get_ARDF(self);
2177 				extend_column_bindings(opts, numcols);
2178 				if (opts->bindings == NULL)
2179 				{
2180 					QR_Destructor(first);
2181 					SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information", func);
2182 					goto cleanup;
2183 				}
2184 			}
2185 
2186 MYLOG(DETAIL_LOG_LEVEL, "!!%p->miscinfo=%x res=%p\n", self, self->miscinfo, first);
2187 			/*
2188 			 * special handling of result for keyset driven cursors.
2189 			 * Use the columns info of the 1st query and
2190 			 * user the keyset info of the 2nd query.
2191 			 */
2192 			if (SQL_CURSOR_KEYSET_DRIVEN == self->options.cursor_type &&
2193 			    SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency &&
2194 			    !useCursor)
2195 			{
2196 				if (tres = QR_nextr(first), tres)
2197 				{
2198 					QR_set_fields(tres, QR_get_fields(first));
2199 					QR_set_fields(first,  NULL);
2200 					tres->num_fields = first->num_fields;
2201 					QR_detach(first);
2202 					SC_set_Result(self, tres);
2203 					rhold = self->rhold;
2204 				}
2205 			}
2206 		}
2207 	}
2208 	else
2209 	{
2210 		/* Bad Error -- The error message will be in the Connection */
2211 		if (!conn->pqconn)
2212 			SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn), func);
2213 		else if (self->statement_type == STMT_TYPE_CREATE)
2214 		{
2215 			SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table", func);
2216 
2217 			/*
2218 			 * This would allow the table to already exists, thus
2219 			 * appending rows to it.  BUT, if the table didn't have the
2220 			 * same attributes, it would fail. return
2221 			 * SQL_SUCCESS_WITH_INFO;
2222 			 */
2223 		}
2224 		else
2225 		{
2226 			SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn), func);
2227 		}
2228 
2229 	}
2230 	if (!SC_get_Result(self))
2231 		SC_set_ResultHold(self, rhold);
2232 	else
2233 	{
2234 		if (self->rhold.last != rhold.first)
2235 			QR_concat(self->rhold.last, rhold.first);
2236 		self->rhold.last = rhold.last;
2237 	}
2238 	if (NULL == SC_get_Curres(self))
2239 		SC_set_Curres(self, SC_get_Result(self));
2240 
2241 	if (self->statement_type == STMT_TYPE_PROCCALL &&
2242 		(SC_get_errornumber(self) == STMT_OK ||
2243 		 SC_get_errornumber(self) == STMT_INFO_ONLY))
2244 	{
2245 		Int2	io, out;
2246 		has_out_para = (CountParameters(self, NULL, &io, &out) > 0);
2247 		if (has_out_para)
2248 		{	/* get the return value of the procedure call */
2249 			RETCODE		ret;
2250 			HSTMT		hstmt = (HSTMT) self;
2251 
2252 			ipdopts = SC_get_IPDF(self);
2253 			self->bind_row = 0;
2254 			ret = SC_fetch(hstmt);
2255 MYLOG(DETAIL_LOG_LEVEL, "!!SC_fetch return =%d\n", ret);
2256 			if (SQL_SUCCEEDED(ret))
2257 			{
2258 				APDFields	*apdopts = SC_get_APDF(self);
2259 				SQLULEN		offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
2260 				ARDFields	*ardopts = SC_get_ARDF(self);
2261 				const ParameterInfoClass	*apara;
2262 				const ParameterImplClass	*ipara;
2263 				int	save_bind_size = ardopts->bind_size, gidx, num_p;
2264 
2265 				ardopts->bind_size = apdopts->param_bind_type;
2266 				num_p = self->num_params;
2267 				if (ipdopts->allocated < num_p)
2268 					num_p = ipdopts->allocated;
2269 				for (i = 0, gidx = 0; i < num_p; i++)
2270 				{
2271 					int icol = gidx;
2272 					ipara = ipdopts->parameters + i;
2273 					if (ipara->paramType == SQL_PARAM_OUTPUT ||
2274 					    ipara->paramType == SQL_PARAM_INPUT_OUTPUT)
2275 					{
2276 						if (NAME_IS_VALID(ipara->paramName))
2277 						{
2278 							icol = QR_search_by_fieldname(rhold.first, GET_NAME(ipara->paramName));
2279 							if (icol < 0)
2280 							{
2281 								SC_set_error(self, STMT_EXEC_ERROR, "Named output parameter does not exist.", func);
2282 								break;
2283 							}
2284 						}
2285 						apara = apdopts->parameters + i;
2286 						ret = PGAPI_GetData(hstmt, icol + 1, apara->CType, apara->buffer + offset, apara->buflen, apara->used ? LENADDR_SHIFT(apara->used, offset) : NULL);
2287 						if (!SQL_SUCCEEDED(ret))
2288 						{
2289 							SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.", func);
2290 							break;
2291 						}
2292 						gidx++;
2293 					}
2294 				}
2295 				ardopts->bind_size = save_bind_size; /* restore */
2296 			}
2297 			else
2298 			{
2299 				SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed.", func);
2300 			}
2301 		}
2302 
2303 		if (ci->fetch_refcursors)
2304 		{
2305 			char			fetch[128];
2306 			QResultClass 	*last = NULL, *res;
2307 
2308 			/* Iterate the columns in the result to look for refcursors */
2309 			numcols = QR_NumResultCols(rhold.first);
2310 			for (i = 0; i < numcols; i++)
2311 			{
2312 				MYLOG(DETAIL_LOG_LEVEL, "!!! numfield=%d field_type=%u\n", numcols, QR_get_field_type(rhold.first, i));
2313 				if (PG_TYPE_REFCURSOR == QR_get_field_type(rhold.first, i))
2314 				{
2315 					if (!CC_is_in_trans(conn))
2316 					{
2317 						SC_set_error(self, STMT_EXEC_ERROR, "Query must be executed in a transaction when FetchRefcursors setting is enabled.", func);
2318 						break;
2319 					}
2320 
2321 					STR_TO_NAME(self->cursor_name, QR_get_value_backend_text(rhold.first, 0, i));
2322 					SC_set_fetchcursor(self);
2323 					qi.result_in = NULL;
2324 					qi.cursor = SC_cursor_name(self);
2325 					qi.fetch_size = qi.row_size = ci->drivers.fetch_max;
2326 					SPRINTF_FIXED(fetch, "fetch " FORMAT_LEN " in \"%s\"", qi.fetch_size, SC_cursor_name(self));
2327 					res = CC_send_query(conn, fetch, &qi, qflag | READ_ONLY_QUERY, SC_get_ancestor(self));
2328 					if (NULL != res)
2329 					{
2330 						if (NULL == last)
2331 						{
2332 							/* Reinitialise with result fetched from first refcursor */
2333 							SC_init_Result(self);
2334 							SC_set_Result(self, res);
2335 						}
2336 						else
2337 						{
2338 							/* Add another result fetched from the next refcursor */
2339 							QR_concat(last, res);
2340 							self->multi_statement = TRUE;
2341 						}
2342 						if (!QR_command_maybe_successful(res))
2343 						{
2344 							SC_set_errorinfo(self, res, 0);
2345 							QR_Destructor(rhold.first);
2346 							break;
2347 						}
2348 
2349 						last = res;
2350 					}
2351 				}
2352 			}
2353 			if (last)
2354 				QR_Destructor(rhold.first);
2355 		}
2356 	}
2357 cleanup:
2358 #undef	return
2359 	SC_SetExecuting(self, FALSE);
2360 	CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
2361 	if (CONN_DOWN != conn->status)
2362 		conn->status = oldstatus;
2363 	/* self->status = STMT_FINISHED; */
2364 	errnum = SC_get_errornumber(self);
2365 	if (errnum_sav > STMT_OK)
2366 		SC_set_error(self, errnum_sav, errmsg_sav, NULL);
2367 	else if (errnum > STMT_OK)
2368 		;
2369 	else if (errnum_sav < STMT_OK)
2370 		SC_set_error(self, errnum_sav, errmsg_sav, NULL);
2371 	if (NULL != errmsg_sav)
2372 		free(errmsg_sav);
2373 
2374 	if (errnum == STMT_OK)
2375 		return SQL_SUCCESS;
2376 	else if (errnum < STMT_OK)
2377 		return SQL_SUCCESS_WITH_INFO;
2378 	else
2379 	{
2380 		char *errmsg = SC_get_errormsg(self);
2381 		if (!errmsg || !errmsg[0])
2382 		{
2383 			if (STMT_NO_MEMORY_ERROR != errnum)
2384 				SC_set_errormsg(self, "Error while executing the query");
2385 			SC_log_error(func, NULL, self);
2386 		}
2387 		return SQL_ERROR;
2388 	}
2389 }
2390 
2391 #define	CALLBACK_ALLOC_ONCE	4
enqueueNeedDataCallback(StatementClass * stmt,NeedDataCallfunc func,void * data)2392 int enqueueNeedDataCallback(StatementClass *stmt, NeedDataCallfunc func, void *data)
2393 {
2394 	if (stmt->num_callbacks >= stmt->allocated_callbacks)
2395 	{
2396 		SC_REALLOC_return_with_error(stmt->callbacks, NeedDataCallback,
2397 			sizeof(NeedDataCallback) * (stmt->allocated_callbacks +
2398 				CALLBACK_ALLOC_ONCE), stmt, "NeedDataCallback enqueue error", 0);
2399 		stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE;
2400 	}
2401 	stmt->callbacks[stmt->num_callbacks].func = func;
2402 	stmt->callbacks[stmt->num_callbacks].data = data;
2403 	stmt->num_callbacks++;
2404 
2405 MYLOG(DETAIL_LOG_LEVEL, "stmt=%p, func=%p, count=%d\n", stmt, func, stmt->num_callbacks);
2406 	return stmt->num_callbacks;
2407 }
2408 
dequeueNeedDataCallback(RETCODE retcode,StatementClass * stmt)2409 RETCODE dequeueNeedDataCallback(RETCODE retcode, StatementClass *stmt)
2410 {
2411 	RETCODE			ret;
2412 	NeedDataCallfunc	func;
2413 	void			*data;
2414 	int			i, cnt;
2415 
2416 	MYLOG(0, "entering ret=%d count=%d\n", retcode, stmt->num_callbacks);
2417 	if (SQL_NEED_DATA == retcode)
2418 		return retcode;
2419 	if (stmt->num_callbacks <= 0)
2420 		return retcode;
2421 	func = stmt->callbacks[0].func;
2422 	data = stmt->callbacks[0].data;
2423 	for (i = 1; i < stmt->num_callbacks; i++)
2424 		stmt->callbacks[i - 1] = stmt->callbacks[i];
2425 	cnt = --stmt->num_callbacks;
2426 	ret = (*func)(retcode, data);
2427 	free(data);
2428 	if (SQL_NEED_DATA != ret && cnt > 0)
2429 		ret = dequeueNeedDataCallback(ret, stmt);
2430 	return ret;
2431 }
2432 
cancelNeedDataState(StatementClass * stmt)2433 void	cancelNeedDataState(StatementClass *stmt)
2434 {
2435 	int	cnt = stmt->num_callbacks, i;
2436 
2437 	stmt->num_callbacks = 0;
2438 	for (i = 0; i < cnt; i++)
2439 	{
2440 		if (stmt->callbacks[i].data)
2441 			free(stmt->callbacks[i].data);
2442 	}
2443 	SC_reset_delegate(SQL_ERROR, stmt);
2444 }
2445 
2446 void
SC_log_error(const char * func,const char * desc,const StatementClass * self)2447 SC_log_error(const char *func, const char *desc, const StatementClass *self)
2448 {
2449 	const	char *head;
2450 #define NULLCHECK(a) (a ? a : "(NULL)")
2451 	if (self)
2452 	{
2453 		QResultClass *res = SC_get_Result(self);
2454 		const ARDFields	*opts = SC_get_ARDF(self);
2455 		const APDFields	*apdopts = SC_get_APDF(self);
2456 		SQLLEN	rowsetSize;
2457 		const int level = 9;
2458 
2459 		rowsetSize = (STMT_TRANSITION_EXTENDED_FETCH == self->transition_status ? opts->size_of_rowset_odbc2 : opts->size_of_rowset);
2460 		if (SC_get_errornumber(self) <= 0)
2461 			head = "STATEMENT WARNING";
2462 		else
2463 		{
2464 			head = "STATEMENT ERROR";
2465 			QLOG(level, "%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",head, func, desc, self->__error_number, NULLCHECK(self->__error_message));
2466 		}
2467 		MYLOG(0, "%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", head, func, desc, self->__error_number, NULLCHECK(self->__error_message));
2468 		if (SC_get_errornumber(self) > 0)
2469 		{
2470 			QLOG(level, "                 ------------------------------------------------------------\n");
2471 			QLOG(level, "                 hdbc=%p, stmt=%p, result=%p\n", self->hdbc, self, res);
2472 			QLOG(level, "                 prepare=%d, external=%d\n", self->prepare, self->external);
2473 			QLOG(level, "                 bindings=%p, bindings_allocated=%d\n", opts->bindings, opts->allocated);
2474 			QLOG(level, "                 parameters=%p, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
2475 			QLOG(level, "                 statement_type=%d, statement='%s'\n", self->statement_type, NULLCHECK(self->statement));
2476 			QLOG(level, "                 stmt_with_params='%s'\n", NULLCHECK(self->stmt_with_params));
2477 			QLOG(level, "                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
2478 			QLOG(level, "                 currTuple=" FORMAT_LEN ", current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
2479 			QLOG(level, "                 maxRows=" FORMAT_LEN ", rowset_size=" FORMAT_LEN ", keyset_size=" FORMAT_LEN ", cursor_type=" FORMAT_UINTEGER ", scroll_concurrency=" FORMAT_UINTEGER "\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
2480 			QLOG(level, "                 cursor_name='%s'\n", SC_cursor_name(self));
2481 
2482 			QLOG(level, "                 ----------------QResult Info -------------------------------\n");
2483 
2484 			if (res)
2485 			{
2486 				QLOG(level, "                 fields=%p, backend_tuples=%p, tupleField=%p, conn=%p\n", QR_get_fields(res), res->backend_tuples, res->tupleField, res->conn);
2487 				QLOG(level, "                 fetch_count=" FORMAT_LEN ", num_total_rows=" FORMAT_ULEN ", num_fields=%d, cursor='%s'\n", res->fetch_number, QR_get_num_total_tuples(res), res->num_fields, NULLCHECK(QR_get_cursor(res)));
2488 				QLOG(level, "                 message='%s', command='%s', notice='%s'\n", NULLCHECK(QR_get_message(res)), NULLCHECK(res->command), NULLCHECK(res->notice));
2489 				QLOG(level, "                 status=%d\n", QR_get_rstatus(res));
2490 			}
2491 
2492 			/* Log the connection error if there is one */
2493 			CC_log_error(func, desc, self->hdbc);
2494 		}
2495 	}
2496 	else
2497 	{
2498 		MYLOG(0, "INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
2499 	}
2500 }
2501 
2502 /*
2503  *	Extended Query
2504  */
2505 
2506 static BOOL
RequestStart(StatementClass * stmt,ConnectionClass * conn,const char * func)2507 RequestStart(StatementClass *stmt, ConnectionClass *conn, const char *func)
2508 {
2509 	BOOL	ret = TRUE;
2510 	unsigned int	svpopt = 0;
2511 
2512 #ifdef	_HANDLE_ENLIST_IN_DTC_
2513 	if (conn->asdum)
2514 		CALL_IsolateDtcConn(conn, TRUE);
2515 #endif /* _HANDLE_ENLIST_IN_DTC_ */
2516 	if (NULL == conn->pqconn)
2517         {
2518 		SC_set_error(stmt, STMT_COMMUNICATION_ERROR, "The connection has been lost", __FUNCTION__);
2519 		return SQL_ERROR;
2520 	}
2521 	if (CC_started_rbpoint(conn))
2522 		return TRUE;
2523 	if (SC_is_readonly(stmt))
2524 		svpopt |= SVPOPT_RDONLY;
2525 	if (SQL_ERROR == SetStatementSvp(stmt, svpopt))
2526 	{
2527 		char	emsg[128];
2528 
2529 		SPRINTF_FIXED(emsg, "internal savepoint error in %s", func);
2530 		SC_set_error_if_not_set(stmt, STMT_INTERNAL_ERROR, emsg, func);
2531 		return FALSE;
2532 	}
2533 
2534 	/*
2535 	 * In auto-commit mode, begin a new transaction implicitly if no
2536 	 * transaction is in progress yet. However, some special statements like
2537 	 * VACUUM and CLUSTER cannot be run in a transaction block.
2538 	 */
2539 	if (!CC_is_in_trans(conn) && CC_loves_visible_trans(conn) &&
2540 		stmt->statement_type != STMT_TYPE_SPECIAL)
2541 	{
2542 		ret = CC_begin(conn);
2543 	}
2544 	return ret;
2545 }
2546 
log_params(int nParams,const Oid * paramTypes,const UCHAR * const * paramValues,const int * paramLengths,const int * paramFormats,int resultFormat)2547 static void log_params(int nParams, const Oid *paramTypes, const UCHAR * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
2548 {
2549 	int	i, j;
2550 	BOOL	isBinary;
2551 
2552 	for (i = 0; i < nParams; i++)
2553 	{
2554 		isBinary = paramFormats ? paramFormats[i] : FALSE;
2555 		if (!paramValues[i])
2556 			QLOG(TUPLE_LOG_LEVEL, "\t%c (null) OID=%u\n", isBinary ? 'b' : 't', paramTypes ? paramTypes[i] : 0);
2557 		else if (isBinary)
2558 		{
2559 			QLOG(TUPLE_LOG_LEVEL, "\tb '");
2560 			for (j = 0; j < paramLengths[i]; j++)
2561 				QPRINTF(TUPLE_LOG_LEVEL, "%02x", paramValues[i][j]);
2562 			QPRINTF(TUPLE_LOG_LEVEL, " OID=%u\n", paramTypes ? paramTypes[i] : 0);
2563 		}
2564 		else
2565 			QLOG(TUPLE_LOG_LEVEL, "\tt '%s' OID=%u\n", paramValues[i], paramTypes ? paramTypes[i] : 0);
2566 	}
2567 }
2568 
2569 static
add_libpq_notice_receiver(StatementClass * stmt,notice_receiver_arg * nrarg)2570 QResultClass *add_libpq_notice_receiver(StatementClass *stmt, notice_receiver_arg *nrarg)
2571 {
2572 	QResultClass *res = NULL, *newres = NULL;
2573 
2574 	newres = res = QR_Constructor();
2575 	nrarg->conn = SC_get_conn(stmt);
2576 	nrarg->comment = __FUNCTION__;
2577 	nrarg->res = res;
2578 	nrarg->stmt = stmt;
2579 	PQsetNoticeReceiver(nrarg->conn->pqconn, receive_libpq_notice, nrarg);
2580 
2581 	return newres;
2582 }
2583 
2584 static QResultClass *
libpq_bind_and_exec(StatementClass * stmt)2585 libpq_bind_and_exec(StatementClass *stmt)
2586 {
2587 	CSTR		func = "libpq_bind_and_exec";
2588 	ConnectionClass	*conn = SC_get_conn(stmt);
2589 	int			nParams;
2590 	Oid		   *paramTypes = NULL;
2591 	char	  **paramValues = NULL;
2592 	int		   *paramLengths = NULL;
2593 	int		   *paramFormats = NULL;
2594 	int			resultFormat;
2595 	PGresult   *pgres = NULL;
2596 	int			pgresstatus;
2597 	QResultClass	*newres = NULL;
2598 	QResultClass *res = NULL;
2599 	char	   *cmdtag;
2600 	char	   *rowcount;
2601 	notice_receiver_arg	nrarg;
2602 
2603 	if (!RequestStart(stmt, conn, func))
2604 		return NULL;
2605 
2606 #ifdef	NOT_USED
2607 	if (CC_is_in_trans(conn) && !CC_started_rbpoint(conn))
2608 	{
2609 		if (SQL_ERROR == SetStatementSvp(stmt, 0))
2610 		{
2611 			SC_set_error_if_not_set(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in build_libpq_bind_params", func);
2612 			return NULL;
2613 		}
2614 	}
2615 #endif /* NOT_USED */
2616 
2617 	/* 1. Bind */
2618 	MYLOG(0, "bind stmt=%p\n", stmt);
2619 	if (!build_libpq_bind_params(stmt,
2620 								 &nParams,
2621 								 &paramTypes,
2622 								 &paramValues,
2623 								 &paramLengths, &paramFormats,
2624 								 &resultFormat))
2625 	{
2626 		if (SC_get_errornumber(stmt) <= 0)
2627 			SC_set_errornumber(stmt, STMT_NO_MEMORY_ERROR);
2628 		goto cleanup;
2629 	}
2630 
2631 	/* 2. Execute */
2632 	MYLOG(0, "execute stmt=%p\n", stmt);
2633 	if (!SC_is_fetchcursor(stmt))
2634 	{
2635 		if (stmt->prepared == NOT_YET_PREPARED ||
2636 			(stmt->prepared == PREPARED_TEMPORARILY && conn->unnamed_prepared_stmt != stmt))
2637 		{
2638 			SC_set_error(stmt, STMT_EXEC_ERROR, "about to execute a non-prepared statement", func);
2639 			goto cleanup;
2640 		}
2641 	}
2642 
2643 	/* 2.5 Prepare and Describe if needed */
2644 	if (stmt->prepared == PREPARING_TEMPORARILY ||
2645 		(stmt->prepared == PREPARED_TEMPORARILY && conn->unnamed_prepared_stmt != stmt))
2646 	{
2647 		ProcessedStmt *pstmt;
2648 
2649 		if (!stmt->processed_statements)
2650 		{
2651 			if (prepareParametersNoDesc(stmt, FALSE, EXEC_PARAM_CAST) == SQL_ERROR)
2652 				goto cleanup;
2653 		}
2654 
2655 		pstmt = stmt->processed_statements;
2656 		QLOG(0, "PQexecParams: %p '%s' nParams=%d\n", conn->pqconn, pstmt->query, nParams);
2657 		log_params(nParams, paramTypes, (const UCHAR * const *) paramValues, paramLengths, paramFormats, resultFormat);
2658 		/* set notice receiver */
2659 		newres = add_libpq_notice_receiver(stmt, &nrarg);
2660 		pgres = PQexecParams(conn->pqconn,
2661 							 pstmt->query,
2662 							 nParams,
2663 							 paramTypes,
2664 							 (const char **) paramValues,
2665 							 paramLengths,
2666 							 paramFormats,
2667 							 resultFormat);
2668 	}
2669 	else
2670 	{
2671 		const char *plan_name;
2672 
2673 		if (stmt->prepared == PREPARING_PERMANENTLY)
2674 		{
2675 			if (prepareParameters(stmt, FALSE) == SQL_ERROR)
2676 				goto cleanup;
2677 		}
2678 
2679 		/* prepareParameters() set plan name, so don't fetch this earlier */
2680 		plan_name = stmt->plan_name ? stmt->plan_name : NULL_STRING;
2681 
2682 		/* already prepared */
2683 		QLOG(0, "PQexecPrepared: %p plan=%s nParams=%d\n", conn->pqconn, plan_name, nParams);
2684 		log_params(nParams, paramTypes, (const UCHAR * const *) paramValues, paramLengths, paramFormats, resultFormat);
2685 		/* set notice receiver */
2686 		newres = add_libpq_notice_receiver(stmt, &nrarg);
2687 		pgres = PQexecPrepared(conn->pqconn,
2688 							   plan_name, 	/* portal name == plan name */
2689 							   nParams,
2690 							   (const char **) paramValues, paramLengths, paramFormats,
2691 							   resultFormat);
2692 	}
2693 	/* reset notice receiver */
2694 	PQsetNoticeReceiver(conn->pqconn, receive_libpq_notice, NULL);
2695 	if (!(res = nrarg.res))
2696 	{
2697 		SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory while allocating result set", func);
2698 		goto cleanup;
2699 	}
2700 
2701 	/* 3. Receive results */
2702 MYLOG(DETAIL_LOG_LEVEL, "get_Result=%p %p\n", res, SC_get_Result(stmt));
2703 	pgresstatus = PQresultStatus(pgres);
2704 	switch (pgresstatus)
2705 	{
2706 		case PGRES_COMMAND_OK:
2707 			/* portal query command, no tuples returned */
2708 			/* read in the return message from the backend */
2709 			cmdtag = PQcmdStatus(pgres);
2710 			QLOG(0, "\tok: - 'C' - %s\n", cmdtag);
2711 			QR_set_command(res, cmdtag);
2712 			if (QR_command_successful(res))
2713 				QR_set_rstatus(res, PORES_COMMAND_OK);
2714 
2715 			/* get rowcount */
2716 			rowcount = PQcmdTuples(pgres);
2717 			if (rowcount && rowcount[0])
2718 				res->recent_processed_row_count = atoi(rowcount);
2719 			else
2720 				res->recent_processed_row_count = -1;
2721 			break;
2722 
2723 		case PGRES_EMPTY_QUERY:
2724 			/* We return the empty query */
2725 			QR_set_rstatus(res, PORES_EMPTY_QUERY);
2726 			break;
2727 		case PGRES_NONFATAL_ERROR:
2728 			handle_pgres_error(conn, pgres, "libpq_bind_and_exec", res, FALSE);
2729 			break;
2730 
2731 		case PGRES_BAD_RESPONSE:
2732 		case PGRES_FATAL_ERROR:
2733 			handle_pgres_error(conn, pgres, "libpq_bind_and_exec", res, TRUE);
2734 			break;
2735 		case PGRES_TUPLES_OK:
2736 			if (!QR_from_PGresult(res, stmt, conn, NULL, &pgres))
2737 				goto cleanup;
2738 			if (res->rstatus == PORES_TUPLES_OK && res->notice)
2739 				QR_set_rstatus(res, PORES_NONFATAL_ERROR);
2740 			break;
2741 		case PGRES_COPY_OUT:
2742 		case PGRES_COPY_IN:
2743 		case PGRES_COPY_BOTH:
2744 		default:
2745 			/* skip the unexpected response if possible */
2746 			QR_set_rstatus(res, PORES_BAD_RESPONSE);
2747 			CC_set_error(conn, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_query)", func);
2748 			CC_on_abort(conn, CONN_DEAD);
2749 
2750 			QLOG(0, "PQexecXxxx error: - (%d) - %s\n", pgresstatus, CC_get_errormsg(conn));
2751 			break;
2752 	}
2753 
2754 	if (res != newres && NULL != newres)
2755 		QR_Destructor(newres);
2756 
2757 cleanup:
2758 	if (pgres)
2759 		PQclear(pgres);
2760 	if (paramValues)
2761 	{
2762 		int			i;
2763 		for (i = 0; i < nParams; i++)
2764 		{
2765 			if (paramValues[i] != NULL)
2766 				free(paramValues[i]);
2767 		}
2768 		free(paramValues);
2769 	}
2770 	if (paramTypes)
2771 		free(paramTypes);
2772 	if (paramLengths)
2773 		free(paramLengths);
2774 	if (paramFormats)
2775 		free(paramFormats);
2776 
2777 	return res;
2778 }
2779 
2780 /*
2781  * Parse a query using libpq.
2782  *
2783  * 'res' is only passed here for error reporting purposes. If an error is
2784  * encountered, it is set in 'res', and the function returns FALSE.
2785  */
2786 static BOOL
ParseWithLibpq(StatementClass * stmt,const char * plan_name,const char * query,Int2 num_params,const char * comment,QResultClass * res)2787 ParseWithLibpq(StatementClass *stmt, const char *plan_name,
2788 			   const char *query,
2789 			   Int2 num_params, const char *comment, QResultClass *res)
2790 {
2791 	CSTR	func = "ParseWithLibpq";
2792 	ConnectionClass	*conn = SC_get_conn(stmt);
2793 	Int4		sta_pidx = -1, end_pidx = -1;
2794 	const char	*cstatus;
2795 	Oid		   *paramTypes = NULL;
2796 	BOOL		retval = FALSE;
2797 	PGresult   *pgres = NULL;
2798 
2799 	MYLOG(0, "entering plan_name=%s query=%s\n", plan_name, query);
2800 	if (!RequestStart(stmt, conn, func))
2801 		return FALSE;
2802 
2803 	if (stmt->discard_output_params)
2804 		num_params = 0;
2805 	else if (num_params != 0)
2806 	{
2807 #ifdef	NOT_USED
2808 		sta_pidx += stmt->proc_return;
2809 #endif /* NOT_USED */
2810 		int	pidx;
2811 
2812 		sta_pidx = stmt->current_exec_param;
2813 		if (num_params < 0)
2814 			end_pidx = stmt->num_params - 1;
2815 		else
2816 			end_pidx = sta_pidx + num_params - 1;
2817 #ifdef	NOT_USED
2818 		num_params = end_pidx - sta_pidx + 1;
2819 #endif /* NOT_USED */
2820 		for (num_params = 0, pidx = sta_pidx - 1;;)
2821 		{
2822 			SC_param_next(stmt, &pidx, NULL, NULL);
2823 			if (pidx > end_pidx)
2824 				break;
2825 			else if (pidx < end_pidx)
2826 			{
2827 				if (0 == num_params)
2828 					sta_pidx = pidx;
2829 				num_params++;
2830 			}
2831 			else
2832 			{
2833 				num_params++;
2834 				break;
2835 			}
2836 		}
2837 MYLOG(0, "sta_pidx=%d end_pidx=%d num_p=%d\n", sta_pidx, end_pidx, num_params);
2838 	}
2839 
2840 	/*
2841 	 * We let the server deduce the right datatype for the parameters, except
2842 	 * for out parameters, which are sent as VOID.
2843 	 */
2844 	if (num_params > 0)
2845 	{
2846 		int	i;
2847 		int j;
2848 		IPDFields	*ipdopts = SC_get_IPDF(stmt);
2849 
2850 		paramTypes = malloc(sizeof(Oid) * num_params);
2851 		if (paramTypes == NULL)
2852 		{
2853 			SC_set_errornumber(stmt, STMT_NO_MEMORY_ERROR);
2854 			goto cleanup;
2855 		}
2856 
2857 		MYLOG(0, "ipdopts->allocated: %d\n", ipdopts->allocated);
2858 		j = 0;
2859 		for (i = sta_pidx; i <= end_pidx; i++)
2860 		{
2861 			if (i < ipdopts->allocated)
2862 			{
2863 				if (SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
2864 					paramTypes[j++] = PG_TYPE_VOID;
2865 				else
2866 					paramTypes[j++] = sqltype_to_bind_pgtype(conn,
2867 															 ipdopts->parameters[i].SQLType);
2868 			}
2869 			else
2870 			{
2871 				/* Unknown type of parameter. Let the server decide */
2872 				paramTypes[j++] = 0;
2873 			}
2874 		}
2875 	}
2876 
2877 	if (plan_name == NULL || plan_name[0] == '\0')
2878 		conn->unnamed_prepared_stmt = NULL;
2879 
2880 	/* Prepare */
2881 	QLOG(0, "PQprepare: %p '%s' plan=%s nParams=%d\n", conn->pqconn, query, plan_name, num_params);
2882 	pgres = PQprepare(conn->pqconn, plan_name, query, num_params, paramTypes);
2883 	if (PQresultStatus(pgres) != PGRES_COMMAND_OK)
2884 	{
2885 		handle_pgres_error(conn, pgres, "ParseWithlibpq", res, TRUE);
2886 		goto cleanup;
2887 	}
2888 	cstatus = PQcmdStatus(pgres);
2889 	QLOG(0, "\tok: - 'C' - %s\n", cstatus);
2890 	if (stmt->plan_name)
2891 		SC_set_prepared(stmt, PREPARED_PERMANENTLY);
2892 	else
2893 		SC_set_prepared(stmt, PREPARED_TEMPORARILY);
2894 
2895 	if (plan_name == NULL || plan_name[0] == '\0')
2896 		conn->unnamed_prepared_stmt = stmt;
2897 
2898 	retval = TRUE;
2899 
2900 cleanup:
2901 	if (paramTypes)
2902 		free(paramTypes);
2903 
2904 	if (pgres)
2905 		PQclear(pgres);
2906 
2907 	return retval;
2908 }
2909 
2910 
2911 /*
2912  * Parse and describe a query using libpq.
2913  *
2914  * Returns an empty result set that has the column information, or error code
2915  * and message, filled in. If 'res' is not NULL, it is the result set
2916  * returned, otherwise a new one is allocated.
2917  *
2918  * NB: The caller must set stmt->current_exec_param before calling this
2919  * function!
2920  */
2921 QResultClass *
ParseAndDescribeWithLibpq(StatementClass * stmt,const char * plan_name,const char * query_param,Int2 num_params,const char * comment,QResultClass * res)2922 ParseAndDescribeWithLibpq(StatementClass *stmt, const char *plan_name,
2923 						  const char *query_param,
2924 						  Int2 num_params, const char *comment,
2925 						  QResultClass *res)
2926 {
2927 	CSTR	func = "ParseAndDescribeWithLibpq";
2928 	ConnectionClass	*conn = SC_get_conn(stmt);
2929 	PGresult   *pgres = NULL;
2930 	int			num_p;
2931 	Int2		num_discard_params;
2932 	IPDFields	*ipdopts;
2933 	int			pidx;
2934 	int			i;
2935 	Oid			oid;
2936 	SQLSMALLINT paramType;
2937 
2938 	MYLOG(0, "entering plan_name=%s query=%s\n", plan_name, query_param);
2939 	if (!RequestStart(stmt, conn, func))
2940 		return NULL;
2941 
2942 	if (!res)
2943 		res = QR_Constructor();
2944 	if (!res)
2945 	{
2946 		SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for query", func);
2947 		return NULL;
2948 	}
2949 
2950 	/*
2951 	 * We need to do Prepare + Describe as two different round-trips to the
2952 	 * server, while before we switched to use libpq, we used to send a Parse
2953 	 * and Describe message followed by a single Sync.
2954 	 */
2955 	if (!ParseWithLibpq(stmt, plan_name, query_param, num_params, comment, res))
2956 		goto cleanup;
2957 
2958 	/* Describe */
2959 	QLOG(0, "\tPQdescribePrepared: %p plan_name=%s\n", conn->pqconn, plan_name);
2960 
2961 	pgres = PQdescribePrepared(conn->pqconn, plan_name);
2962 	switch (PQresultStatus(pgres))
2963 	{
2964 		case PGRES_COMMAND_OK:
2965 			QLOG(0, "\tok: - 'C' - %s\n", PQcmdStatus(pgres));
2966 			/* expected */
2967 			break;
2968 		case PGRES_NONFATAL_ERROR:
2969 			handle_pgres_error(conn, pgres, "ParseAndDescribeWithLibpq", res, FALSE);
2970 			goto cleanup;
2971 		case PGRES_FATAL_ERROR:
2972 			handle_pgres_error(conn, pgres, "ParseAndDescribeWithLibpq", res, TRUE);
2973 			goto cleanup;
2974 		default:
2975 			/* skip the unexpected response if possible */
2976 			CC_set_error(conn, CONNECTION_BACKEND_CRAZY, "Unexpected result from PQdescribePrepared", func);
2977 			CC_on_abort(conn, CONN_DEAD);
2978 
2979 			MYLOG(0, "PQdescribePrepared: error - %s\n", CC_get_errormsg(conn));
2980 			goto cleanup;
2981 	}
2982 
2983 	/* Extract parameter information from the result set */
2984 	num_p = PQnparams(pgres);
2985 MYLOG(DETAIL_LOG_LEVEL, "num_params=%d info=%d\n", stmt->num_params, num_p);
2986 	if (get_qlog() > 0 || get_mylog() > 0)
2987 	{
2988 		int	i;
2989 
2990 		QLOG(0, "\tnParams=%d", num_p);
2991 		for (i = 0; i < num_p; i++)
2992 			QPRINTF(0, " %u", PQparamtype(pgres, i));
2993 		QPRINTF(0, "\n");
2994 	}
2995 	num_discard_params = 0;
2996 	if (stmt->discard_output_params)
2997 		CountParameters(stmt, NULL, NULL, &num_discard_params);
2998 	if (num_discard_params < stmt->proc_return)
2999 		num_discard_params = stmt->proc_return;
3000 	if (num_p + num_discard_params != (int) stmt->num_params)
3001 	{
3002 		MYLOG(0, "ParamInfo unmatch num_params(=%d) != info(=%d)+discard(=%d)\n", stmt->num_params, num_p, num_discard_params);
3003 		/* stmt->num_params = (Int2) num_p + num_discard_params; it's possible in case of multi command queries */
3004 	}
3005 	ipdopts = SC_get_IPDF(stmt);
3006 	extend_iparameter_bindings(ipdopts, stmt->num_params);
3007 	pidx = stmt->current_exec_param;
3008 	if (pidx >= 0)
3009 		pidx--;
3010 	for (i = 0; i < num_p; i++)
3011 	{
3012 		SC_param_next(stmt, &pidx, NULL, NULL);
3013 		if (pidx >= stmt->num_params)
3014 		{
3015 			MYLOG(0, "%dth parameter's position(%d) is out of bound[%d]\n", i, pidx, stmt->num_params);
3016 			break;
3017 		}
3018 		oid = PQparamtype(pgres, i);
3019 		paramType = ipdopts->parameters[pidx].paramType;
3020 		if (SQL_PARAM_OUTPUT != paramType ||
3021 			PG_TYPE_VOID != oid)
3022 			PIC_set_pgtype(ipdopts->parameters[pidx], oid);
3023 	}
3024 
3025 	/* Extract Portal information */
3026 	QR_set_conn(res, conn);
3027 
3028 	if (CI_read_fields_from_pgres(QR_get_fields(res), pgres))
3029 	{
3030 		Int2	dummy1, dummy2;
3031 		int	cidx;
3032 		int num_io_params;
3033 
3034 		QR_set_rstatus(res, PORES_FIELDS_OK);
3035 		res->num_fields = CI_get_num_fields(QR_get_fields(res));
3036 		if (QR_haskeyset(res))
3037 			res->num_fields -= res->num_key_fields;
3038 		num_io_params = CountParameters(stmt, NULL, &dummy1, &dummy2);
3039 		if (stmt->proc_return > 0 ||
3040 			num_io_params > 0)
3041 		{
3042 			ipdopts = SC_get_IPDF(stmt);
3043 			extend_iparameter_bindings(ipdopts, stmt->num_params);
3044 			for (i = 0, cidx = 0; i < stmt->num_params; i++)
3045 			{
3046 				if (i < stmt->proc_return)
3047 					ipdopts->parameters[i].paramType = SQL_PARAM_OUTPUT;
3048 				paramType =ipdopts->parameters[i].paramType;
3049 				if (SQL_PARAM_OUTPUT == paramType ||
3050 					SQL_PARAM_INPUT_OUTPUT == paramType)
3051 				{
3052 					MYLOG(DETAIL_LOG_LEVEL, "!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_get_oid(QR_get_fields(res), cidx));
3053 					PIC_set_pgtype(ipdopts->parameters[i], CI_get_oid(QR_get_fields(res), cidx));
3054 					cidx++;
3055 				}
3056 			}
3057 		}
3058 	}
3059 	else
3060 	{
3061 		if (NULL == QR_get_fields(res)->coli_array)
3062 		{
3063 			QR_set_rstatus(res, PORES_NO_MEMORY_ERROR);
3064 			QR_set_messageref(res, "Out of memory while reading field information");
3065 		}
3066 		else
3067 		{
3068 			QR_set_rstatus(res, PORES_BAD_RESPONSE);
3069 			QR_set_message(res, "Error reading field information");
3070 		}
3071 	}
3072 
3073 cleanup:
3074 	if (pgres)
3075 		PQclear(pgres);
3076 
3077 	return res;
3078 }
3079 
3080 enum {
3081 	CancelRequestSet	= 1L
3082 	,CancelRequestAccepted	= (1L << 1)
3083 	,CancelCompleted	= (1L << 2)
3084 };
3085 /*	commonly used for short term lock */
3086 #if defined(WIN_MULTITHREAD_SUPPORT)
3087 extern  CRITICAL_SECTION        common_cs;
3088 #elif defined(POSIX_MULTITHREAD_SUPPORT)
3089 extern  pthread_mutex_t         common_cs;
3090 #endif /* WIN_MULTITHREAD_SUPPORT */
SC_IsExecuting(const StatementClass * self)3091 BOOL	SC_IsExecuting(const StatementClass *self)
3092 {
3093 	BOOL	ret;
3094 	ENTER_COMMON_CS; /* short time blocking */
3095 	ret = (STMT_EXECUTING == self->status);
3096 	LEAVE_COMMON_CS;
3097 	return ret;
3098 }
SC_SetExecuting(StatementClass * self,BOOL on)3099 BOOL	SC_SetExecuting(StatementClass *self, BOOL on)
3100 {
3101 	BOOL	exeSet = FALSE;
3102 	ENTER_COMMON_CS; /* short time blocking */
3103 	if (on)
3104 	{
3105 		if (0 == (self->cancel_info & CancelRequestSet))
3106 		{
3107 			self->status = STMT_EXECUTING;
3108 			exeSet = TRUE;
3109 		}
3110 	}
3111 	else
3112 	{
3113 		self->cancel_info = 0;
3114 		self->status = STMT_FINISHED;
3115 MYLOG(0, "set %p STMT_FINISHED\n", self);
3116 		exeSet = TRUE;
3117 	}
3118 	LEAVE_COMMON_CS;
3119 	return exeSet;
3120 }
3121 
3122 #ifdef	NOT_USED
SC_SetCancelRequest(StatementClass * self)3123 BOOL	SC_SetCancelRequest(StatementClass *self)
3124 {
3125 	BOOL	enteredCS = FALSE;
3126 
3127 	ENTER_COMMON_CS;
3128 	if (0 != (self->cancel_info & CancelCompleted))
3129 		;
3130 	else if (STMT_EXECUTING == self->status)
3131 	{
3132 		self->cancel_info |= CancelRequestSet;
3133 	}
3134 	else
3135 	{
3136 		/* try to acquire */
3137 		if (TRY_ENTER_STMT_CS(self))
3138 			enteredCS = TRUE;
3139 		else
3140 			self->cancel_info |= CancelRequestSet;
3141 	}
3142 	LEAVE_COMMON_CS;
3143 	return enteredCS;
3144 }
3145 #endif /* NOT_USED */
3146 
SC_AcceptedCancelRequest(const StatementClass * self)3147 BOOL	SC_AcceptedCancelRequest(const StatementClass *self)
3148 {
3149 	BOOL	shouldCancel = FALSE;
3150 	ENTER_COMMON_CS;
3151 	if (0 != (self->cancel_info & (CancelRequestSet | CancelRequestAccepted | CancelCompleted)))
3152 		shouldCancel = TRUE;
3153 	LEAVE_COMMON_CS;
3154 	return shouldCancel;
3155 }
3156 
3157 static void
SC_set_error_if_not_set(StatementClass * self,int errornumber,const char * errmsg,const char * func)3158 SC_set_error_if_not_set(StatementClass *self, int errornumber, const char *errmsg, const char *func)
3159 {
3160 	int	errnum = SC_get_errornumber(self);
3161 
3162 	if (errnum <= 0)
3163 	{
3164 		const char *emsg = SC_get_errormsg(self);
3165 
3166 		if (emsg && 0 == errnum)
3167 			SC_set_errornumber(self, errornumber);
3168 		else
3169 			SC_set_error(self, errornumber, errmsg, func);
3170 	}
3171 }
3172 
3173 static void
SC_set_errorinfo(StatementClass * self,QResultClass * res,int errkind)3174 SC_set_errorinfo(StatementClass *self, QResultClass *res, int errkind)
3175 {
3176 	ConnectionClass *conn = SC_get_conn(self);
3177 
3178 	if (CC_not_connected(conn))
3179 	{
3180 		SC_set_error_if_not_set(self, STMT_COMMUNICATION_ERROR, "The connection has been lost", __FUNCTION__);
3181 		return;
3182 	}
3183 
3184 	switch (QR_get_rstatus(res))
3185 	{
3186 		case PORES_NO_MEMORY_ERROR:
3187 			SC_set_error_if_not_set(self, STMT_NO_MEMORY_ERROR, "memory allocation error???", __FUNCTION__);
3188 			break;
3189 		case PORES_BAD_RESPONSE:
3190 			SC_set_error_if_not_set(self, STMT_COMMUNICATION_ERROR, "communication error occured", __FUNCTION__);
3191 			break;
3192 		case PORES_INTERNAL_ERROR:
3193 			SC_set_error_if_not_set(self, STMT_INTERNAL_ERROR, "Internal error fetching next row", __FUNCTION__);
3194 			break;
3195 		default:
3196 			switch (errkind)
3197 			{
3198 				case 1:
3199 					SC_set_error_if_not_set(self, STMT_EXEC_ERROR, "Error while fetching the next result", __FUNCTION__);
3200 					break;
3201 				default:
3202 					SC_set_error_if_not_set(self, STMT_EXEC_ERROR, "Error while executing the query", __FUNCTION__);
3203 					break;
3204 			}
3205 			break;
3206 	}
3207 }
3208 
3209 /*
3210  *	Before 9.6, the driver offered very simple bookmark support -- it is just
3211  *	the current row number.
3212  *	Now the driver offers more verbose bookmarks which contain KeySet informations
3213  *	(CTID (+ OID)). Though they consume 12bytes(row number + CTID) or 16bytes
3214  *	(row number + CTID + OID), they are useful in declare/fetch mode.
3215  */
3216 
SC_Resolve_bookmark(const ARDFields * opts,Int4 idx)3217 PG_BM	SC_Resolve_bookmark(const ARDFields *opts, Int4 idx)
3218 {
3219 	BindInfoClass	*bookmark;
3220 	SQLLEN		*used;
3221 	SQLULEN		offset;
3222 	SQLUINTEGER	bind_size;
3223 	size_t	cpylen = sizeof(Int4);
3224 	PG_BM	pg_bm;
3225 
3226 	bookmark = opts->bookmark;
3227 	offset = opts->row_offset_ptr ? *(opts->row_offset_ptr) : 0;
3228 	bind_size = opts->bind_size;
3229 	memset(&pg_bm, 0, sizeof(pg_bm));
3230 	if (used = bookmark->used, used != NULL)
3231 	{
3232 		used = LENADDR_SHIFT(used, offset);
3233 		if (bind_size > 0)
3234 			used = LENADDR_SHIFT(used, idx * bind_size);
3235 		else
3236 			used = LENADDR_SHIFT(used, idx * sizeof(SQLLEN));
3237 		if (*used >= sizeof(pg_bm))
3238 			cpylen = sizeof(pg_bm);
3239 		else if (*used >= 12)
3240 			cpylen = 12;
3241 		MYLOG(0, "used=" FORMAT_LEN " cpylen=" FORMAT_SIZE_T "\n", *used, cpylen);
3242 	}
3243 	memcpy(&pg_bm, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, idx), cpylen);
3244 MYLOG(0, "index=%d block=%d off=%d\n", pg_bm.index, pg_bm.keys.blocknum, pg_bm.keys.offset);
3245 	pg_bm.index = SC_resolve_int4_bookmark(pg_bm.index);
3246 
3247 	return pg_bm;
3248 }
3249 
SC_Create_bookmark(StatementClass * self,BindInfoClass * bookmark,Int4 bind_row,Int4 currTuple,const KeySet * keyset)3250 int	SC_Create_bookmark(StatementClass *self, BindInfoClass *bookmark, Int4 bind_row, Int4 currTuple, const KeySet *keyset)
3251 {
3252 	ARDFields	*opts = SC_get_ARDF(self);
3253 	SQLUINTEGER	bind_size = opts->bind_size;
3254 	SQLULEN		offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
3255 	size_t		cvtlen = sizeof(Int4);
3256 	PG_BM		pg_bm;
3257 
3258 MYLOG(0, "entering type=%d buflen=" FORMAT_LEN " buf=%p\n", bookmark->returntype, bookmark->buflen, bookmark->buffer);
3259 	memset(&pg_bm, 0, sizeof(pg_bm));
3260 	if (SQL_C_BOOKMARK == bookmark->returntype)
3261 		;
3262 	else if (bookmark->buflen >= sizeof(pg_bm))
3263 		cvtlen = sizeof(pg_bm);
3264 	else if (bookmark->buflen >= 12)
3265 		cvtlen = 12;
3266 	pg_bm.index = SC_make_int4_bookmark(currTuple);
3267 	if (keyset)
3268 		pg_bm.keys  = *keyset;
3269 	memcpy(CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, bind_row), &pg_bm, cvtlen);
3270 	if (bookmark->used)
3271 	{
3272 		SQLLEN *used = LENADDR_SHIFT(bookmark->used, offset);
3273 
3274 		if (bind_size > 0)
3275 			used = LENADDR_SHIFT(used, bind_row * bind_size);
3276 		else
3277 			used = LENADDR_SHIFT(used, bind_row * sizeof(SQLLEN));
3278 		*used = cvtlen;
3279 	}
3280 MYLOG(0, "leaving cvtlen=" FORMAT_SIZE_T " ix(bl,of)=%d(%d,%d)\n", cvtlen, pg_bm.index, pg_bm.keys.blocknum, pg_bm.keys.offset);
3281 
3282 	return COPY_OK;
3283 }
3284