DON'T USE THIS REPO: IT'S OBSOLETE.
[versaplex.git] / vxodbc / statement.cc
blobafe701fde55186cf58fbee99197241a274b0939b
1 /*
2 * Description: This module contains functions related to creating
3 * and manipulating a statement.
4 */
6 #ifndef _WIN32_WINNT
7 #define _WIN32_WINNT 0x0400
8 #endif /* _WIN32_WINNT */
10 #include "statement.h"
12 #include "bind.h"
13 #include "connection.h"
14 #include "multibyte.h"
15 #include "qresult.h"
16 #include "convert.h"
17 #include "environ.h"
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
23 #include "pgapifunc.h"
26 #define PRN_NULLCHECK
28 /* Map sql commands to statement types */
29 static struct {
30 int type;
31 char *s;
32 } Statement_Type[] =
35 STMT_TYPE_SELECT, "SELECT"}
38 STMT_TYPE_INSERT, "INSERT"}
41 STMT_TYPE_UPDATE, "UPDATE"}
44 STMT_TYPE_DELETE, "DELETE"}
47 STMT_TYPE_PROCCALL, "{"}
50 STMT_TYPE_SET, "SET"}
53 STMT_TYPE_RESET, "RESET"}
56 STMT_TYPE_CREATE, "CREATE"}
59 STMT_TYPE_DECLARE, "DECLARE"}
62 STMT_TYPE_FETCH, "FETCH"}
65 STMT_TYPE_MOVE, "MOVE"}
68 STMT_TYPE_CLOSE, "CLOSE"}
71 STMT_TYPE_PREPARE, "PREPARE"}
74 STMT_TYPE_EXECUTE, "EXECUTE"}
77 STMT_TYPE_DEALLOCATE, "DEALLOCATE"}
80 STMT_TYPE_DROP, "DROP"}
83 STMT_TYPE_START, "BEGIN"}
86 STMT_TYPE_START, "START"}
89 STMT_TYPE_TRANSACTION, "SAVEPOINT"}
92 STMT_TYPE_TRANSACTION, "RELEASE"}
95 STMT_TYPE_TRANSACTION, "COMMIT"}
98 STMT_TYPE_TRANSACTION, "END"}
101 STMT_TYPE_TRANSACTION, "ROLLBACK"}
104 STMT_TYPE_TRANSACTION, "ABORT"}
107 STMT_TYPE_LOCK, "LOCK"}
110 STMT_TYPE_ALTER, "ALTER"}
113 STMT_TYPE_GRANT, "GRANT"}
116 STMT_TYPE_REVOKE, "REVOKE"}
119 STMT_TYPE_COPY, "COPY"}
122 STMT_TYPE_ANALYZE, "ANALYZE"}
125 STMT_TYPE_NOTIFY, "NOTIFY"}
128 STMT_TYPE_EXPLAIN, "EXPLAIN"}
131 STMT_TYPE_SPECIAL, "VACUUM"}
134 STMT_TYPE_SPECIAL, "REINDEX"}
137 STMT_TYPE_SPECIAL, "CLUSTER"}
140 STMT_TYPE_SPECIAL, "CHECKPOINT"}
143 0, NULL}
147 void SC_set_Result(StatementClass *s, QResultClass *q)
149 if (q != s->result)
151 mylog("SC_set_Result(%x, %x)\n", s, q);
152 QR_Destructor(s->result);
153 s->result = s->curres = q;
158 RETCODE SQL_API PGAPI_AllocStmt(HDBC hdbc, HSTMT FAR * phstmt)
160 CSTR func = "PGAPI_AllocStmt";
161 ConnectionClass *conn = (ConnectionClass *) hdbc;
162 StatementClass *stmt;
163 ARDFields *ardopts;
164 BindInfoClass *bookmark;
166 mylog("%s: entering...\n", func);
168 if (!conn)
170 CC_log_error(func, "", NULL);
171 return SQL_INVALID_HANDLE;
174 stmt = SC_Constructor(conn);
176 mylog("**** PGAPI_AllocStmt: hdbc = %p, stmt = %p\n", hdbc, stmt);
178 if (!stmt)
180 CC_set_error(conn, CONN_STMT_ALLOC_ERROR,
181 "No more memory to allocate a further SQL-statement",
182 func);
183 *phstmt = SQL_NULL_HSTMT;
184 return SQL_ERROR;
187 if (!CC_add_statement(conn, stmt))
189 CC_set_error(conn, CONN_STMT_ALLOC_ERROR,
190 "Maximum number of statements exceeded.", func);
191 SC_Destructor(stmt);
192 *phstmt = SQL_NULL_HSTMT;
193 return SQL_ERROR;
196 *phstmt = (HSTMT) stmt;
198 /* Copy default statement options based from Connection options */
199 stmt->options = stmt->options_orig = conn->stmtOptions;
200 stmt->ardi.ardopts = conn->ardOptions;
201 ardopts = SC_get_ARDF(stmt);
202 bookmark = ARD_AllocBookmark(ardopts);
204 stmt->stmt_size_limit = CC_get_max_query_len(conn);
205 /* Save the handle for later */
206 stmt->phstmt = phstmt;
208 return SQL_SUCCESS;
212 RETCODE SQL_API PGAPI_FreeStmt(HSTMT hstmt, SQLUSMALLINT fOption)
214 CSTR func = "PGAPI_FreeStmt";
215 StatementClass *stmt = (StatementClass *) hstmt;
217 mylog("hstmt=%p, fOption=%hi\n", hstmt, fOption);
219 if (!stmt)
221 SC_log_error(func, "", NULL);
222 return SQL_INVALID_HANDLE;
224 SC_clear_error(stmt);
226 if (fOption == SQL_DROP)
228 ConnectionClass *conn = stmt->hdbc;
230 /* Remove the statement from the connection's statement list */
231 if (conn)
233 QResultClass *res;
235 if (!CC_remove_statement(conn, stmt))
237 SC_set_error(stmt, STMT_SEQUENCE_ERROR,
238 "Statement is currently executing a transaction.",
239 func);
240 return SQL_ERROR; /* stmt may be executing a
241 * transaction */
244 /* Free any cursors and discard any result info */
245 res = SC_get_Result(stmt);
246 QR_Destructor(res);
247 SC_init_Result(stmt);
250 if (stmt->execute_delegate)
252 PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
253 stmt->execute_delegate = NULL;
255 if (stmt->execute_parent)
256 stmt->execute_parent->execute_delegate = NULL;
257 /* Destroy the statement and free any results, cursors, etc. */
258 SC_Destructor(stmt);
259 } else if (fOption == SQL_UNBIND)
260 SC_unbind_cols(stmt);
261 else if (fOption == SQL_CLOSE)
264 * this should discard all the results, but leave the statement
265 * itself in place (it can be executed again)
267 stmt->transition_status = 0;
268 if (stmt->execute_delegate)
270 PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
271 stmt->execute_delegate = NULL;
273 if (!SC_recycle_statement(stmt))
275 return SQL_ERROR;
278 else
280 SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR,
281 "Invalid option passed to PGAPI_FreeStmt.", func);
282 return SQL_ERROR;
285 return SQL_SUCCESS;
290 * StatementClass implementation
292 void InitializeStatementOptions(StatementOptions * opt)
294 memset(opt, 0, sizeof(StatementOptions));
295 opt->maxRows = 0; /* driver returns all rows */
296 opt->maxLength = 0; /* driver returns all data for char/binary */
297 opt->keyset_size = 0; /* fully keyset driven is the default */
298 opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
299 opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
300 opt->retrieve_data = SQL_RD_ON;
301 opt->use_bookmarks = SQL_UB_OFF;
302 opt->metadata_id = SQL_FALSE;
305 static void SC_clear_parse_status(StatementClass * self,
306 ConnectionClass * conn)
308 self->parse_status = STMT_PARSE_NONE;
309 if (PG_VERSION_LT(conn, 7.2))
311 SC_set_checked_hasoids(self, TRUE);
312 self->num_key_fields = PG_NUM_NORMAL_KEYS;
316 static void SC_init_discard_output_params(StatementClass * self)
318 ConnectionClass *conn = SC_get_conn(self);
320 if (!conn)
321 return;
322 self->discard_output_params = 0;
323 if (!conn->connInfo.use_server_side_prepare)
324 self->discard_output_params = 1;
327 static void SC_init_parse_method(StatementClass * self)
329 ConnectionClass *conn = SC_get_conn(self);
331 self->parse_method = 0;
332 if (!conn)
333 return;
334 if (self->catalog_result)
335 return;
336 if (self->multi_statement <= 0 && conn->connInfo.disallow_premature)
337 SC_set_parse_tricky(self);
340 StatementClass *SC_Constructor(ConnectionClass * conn)
342 StatementClass *rv;
344 rv = (StatementClass *) malloc(sizeof(StatementClass));
345 if (rv)
347 rv->hdbc = conn;
348 rv->phstmt = NULL;
349 rv->result = NULL;
350 rv->curres = NULL;
351 rv->catalog_result = FALSE;
352 rv->prepare = NON_PREPARE_STATEMENT;
353 rv->prepared = NOT_YET_PREPARED;
354 rv->status = STMT_ALLOCATED;
355 rv->internal = FALSE;
356 rv->plan_name = NULL;
357 rv->transition_status = 0;
358 rv->multi_statement = -1; /* unknown */
359 rv->num_params = -1; /* unknown */
361 rv->__error_message = NULL;
362 rv->__error_number = 0;
363 rv->pgerror = NULL;
365 rv->statement = NULL;
366 rv->stmt_with_params = NULL;
367 rv->load_statement = NULL;
368 rv->execute_statement = NULL;
369 rv->stmt_size_limit = -1;
370 rv->statement_type = STMT_TYPE_UNKNOWN;
372 rv->currTuple = -1;
373 SC_set_rowset_start(rv, -1, FALSE);
374 rv->current_col = -1;
375 rv->bind_row = 0;
376 rv->last_fetch_count = rv->last_fetch_count_include_ommitted =
378 rv->save_rowset_size = -1;
380 rv->data_at_exec = -1;
381 rv->current_exec_param = -1;
382 rv->exec_start_row = -1;
383 rv->exec_end_row = -1;
384 rv->exec_current_row = -1;
385 rv->put_data = FALSE;
386 rv->ref_CC_error = FALSE;
387 rv->lock_CC_for_rb = 0;
388 rv->join_info = 0;
389 SC_init_parse_method(rv);
391 INIT_NAME(rv->cursor_name);
393 /* Parse Stuff */
394 rv->ti = NULL;
395 rv->ntab = 0;
396 rv->num_key_fields = -1; /* unknown */
397 SC_clear_parse_status(rv, conn);
398 rv->proc_return = -1;
399 SC_init_discard_output_params(rv);
400 rv->cancel_info = 0;
402 /* Clear Statement Options -- defaults will be set in AllocStmt */
403 memset(&rv->options, 0, sizeof(StatementOptions));
404 InitializeEmbeddedDescriptor((DescriptorClass *) & (rv->ardi),
405 rv, SQL_ATTR_APP_ROW_DESC);
406 InitializeEmbeddedDescriptor((DescriptorClass *) & (rv->apdi),
407 rv, SQL_ATTR_APP_PARAM_DESC);
408 InitializeEmbeddedDescriptor((DescriptorClass *) & (rv->irdi),
409 rv, SQL_ATTR_IMP_ROW_DESC);
410 InitializeEmbeddedDescriptor((DescriptorClass *) & (rv->ipdi),
411 rv, SQL_ATTR_IMP_PARAM_DESC);
413 rv->pre_executing = FALSE;
414 rv->inaccurate_result = FALSE;
415 rv->miscinfo = 0;
416 rv->updatable = FALSE;
417 rv->diag_row_count = 0;
418 rv->stmt_time = 0;
419 rv->execute_delegate = NULL;
420 rv->execute_parent = NULL;
421 rv->allocated_callbacks = 0;
422 rv->num_callbacks = 0;
423 rv->callbacks = NULL;
424 GetDataInfoInitialize(SC_get_GDTI(rv));
425 INIT_STMT_CS(rv);
427 return rv;
430 char SC_Destructor(StatementClass * self)
432 CSTR func = "SC_Destrcutor";
433 QResultClass *res = SC_get_Result(self);
435 if (!self)
436 return FALSE;
437 mylog("self=%p, self->result=%p, self->hdbc=%p\n",
438 self, res, self->hdbc);
439 SC_clear_error(self);
440 if (STMT_EXECUTING == self->status)
442 SC_set_error(self, STMT_SEQUENCE_ERROR,
443 "Statement is currently executing a transaction.",
444 func);
445 return FALSE;
448 if (res)
450 if (!self->hdbc)
451 res->conn = NULL; /* prevent any dbase activity */
453 QR_Destructor(res);
456 SC_initialize_stmts(self, TRUE);
458 /* Free the parsed table information */
459 SC_initialize_cols_info(self, FALSE, TRUE);
461 NULL_THE_NAME(self->cursor_name);
462 /* Free the parsed field information */
463 DC_Destructor((DescriptorClass *) SC_get_ARDi(self));
464 DC_Destructor((DescriptorClass *) SC_get_APDi(self));
465 DC_Destructor((DescriptorClass *) SC_get_IRDi(self));
466 DC_Destructor((DescriptorClass *) SC_get_IPDi(self));
467 GDATA_unbind_cols(SC_get_GDTI(self), TRUE);
469 if (self->__error_message)
470 free(self->__error_message);
471 if (self->pgerror)
472 ER_Destructor(self->pgerror);
473 cancelNeedDataState(self);
474 if (self->callbacks)
475 free(self->callbacks);
477 DELETE_STMT_CS(self);
478 free(self);
480 mylog("done\n");
481 return TRUE;
485 int statement_type(const char *statement)
487 int i;
489 /* ignore leading whitespace in query string */
490 while (*statement
491 && (isspace((UCHAR) * statement) || *statement == '('))
492 statement++;
494 for (i = 0; Statement_Type[i].s; i++)
495 if (!strnicmp
496 (statement, Statement_Type[i].s,
497 strlen(Statement_Type[i].s)))
498 return Statement_Type[i].type;
500 return STMT_TYPE_OTHER;
503 void SC_set_planname(StatementClass * stmt, const char *plan_name)
505 if (stmt->plan_name)
506 free(stmt->plan_name);
507 if (plan_name && plan_name[0])
508 stmt->plan_name = strdup(plan_name);
509 else
510 stmt->plan_name = NULL;
513 void
514 SC_set_rowset_start(StatementClass * stmt, SQLLEN start,
515 BOOL valid_base)
517 QResultClass *res = SC_get_Curres(stmt);
518 SQLLEN incr = start - stmt->rowset_start;
520 inolog("%p->SC_set_rowstart " FORMAT_LEN "->" FORMAT_LEN "(%s) ",
521 stmt, stmt->rowset_start, start,
522 valid_base ? "valid" : "unknown");
523 if (res != NULL)
525 BOOL valid = QR_has_valid_base(res);
526 inolog(":QR is %s",
527 QR_has_valid_base(res) ? "valid" : "unknown");
529 if (valid)
531 if (valid_base)
532 QR_inc_rowstart_in_cache(res, incr);
533 else
534 QR_set_no_valid_base(res);
535 } else if (valid_base)
537 QR_set_has_valid_base(res);
538 if (start < 0)
539 QR_set_rowstart_in_cache(res, -1);
540 else
541 QR_set_rowstart_in_cache(res, 0);
543 if (!QR_get_cursor(res))
544 res->key_base = start;
545 inolog(":QR result=" FORMAT_LEN "(%s)",
546 QR_get_rowstart_in_cache(res),
547 QR_has_valid_base(res) ? "valid" : "unknown");
549 stmt->rowset_start = start;
550 inolog(":stmt result=" FORMAT_LEN "\n", stmt->rowset_start);
553 void SC_inc_rowset_start(StatementClass * stmt, SQLLEN inc)
555 SQLLEN start = stmt->rowset_start + inc;
557 SC_set_rowset_start(stmt, start, TRUE);
559 int SC_set_current_col(StatementClass * stmt, int col)
561 if (col == stmt->current_col)
562 return col;
563 if (col >= 0)
564 reset_a_getdata_info(SC_get_GDTI(stmt), col + 1);
565 stmt->current_col = col;
567 return stmt->current_col;
570 // VX_CLEANUP: We don't support much in the way of prepared statements, this
571 // may be unused. It sure is useless.
572 void SC_set_prepared(StatementClass * stmt, BOOL prepared)
574 if (NOT_YET_PREPARED == prepared)
575 SC_set_planname(stmt, NULL);
576 stmt->prepared = prepared;
580 * Initialize stmt_with_params, load_statement and execute_statement
581 * member pointer deallocating corresponding prepared plan.
582 * Also initialize statement member pointer if specified.
584 RETCODE
585 SC_initialize_stmts(StatementClass * self, BOOL initializeOriginal)
587 ConnectionClass *conn = SC_get_conn(self);
589 if (self->lock_CC_for_rb > 0)
591 while (self->lock_CC_for_rb > 0)
593 LEAVE_CONN_CS(conn);
594 self->lock_CC_for_rb--;
597 if (initializeOriginal)
599 if (self->statement)
601 free(self->statement);
602 self->statement = NULL;
604 if (self->execute_statement)
606 free(self->execute_statement);
607 self->execute_statement = NULL;
609 self->prepare = NON_PREPARE_STATEMENT;
610 SC_set_prepared(self, NOT_YET_PREPARED);
611 self->statement_type = STMT_TYPE_UNKNOWN; /* unknown */
612 self->multi_statement = -1; /* unknown */
613 self->num_params = -1; /* unknown */
614 self->proc_return = -1; /* unknown */
615 self->join_info = 0;
616 SC_init_parse_method(self);
617 SC_init_discard_output_params(self);
619 if (self->stmt_with_params)
621 free(self->stmt_with_params);
622 self->stmt_with_params = NULL;
624 if (self->load_statement)
626 free(self->load_statement);
627 self->load_statement = NULL;
630 return 0;
633 BOOL SC_opencheck(StatementClass * self, const char *func)
635 QResultClass *res;
637 if (!self)
638 return FALSE;
639 if (self->status == STMT_EXECUTING)
641 SC_set_error(self, STMT_SEQUENCE_ERROR,
642 "Statement is currently executing a transaction.",
643 func);
644 return TRUE;
647 * We can dispose the result of PREMATURE execution any time.
649 if (self->prepare && self->status == STMT_PREMATURE)
651 mylog
652 ("SC_opencheck: self->prepare && self->status == STMT_PREMATURE\n");
653 return FALSE;
655 if (res = SC_get_Curres(self), NULL != res)
657 if (QR_command_maybe_successful(res) && res->backend_tuples)
659 SC_set_error(self, STMT_SEQUENCE_ERROR,
660 "The cursor is open.", func);
661 return TRUE;
665 return FALSE;
668 RETCODE SC_initialize_and_recycle(StatementClass * self)
670 SC_initialize_stmts(self, TRUE);
671 if (!SC_recycle_statement(self))
672 return SQL_ERROR;
674 return SQL_SUCCESS;
678 * Called from SQLPrepare if STMT_PREMATURE, or
679 * from SQLExecute if STMT_FINISHED, or
680 * from SQLFreeStmt(SQL_CLOSE)
682 char SC_recycle_statement(StatementClass * self)
684 CSTR func = "SC_recycle_statement";
685 ConnectionClass *conn;
686 QResultClass *res;
688 mylog("%s: self= %p\n", func, self);
690 SC_clear_error(self);
691 /* This would not happen */
692 if (self->status == STMT_EXECUTING)
694 SC_set_error(self, STMT_SEQUENCE_ERROR,
695 "Statement is currently executing a transaction.",
696 func);
697 return FALSE;
700 conn = SC_get_conn(self);
701 switch (self->status)
703 case STMT_ALLOCATED:
704 /* this statement does not need to be recycled */
705 return TRUE;
707 case STMT_READY:
708 break;
710 case STMT_PREMATURE:
713 * Premature execution of the statement might have caused the
714 * start of a transaction. If so, we have to rollback that
715 * transaction.
717 // VX_CLEANUP: This was cleaned up.
718 break;
720 case STMT_FINISHED:
721 break;
723 default:
724 SC_set_error(self, STMT_INTERNAL_ERROR,
725 "An internal error occured while recycling statements",
726 func);
727 return FALSE;
730 switch (self->prepared)
732 case NOT_YET_PREPARED:
733 case ONCE_DESCRIBED:
734 /* Free the parsed table/field information */
735 SC_initialize_cols_info(self, TRUE, TRUE);
737 inolog("SC_clear_parse_status\n");
738 SC_clear_parse_status(self, conn);
739 break;
742 /* Free any cursors */
743 if (res = SC_get_Result(self), res)
745 if (PREPARED_PERMANENTLY == self->prepared)
746 QR_close_result(res, FALSE);
747 else
749 QR_Destructor(res);
750 SC_init_Result(self);
753 self->inaccurate_result = FALSE;
754 self->miscinfo = 0;
757 * Reset only parameters that have anything to do with results
759 self->status = STMT_READY;
760 self->catalog_result = FALSE; /* not very important */
762 self->currTuple = -1;
763 SC_set_rowset_start(self, -1, FALSE);
764 SC_set_current_col(self, -1);
765 self->bind_row = 0;
766 inolog("%s statement=%p ommitted=0\n", func, self);
767 self->last_fetch_count = self->last_fetch_count_include_ommitted =
770 self->__error_message = NULL;
771 self->__error_number = 0;
773 SC_initialize_stmts(self, FALSE);
774 cancelNeedDataState(self);
775 self->cancel_info = 0;
777 * reset the current attr setting to the original one.
779 self->options.scroll_concurrency =
780 self->options_orig.scroll_concurrency;
781 self->options.cursor_type = self->options_orig.cursor_type;
782 self->options.keyset_size = self->options_orig.keyset_size;
783 self->options.maxLength = self->options_orig.maxLength;
784 self->options.maxRows = self->options_orig.maxRows;
786 return TRUE;
791 * Pre-execute a statement (for SQLPrepare/SQLDescribeCol)
793 Int4 /* returns # of fields if successful */
794 SC_pre_execute(StatementClass * self)
796 Int4 num_fields = -1;
797 QResultClass *res;
798 mylog("SC_pre_execute: status = %d\n", self->status);
800 res = SC_get_Curres(self);
801 if (res && (num_fields = QR_NumResultCols(res)) > 0)
802 return num_fields;
804 mylog("SC_pre_execute: Unknown result/number of columns\n");
805 return -1;
809 /* This is only called from SQLFreeStmt(SQL_UNBIND) */
810 char SC_unbind_cols(StatementClass * self)
812 ARDFields *opts = SC_get_ARDF(self);
813 GetDataInfo *gdata = SC_get_GDTI(self);
814 BindInfoClass *bookmark;
816 ARD_unbind_cols(opts, FALSE);
817 GDATA_unbind_cols(gdata, FALSE);
818 if (bookmark = opts->bookmark, bookmark != NULL)
820 bookmark->buffer = NULL;
821 bookmark->used = NULL;
824 return 1;
828 void SC_clear_error(StatementClass * self)
830 QResultClass *res;
832 self->__error_number = 0;
833 if (self->__error_message)
835 free(self->__error_message);
836 self->__error_message = NULL;
838 if (self->pgerror)
840 ER_Destructor(self->pgerror);
841 self->pgerror = NULL;
843 self->diag_row_count = 0;
844 if (res = SC_get_Curres(self), res)
846 QR_set_message(res, NULL);
847 QR_set_notice(res, NULL);
848 res->sqlstate[0] = '\0';
850 self->stmt_time = 0;
851 SC_unref_CC_error(self);
856 * This function creates an error info which is the concatenation
857 * of the result, statement, connection, and socket messages.
860 /* Map sql commands to statement types */
861 static struct {
862 int number;
863 const char *ver3str;
864 const char *ver2str;
865 } Statement_sqlstate[] =
868 STMT_ERROR_IN_ROW, "01S01", "01S01"},
870 STMT_OPTION_VALUE_CHANGED, "01S02", "01S02"},
872 STMT_ROW_VERSION_CHANGED, "01001", "01001"}, /* data changed */
874 STMT_POS_BEFORE_RECORDSET, "01S06", "01S06"},
876 STMT_TRUNCATED, "01004", "01004"}, /* data truncated */
878 STMT_INFO_ONLY, "00000", "00000"}, /* just an information that is returned, no error */
880 STMT_OK, "00000", "00000"}, /* OK */
882 STMT_EXEC_ERROR, "HY000", "S1000"}, /* also a general error */
884 STMT_STATUS_ERROR, "HY010", "S1010"},
886 STMT_SEQUENCE_ERROR, "HY010", "S1010"}, /* Function sequence error */
888 STMT_NO_MEMORY_ERROR, "HY001", "S1001"}, /* memory allocation failure */
890 STMT_COLNUM_ERROR, "07009", "S1002"}, /* invalid column number */
892 STMT_NO_STMTSTRING, "HY001", "S1001"}, /* having no stmtstring is also a malloc problem */
894 STMT_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000"}, /* general error */
896 STMT_INTERNAL_ERROR, "HY000", "S1000"}, /* general error */
898 STMT_STILL_EXECUTING, "HY010", "S1010"},
900 STMT_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00"}, /* == 'driver not
901 * capable' */
903 STMT_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093"},
905 STMT_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092"},
907 STMT_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002"},
909 STMT_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006"},
911 STMT_INVALID_CURSOR_STATE_ERROR, "07005", "24000"},
913 STMT_CREATE_TABLE_ERROR, "42S01", "S0001"}, /* table already exists */
915 STMT_NO_CURSOR_NAME, "S1015", "S1015"},
917 STMT_INVALID_CURSOR_NAME, "34000", "34000"},
919 STMT_INVALID_ARGUMENT_NO, "HY024", "S1009"}, /* invalid argument value */
921 STMT_ROW_OUT_OF_RANGE, "HY107", "S1107"},
923 STMT_OPERATION_CANCELLED, "HY008", "S1008"},
925 STMT_INVALID_CURSOR_POSITION, "HY109", "S1109"},
927 STMT_VALUE_OUT_OF_RANGE, "HY019", "22003"},
929 STMT_OPERATION_INVALID, "HY011", "S1011"},
931 STMT_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????"},
933 STMT_BAD_ERROR, "08S01", "08S01"}, /* communication link failure */
935 STMT_INVALID_OPTION_IDENTIFIER, "HY092", "HY092"},
937 STMT_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002"},
939 STMT_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091"},
941 STMT_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00"},
943 STMT_FETCH_OUT_OF_RANGE, "HY106", "S1106"},
945 STMT_COUNT_FIELD_INCORRECT, "07002", "07002"},
947 STMT_INVALID_NULL_ARG, "HY009", "S1009"}
950 static PG_ErrorInfo *SC_create_errorinfo(const StatementClass * self)
952 QResultClass *res = SC_get_Curres(self);
953 ConnectionClass *conn = SC_get_conn(self);
954 Int4 errornum;
955 size_t pos;
956 BOOL resmsg = FALSE, detailmsg = FALSE, msgend = FALSE;
957 char msg[4096], *wmsg;
958 char *ermsg = NULL, *sqlstate = NULL;
959 PG_ErrorInfo *pgerror;
961 if (self->pgerror)
962 return self->pgerror;
963 errornum = self->__error_number;
964 if (errornum == 0)
965 return NULL;
967 msg[0] = '\0';
968 if (res)
970 if (res->sqlstate[0])
971 sqlstate = res->sqlstate;
972 if (res->message)
974 strncpy(msg, res->message, sizeof(msg));
975 detailmsg = resmsg = TRUE;
977 if (msg[0])
978 ermsg = msg;
979 else if (QR_get_notice(res))
981 char *notice = QR_get_notice(res);
982 size_t len = strlen(notice);
983 if (len < sizeof(msg))
985 memcpy(msg, notice, len);
986 msg[len] = '\0';
987 ermsg = msg;
988 } else
990 ermsg = notice;
991 msgend = TRUE;
995 if (!msgend && (wmsg = SC_get_errormsg(self)) && wmsg[0])
997 pos = strlen(msg);
999 if (detailmsg)
1001 msg[pos++] = ';';
1002 msg[pos++] = '\n';
1004 strncpy(msg + pos, wmsg, sizeof(msg) - pos);
1005 ermsg = msg;
1006 detailmsg = TRUE;
1008 if (!self->ref_CC_error)
1009 msgend = TRUE;
1011 if (conn && !msgend)
1013 // VX_CLEANUP: This is suspiciously similar to CC_create_errormsg, and
1014 // just as useless now that there's no socket error message.
1015 if (!resmsg && (wmsg = CC_get_errormsg(conn))
1016 && wmsg[0] != '\0')
1018 pos = strlen(msg);
1019 snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s",
1020 CC_get_errormsg(conn));
1023 ermsg = msg;
1025 pgerror = ER_Constructor(self->__error_number, ermsg);
1026 if (sqlstate)
1027 strcpy(pgerror->sqlstate, sqlstate);
1028 else if (conn)
1030 if (!msgend && conn->sqlstate[0])
1031 strcpy(pgerror->sqlstate, conn->sqlstate);
1032 else
1034 EnvironmentClass *env = (EnvironmentClass *) conn->henv;
1036 errornum -= LOWEST_STMT_ERROR;
1037 if (errornum < 0 ||
1038 errornum >=
1039 sizeof(Statement_sqlstate) /
1040 sizeof(Statement_sqlstate[0]))
1041 errornum = 1 - LOWEST_STMT_ERROR;
1042 strcpy(pgerror->sqlstate, EN_is_odbc3(env) ?
1043 Statement_sqlstate[errornum].ver3str :
1044 Statement_sqlstate[errornum].ver2str);
1048 return pgerror;
1052 StatementClass *SC_get_ancestor(StatementClass * stmt)
1054 StatementClass *child = stmt, *parent;
1056 inolog("SC_get_ancestor in stmt=%p\n", stmt);
1057 for (child = stmt, parent = child->execute_parent; parent;
1058 child = parent, parent = child->execute_parent)
1060 inolog("parent=%p\n", parent);
1062 return child;
1065 void SC_reset_delegate(RETCODE retcode, StatementClass * stmt)
1067 StatementClass *delegate = stmt->execute_delegate;
1069 if (!delegate)
1070 return;
1071 PGAPI_FreeStmt(delegate, SQL_DROP);
1074 void
1075 SC_set_error(StatementClass * self, int number, const char *message,
1076 const char *func)
1078 if (self->__error_message)
1079 free(self->__error_message);
1080 self->__error_number = number;
1081 self->__error_message = message ? strdup(message) : NULL;
1082 if (func && number != STMT_OK && number != STMT_INFO_ONLY)
1083 SC_log_error(func, "", self);
1087 void SC_set_errormsg(StatementClass * self, const char *message)
1089 if (self->__error_message)
1090 free(self->__error_message);
1091 self->__error_message = message ? strdup(message) : NULL;
1095 void
1096 SC_replace_error_with_res(StatementClass * self, int number,
1097 const char *message,
1098 const QResultClass * from_res, BOOL check)
1100 QResultClass *self_res;
1101 BOOL repstate;
1103 inolog("SC_set_error_from_res %p->%p check=%i\n", from_res, self,
1104 check);
1105 if (check)
1107 if (0 == number)
1108 return;
1109 if (0 > number && /* SQL_SUCCESS_WITH_INFO */
1110 0 < self->__error_number)
1111 return;
1113 self->__error_number = number;
1114 if (!check || message)
1116 if (self->__error_message)
1117 free(self->__error_message);
1118 self->__error_message = message ? strdup(message) : NULL;
1120 if (self->pgerror)
1122 ER_Destructor(self->pgerror);
1123 self->pgerror = NULL;
1125 self_res = SC_get_Curres(self);
1126 if (!self_res)
1127 return;
1128 if (self_res == from_res)
1129 return;
1130 QR_add_message(self_res, QR_get_message(from_res));
1131 QR_add_notice(self_res, QR_get_notice(from_res));
1132 repstate = FALSE;
1133 if (!check)
1134 repstate = TRUE;
1135 else if (from_res->sqlstate[0])
1137 if (!self_res->sqlstate[0]
1138 || strncmp(self_res->sqlstate, "00", 2) == 0)
1139 repstate = TRUE;
1140 else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
1141 repstate = TRUE;
1143 if (repstate)
1144 strcpy(self_res->sqlstate, from_res->sqlstate);
1147 void
1148 SC_error_copy(StatementClass * self, const StatementClass * from,
1149 BOOL check)
1151 QResultClass *self_res, *from_res;
1152 BOOL repstate;
1154 inolog("SC_error_copy %p->%p check=%i\n", from, self, check);
1155 if (self == from)
1156 return;
1157 if (check)
1159 if (0 == from->__error_number) /* SQL_SUCCESS */
1160 return;
1161 if (0 > from->__error_number && /* SQL_SUCCESS_WITH_INFO */
1162 0 < self->__error_number)
1163 return;
1165 self->__error_number = from->__error_number;
1166 if (!check || from->__error_message)
1168 if (self->__error_message)
1169 free(self->__error_message);
1170 self->__error_message =
1171 from->__error_message ? strdup(from->
1172 __error_message) : NULL;
1174 if (self->pgerror)
1176 ER_Destructor(self->pgerror);
1177 self->pgerror = NULL;
1179 self_res = SC_get_Curres(self);
1180 from_res = SC_get_Curres(from);
1181 if (!self_res || !from_res)
1182 return;
1183 QR_add_message(self_res, QR_get_message(from_res));
1184 QR_add_notice(self_res, QR_get_notice(from_res));
1185 repstate = FALSE;
1186 if (!check)
1187 repstate = TRUE;
1188 else if (from_res->sqlstate[0])
1190 if (!self_res->sqlstate[0]
1191 || strncmp(self_res->sqlstate, "00", 2) == 0)
1192 repstate = TRUE;
1193 else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
1194 repstate = TRUE;
1196 if (repstate)
1197 strcpy(self_res->sqlstate, from_res->sqlstate);
1201 void
1202 SC_full_error_copy(StatementClass * self, const StatementClass * from,
1203 BOOL allres)
1205 PG_ErrorInfo *pgerror;
1207 inolog("SC_full_error_copy %p->%p\n", from, self);
1208 if (self->__error_message)
1210 free(self->__error_message);
1211 self->__error_message = NULL;
1213 if (from->__error_message)
1214 self->__error_message = strdup(from->__error_message);
1215 self->__error_number = from->__error_number;
1216 if (from->pgerror)
1218 if (self->pgerror)
1219 ER_Destructor(self->pgerror);
1220 self->pgerror = ER_Dup(from->pgerror);
1221 return;
1222 } else if (!allres)
1223 return;
1224 pgerror = SC_create_errorinfo(from);
1225 if (!pgerror->__error_message[0])
1227 ER_Destructor(pgerror);
1228 return;
1230 if (self->pgerror)
1231 ER_Destructor(self->pgerror);
1232 self->pgerror = pgerror;
1235 /* Returns the next SQL error information. */
1236 RETCODE SQL_API
1237 PGAPI_StmtError(SQLHSTMT hstmt,
1238 SQLSMALLINT RecNumber,
1239 SQLCHAR FAR * szSqlState,
1240 SQLINTEGER FAR * pfNativeError,
1241 SQLCHAR FAR * szErrorMsg,
1242 SQLSMALLINT cbErrorMsgMax,
1243 SQLSMALLINT FAR * pcbErrorMsg, UWORD flag)
1245 /* CC: return an error of a hdesc */
1246 StatementClass *stmt = (StatementClass *) hstmt;
1248 stmt->pgerror = SC_create_errorinfo(stmt);
1249 return ER_ReturnError(&(stmt->pgerror), RecNumber, szSqlState,
1250 pfNativeError, szErrorMsg, cbErrorMsgMax,
1251 pcbErrorMsg, flag);
1254 time_t SC_get_time(StatementClass * stmt)
1256 if (!stmt)
1257 return time(NULL);
1258 if (0 == stmt->stmt_time)
1259 stmt->stmt_time = time(NULL);
1260 return stmt->stmt_time;
1264 * Currently, the driver offers very simple bookmark support -- it is
1265 * just the current row number. But it could be more sophisticated
1266 * someday, such as mapping a key to a 32 bit value
1268 SQLULEN SC_get_bookmark(StatementClass * self)
1270 return SC_make_bookmark(self->currTuple);
1274 RETCODE SC_fetch(StatementClass * self)
1276 CSTR func = "SC_fetch";
1277 QResultClass *res = SC_get_Curres(self);
1278 ARDFields *opts;
1279 GetDataInfo *gdata;
1280 int retval;
1281 RETCODE result;
1283 Int2 num_cols, lf;
1284 OID type;
1285 char *value;
1286 ColumnInfoClass *coli;
1287 BindInfoClass *bookmark;
1289 inolog("%s statement=%p ommitted=0\n", func, self);
1290 self->last_fetch_count = self->last_fetch_count_include_ommitted =
1292 coli = QR_get_fields(res); /* the column info */
1294 mylog("fetch_cursor=%d, %p->total_read=%d\n",
1295 0 /*SC_is_fetchcursor(self)*/, res, res->num_total_read);
1297 if (self->currTuple >= (Int4) QR_get_num_total_tuples(res) - 1
1298 || (self->options.maxRows > 0
1299 && self->currTuple == self->options.maxRows - 1))
1302 * if at the end of the tuples, return "no data found" and set
1303 * the cursor past the end of the result set
1305 self->currTuple = QR_get_num_total_tuples(res);
1306 return SQL_NO_DATA_FOUND;
1309 mylog("**** %s: non-cursor_result\n", func);
1310 (self->currTuple)++;
1312 if (QR_haskeyset(res))
1314 SQLLEN kres_ridx;
1316 kres_ridx = GIdx2KResIdx(self->currTuple, self, res);
1317 if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
1319 UWORD pstatus = res->keyset[kres_ridx].status;
1320 inolog("SC_ pstatus[%d]=%hx fetch_count=" FORMAT_LEN "\n",
1321 kres_ridx, pstatus, self->last_fetch_count);
1322 if (0 !=
1323 (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
1324 return SQL_SUCCESS_WITH_INFO;
1325 if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
1326 0 != (pstatus & CURS_OTHER_DELETED))
1327 return SQL_SUCCESS_WITH_INFO;
1328 if (0 != (CURS_NEEDS_REREAD & pstatus))
1330 UWORD qcount;
1332 result =
1333 SC_pos_reload(self, self->currTuple, &qcount, 0);
1334 if (SQL_ERROR == result)
1335 return result;
1336 pstatus &= ~CURS_NEEDS_REREAD;
1341 num_cols = QR_NumPublicResultCols(res);
1343 result = SQL_SUCCESS;
1344 self->last_fetch_count++;
1345 inolog("%s: stmt=%p ommitted++\n", func, self);
1346 self->last_fetch_count_include_ommitted++;
1348 opts = SC_get_ARDF(self);
1350 * If the bookmark column was bound then return a bookmark. Since this
1351 * is used with SQLExtendedFetch, and the rowset size may be greater
1352 * than 1, and an application can use row or column wise binding, use
1353 * the code in copy_and_convert_field() to handle that.
1355 if ((bookmark = opts->bookmark) && bookmark->buffer)
1357 char buf[32];
1358 SQLLEN offset =
1359 opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
1361 sprintf(buf, FORMAT_ULEN, SC_get_bookmark(self));
1362 SC_set_current_col(self, -1);
1363 result = copy_and_convert_field(self, 0, buf,
1364 SQL_C_ULONG,
1365 bookmark->buffer + offset, 0,
1366 LENADDR_SHIFT(bookmark->used,
1367 offset),
1368 LENADDR_SHIFT(bookmark->used,
1369 offset));
1372 if (self->options.retrieve_data == SQL_RD_OFF) /* data isn't required */
1373 return SQL_SUCCESS;
1374 gdata = SC_get_GDTI(self);
1375 if (gdata->allocated != opts->allocated)
1376 extend_getdata_info(gdata, opts->allocated, TRUE);
1377 for (lf = 0; lf < num_cols; lf++)
1379 mylog
1380 ("fetch: cols=%d, lf=%d, opts = %p, opts->bindings = %p, buffer[] = %p\n",
1381 num_cols, lf, opts, opts->bindings,
1382 opts->bindings[lf].buffer);
1384 /* reset for SQLGetData */
1385 gdata->gdata[lf].data_left = -1;
1387 if (NULL == opts->bindings)
1388 continue;
1389 if (opts->bindings[lf].buffer != NULL)
1391 /* this column has a binding */
1393 /* type = QR_get_field_type(res, lf); */
1394 type = CI_get_oid(coli, lf); /* speed things up */
1396 mylog("type = %d\n", type);
1398 SQLLEN curt = GIdx2CacheIdx(self->currTuple, self, res);
1399 inolog("base=%d curr=%d st=%d\n",
1400 QR_get_rowstart_in_cache(res), self->currTuple,
1401 SC_get_rowset_start(self));
1402 inolog("curt=%d\n", curt);
1403 value = (char *)QR_get_value_backend_row(res, curt, lf);
1405 mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
1407 retval =
1408 copy_and_convert_field_bindinfo(self, type, value, lf);
1410 mylog("copy_and_convert: retval = %d\n", retval);
1412 switch (retval)
1414 case COPY_OK:
1415 break; /* OK, do next bound column */
1417 case COPY_UNSUPPORTED_TYPE:
1418 SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR,
1419 "Received an unsupported type from Postgres.",
1420 func);
1421 result = SQL_ERROR;
1422 break;
1424 case COPY_UNSUPPORTED_CONVERSION:
1425 SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR,
1426 "Couldn't handle the necessary data type conversion.",
1427 func);
1428 result = SQL_ERROR;
1429 break;
1431 case COPY_RESULT_TRUNCATED:
1432 SC_set_error(self, STMT_TRUNCATED,
1433 "Fetched item was truncated.", func);
1434 qlog("The %dth item was truncated\n", lf + 1);
1435 qlog("The buffer size = %d", opts->bindings[lf].buflen);
1436 qlog(" and the value is '%s'\n", value);
1437 result = SQL_SUCCESS_WITH_INFO;
1438 break;
1440 /* error msg already filled in */
1441 case COPY_GENERAL_ERROR:
1442 result = SQL_ERROR;
1443 break;
1445 /* This would not be meaningful in SQLFetch. */
1446 case COPY_NO_DATA_FOUND:
1447 break;
1449 default:
1450 SC_set_error(self, STMT_INTERNAL_ERROR,
1451 "Unrecognized return value from copy_and_convert_field.",
1452 func);
1453 result = SQL_ERROR;
1454 break;
1459 return result;
1463 #define CALLBACK_ALLOC_ONCE 4
1464 int enqueueNeedDataCallback(StatementClass * stmt,
1465 NeedDataCallfunc func, void *data)
1467 if (stmt->num_callbacks >= stmt->allocated_callbacks)
1469 stmt->callbacks = (NeedDataCallback *) realloc(stmt->callbacks,
1470 sizeof
1471 (NeedDataCallback)
1473 (stmt->
1474 allocated_callbacks
1476 CALLBACK_ALLOC_ONCE));
1477 stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE;
1479 stmt->callbacks[stmt->num_callbacks].func = func;
1480 stmt->callbacks[stmt->num_callbacks].data = data;
1481 stmt->num_callbacks++;
1483 inolog("enqueueNeedDataCallack stmt=%p, func=%p, count=%d\n", stmt,
1484 func, stmt->num_callbacks);
1485 return stmt->num_callbacks;
1488 RETCODE dequeueNeedDataCallback(RETCODE retcode, StatementClass * stmt)
1490 RETCODE ret;
1491 NeedDataCallfunc func;
1492 void *data;
1493 int i, cnt;
1495 mylog("dequeueNeedDataCallback ret=%d count=%d\n", retcode,
1496 stmt->num_callbacks);
1497 if (SQL_NEED_DATA == retcode)
1498 return retcode;
1499 if (stmt->num_callbacks <= 0)
1500 return retcode;
1501 func = stmt->callbacks[0].func;
1502 data = stmt->callbacks[0].data;
1503 for (i = 1; i < stmt->num_callbacks; i++)
1504 stmt->callbacks[i - 1] = stmt->callbacks[i];
1505 cnt = --stmt->num_callbacks;
1506 ret = (*func) (retcode, data);
1507 free(data);
1508 if (SQL_NEED_DATA != ret && cnt > 0)
1509 ret = dequeueNeedDataCallback(ret, stmt);
1510 return ret;
1513 void cancelNeedDataState(StatementClass * stmt)
1515 int cnt = stmt->num_callbacks, i;
1517 stmt->num_callbacks = 0;
1518 for (i = 0; i < cnt; i++)
1520 if (stmt->callbacks[i].data)
1521 free(stmt->callbacks[i].data);
1523 SC_reset_delegate(SQL_ERROR, stmt);
1526 void
1527 SC_log_error(const char *func, const char *desc,
1528 const StatementClass * self)
1530 const char *head;
1531 #ifdef PRN_NULLCHECK
1532 #define nullcheck(a) (a ? a : "(NULL)")
1533 #endif
1534 if (self)
1536 QResultClass *res = SC_get_Result(self);
1537 const ARDFields *opts = SC_get_ARDF(self);
1538 const APDFields *apdopts = SC_get_APDF(self);
1539 SQLLEN rowsetSize;
1541 rowsetSize =
1542 (7 ==
1543 self->transition_status ? opts->
1544 size_of_rowset_odbc2 : opts->size_of_rowset);
1545 if (SC_get_errornumber(self) <= 0)
1546 head = "STATEMENT WARNING";
1547 else
1549 head = "STATEMENT ERROR";
1550 qlog("%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1551 head, func, desc, self->__error_number,
1552 nullcheck(self->__error_message));
1554 mylog("%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", head,
1555 func, desc, self->__error_number,
1556 nullcheck(self->__error_message));
1557 if (SC_get_errornumber(self) > 0)
1559 qlog(" ------------------------------------------------------------\n");
1560 qlog(" hdbc=%p, stmt=%p, result=%p\n",
1561 self->hdbc, self, res);
1562 qlog(" prepare=%d, internal=%d\n",
1563 self->prepare, self->internal);
1564 qlog(" bindings=%p, bindings_allocated=%d\n", opts->bindings, opts->allocated);
1565 qlog(" parameters=%p, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
1566 qlog(" statement_type=%d, statement='%s'\n",
1567 self->statement_type, nullcheck(self->statement));
1568 qlog(" stmt_with_params='%s'\n",
1569 nullcheck(self->stmt_with_params));
1570 qlog(" data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
1571 qlog(" currTuple=%d, current_col=%d\n", self->currTuple, self->current_col);
1572 qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
1573 qlog(" cursor_name='%s'\n",
1574 SC_cursor_name(self));
1576 qlog(" ----------------QResult Info -------------------------------\n");
1578 if (res)
1580 qlog(" fields=%p, backend_tuples=%p, tupleField=%d, conn=%p\n", res->fields, res->backend_tuples, res->tupleField, res->conn);
1581 qlog(" fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_number, QR_get_num_total_tuples(res), res->num_fields, nullcheck(QR_get_cursor(res)));
1582 qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
1583 qlog(" status=%d, inTuples=%d\n",
1584 QR_get_rstatus(res), QR_is_fetching_tuples(res));
1587 /* Log the connection error if there is one */
1588 CC_log_error(func, desc, self->hdbc);
1590 } else
1592 qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n",
1593 func, desc);
1594 mylog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n",
1595 func, desc);
1597 #undef PRN_NULLCHECK
1601 * Extended Query
1604 enum {
1605 CancelRequestSet = 1L, CancelRequestAccepted =
1606 (1L << 1), CancelCompleted = (1L << 2)
1608 /* commonly used for short term lock */
1609 #if defined(WIN_MULTITHREAD_SUPPORT)
1610 extern CRITICAL_SECTION common_cs;
1611 #elif defined(POSIX_MULTITHREAD_SUPPORT)
1612 extern pthread_mutex_t common_cs;
1613 #endif /* WIN_MULTITHREAD_SUPPORT */
1614 BOOL SC_IsExecuting(const StatementClass * self)
1616 BOOL ret;
1617 ENTER_COMMON_CS; /* short time blocking */
1618 ret = (STMT_EXECUTING == self->status);
1619 LEAVE_COMMON_CS;
1620 return ret;
1623 BOOL SC_SetExecuting(StatementClass * self, BOOL on)
1625 BOOL exeSet = FALSE;
1626 ENTER_COMMON_CS; /* short time blocking */
1627 if (on)
1629 if (0 == (self->cancel_info & CancelRequestSet))
1631 self->status = STMT_EXECUTING;
1632 exeSet = TRUE;
1634 } else
1636 self->cancel_info = 0;
1637 self->status = STMT_FINISHED;
1638 exeSet = TRUE;
1640 LEAVE_COMMON_CS;
1641 return exeSet;
1644 BOOL SC_SetCancelRequest(StatementClass * self)
1646 BOOL enteredCS = FALSE;
1648 ENTER_COMMON_CS;
1649 if (0 != (self->cancel_info & CancelCompleted))
1651 else if (STMT_EXECUTING == self->status)
1653 self->cancel_info |= CancelRequestSet;
1654 } else
1656 /* try to acquire */
1657 if (TRY_ENTER_STMT_CS(self))
1658 enteredCS = TRUE;
1659 else
1660 self->cancel_info |= CancelRequestSet;
1662 LEAVE_COMMON_CS;
1663 return enteredCS;
1666 BOOL SC_AcceptedCancelRequest(const StatementClass * self)
1668 BOOL shouldCancel = FALSE;
1669 ENTER_COMMON_CS;
1670 if (0 !=
1671 (self->
1672 cancel_info & (CancelRequestSet | CancelRequestAccepted |
1673 CancelCompleted)))
1674 shouldCancel = TRUE;
1675 LEAVE_COMMON_CS;
1676 return shouldCancel;