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 ¶mTypes,
2622 ¶mValues,
2623 ¶mLengths, ¶mFormats,
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