2 * Description: This module contains functions related to creating
3 * and manipulating a statement.
7 #define _WIN32_WINNT 0x0400
8 #endif /* _WIN32_WINNT */
10 #include "statement.h"
13 #include "connection.h"
14 #include "multibyte.h"
23 #include "pgapifunc.h"
28 /* Map sql commands to statement types */
35 STMT_TYPE_SELECT
, "SELECT"}
38 STMT_TYPE_INSERT
, "INSERT"}
41 STMT_TYPE_UPDATE
, "UPDATE"}
44 STMT_TYPE_DELETE
, "DELETE"}
47 STMT_TYPE_PROCCALL
, "{"}
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"}
147 void SC_set_Result(StatementClass
*s
, QResultClass
*q
)
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
;
164 BindInfoClass
*bookmark
;
166 mylog("%s: entering...\n", func
);
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
);
180 CC_set_error(conn
, CONN_STMT_ALLOC_ERROR
,
181 "No more memory to allocate a further SQL-statement",
183 *phstmt
= SQL_NULL_HSTMT
;
187 if (!CC_add_statement(conn
, stmt
))
189 CC_set_error(conn
, CONN_STMT_ALLOC_ERROR
,
190 "Maximum number of statements exceeded.", func
);
192 *phstmt
= SQL_NULL_HSTMT
;
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
;
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
);
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 */
235 if (!CC_remove_statement(conn
, stmt
))
237 SC_set_error(stmt
, STMT_SEQUENCE_ERROR
,
238 "Statement is currently executing a transaction.",
240 return SQL_ERROR
; /* stmt may be executing a
244 /* Free any cursors and discard any result info */
245 res
= SC_get_Result(stmt
);
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. */
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
))
280 SC_set_error(stmt
, STMT_OPTION_OUT_OF_RANGE_ERROR
,
281 "Invalid option passed to PGAPI_FreeStmt.", func
);
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
);
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;
334 if (self
->catalog_result
)
336 if (self
->multi_statement
<= 0 && conn
->connInfo
.disallow_premature
)
337 SC_set_parse_tricky(self
);
340 StatementClass
*SC_Constructor(ConnectionClass
* conn
)
344 rv
= (StatementClass
*) malloc(sizeof(StatementClass
));
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;
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
;
373 SC_set_rowset_start(rv
, -1, FALSE
);
374 rv
->current_col
= -1;
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;
389 SC_init_parse_method(rv
);
391 INIT_NAME(rv
->cursor_name
);
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
);
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
;
416 rv
->updatable
= FALSE
;
417 rv
->diag_row_count
= 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
));
430 char SC_Destructor(StatementClass
* self
)
432 CSTR func
= "SC_Destrcutor";
433 QResultClass
*res
= SC_get_Result(self
);
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.",
451 res
->conn
= NULL
; /* prevent any dbase activity */
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
);
472 ER_Destructor(self
->pgerror
);
473 cancelNeedDataState(self
);
475 free(self
->callbacks
);
477 DELETE_STMT_CS(self
);
485 int statement_type(const char *statement
)
489 /* ignore leading whitespace in query string */
491 && (isspace((UCHAR
) * statement
) || *statement
== '('))
494 for (i
= 0; Statement_Type
[i
].s
; i
++)
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
)
506 free(stmt
->plan_name
);
507 if (plan_name
&& plan_name
[0])
508 stmt
->plan_name
= strdup(plan_name
);
510 stmt
->plan_name
= NULL
;
514 SC_set_rowset_start(StatementClass
* stmt
, SQLLEN start
,
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");
525 BOOL valid
= QR_has_valid_base(res
);
527 QR_has_valid_base(res
) ? "valid" : "unknown");
532 QR_inc_rowstart_in_cache(res
, incr
);
534 QR_set_no_valid_base(res
);
535 } else if (valid_base
)
537 QR_set_has_valid_base(res
);
539 QR_set_rowstart_in_cache(res
, -1);
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
)
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.
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)
594 self
->lock_CC_for_rb
--;
597 if (initializeOriginal
)
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 */
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
;
633 BOOL
SC_opencheck(StatementClass
* self
, const char *func
)
639 if (self
->status
== STMT_EXECUTING
)
641 SC_set_error(self
, STMT_SEQUENCE_ERROR
,
642 "Statement is currently executing a transaction.",
647 * We can dispose the result of PREMATURE execution any time.
649 if (self
->prepare
&& self
->status
== STMT_PREMATURE
)
652 ("SC_opencheck: self->prepare && self->status == STMT_PREMATURE\n");
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
);
668 RETCODE
SC_initialize_and_recycle(StatementClass
* self
)
670 SC_initialize_stmts(self
, TRUE
);
671 if (!SC_recycle_statement(self
))
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
;
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.",
700 conn
= SC_get_conn(self
);
701 switch (self
->status
)
704 /* this statement does not need to be recycled */
713 * Premature execution of the statement might have caused the
714 * start of a transaction. If so, we have to rollback that
717 // VX_CLEANUP: This was cleaned up.
724 SC_set_error(self
, STMT_INTERNAL_ERROR
,
725 "An internal error occured while recycling statements",
730 switch (self
->prepared
)
732 case NOT_YET_PREPARED
:
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
);
742 /* Free any cursors */
743 if (res
= SC_get_Result(self
), res
)
745 if (PREPARED_PERMANENTLY
== self
->prepared
)
746 QR_close_result(res
, FALSE
);
750 SC_init_Result(self
);
753 self
->inaccurate_result
= FALSE
;
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);
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
;
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;
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)
804 mylog("SC_pre_execute: Unknown result/number of columns\n");
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
;
828 void SC_clear_error(StatementClass
* self
)
832 self
->__error_number
= 0;
833 if (self
->__error_message
)
835 free(self
->__error_message
);
836 self
->__error_message
= NULL
;
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';
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 */
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
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
);
956 BOOL resmsg
= FALSE
, detailmsg
= FALSE
, msgend
= FALSE
;
957 char msg
[4096], *wmsg
;
958 char *ermsg
= NULL
, *sqlstate
= NULL
;
959 PG_ErrorInfo
*pgerror
;
962 return self
->pgerror
;
963 errornum
= self
->__error_number
;
970 if (res
->sqlstate
[0])
971 sqlstate
= res
->sqlstate
;
974 strncpy(msg
, res
->message
, sizeof(msg
));
975 detailmsg
= resmsg
= TRUE
;
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
);
995 if (!msgend
&& (wmsg
= SC_get_errormsg(self
)) && wmsg
[0])
1004 strncpy(msg
+ pos
, wmsg
, sizeof(msg
) - pos
);
1008 if (!self
->ref_CC_error
)
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
))
1019 snprintf(&msg
[pos
], sizeof(msg
) - pos
, ";\n%s",
1020 CC_get_errormsg(conn
));
1025 pgerror
= ER_Constructor(self
->__error_number
, ermsg
);
1027 strcpy(pgerror
->sqlstate
, sqlstate
);
1030 if (!msgend
&& conn
->sqlstate
[0])
1031 strcpy(pgerror
->sqlstate
, conn
->sqlstate
);
1034 EnvironmentClass
*env
= (EnvironmentClass
*) conn
->henv
;
1036 errornum
-= LOWEST_STMT_ERROR
;
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
);
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
);
1065 void SC_reset_delegate(RETCODE retcode
, StatementClass
* stmt
)
1067 StatementClass
*delegate
= stmt
->execute_delegate
;
1071 PGAPI_FreeStmt(delegate
, SQL_DROP
);
1075 SC_set_error(StatementClass
* self
, int number
, const char *message
,
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
;
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
;
1103 inolog("SC_set_error_from_res %p->%p check=%i\n", from_res
, self
,
1109 if (0 > number
&& /* SQL_SUCCESS_WITH_INFO */
1110 0 < self
->__error_number
)
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
;
1122 ER_Destructor(self
->pgerror
);
1123 self
->pgerror
= NULL
;
1125 self_res
= SC_get_Curres(self
);
1128 if (self_res
== from_res
)
1130 QR_add_message(self_res
, QR_get_message(from_res
));
1131 QR_add_notice(self_res
, QR_get_notice(from_res
));
1135 else if (from_res
->sqlstate
[0])
1137 if (!self_res
->sqlstate
[0]
1138 || strncmp(self_res
->sqlstate
, "00", 2) == 0)
1140 else if (strncmp(from_res
->sqlstate
, "01", 2) >= 0)
1144 strcpy(self_res
->sqlstate
, from_res
->sqlstate
);
1148 SC_error_copy(StatementClass
* self
, const StatementClass
* from
,
1151 QResultClass
*self_res
, *from_res
;
1154 inolog("SC_error_copy %p->%p check=%i\n", from
, self
, check
);
1159 if (0 == from
->__error_number
) /* SQL_SUCCESS */
1161 if (0 > from
->__error_number
&& /* SQL_SUCCESS_WITH_INFO */
1162 0 < self
->__error_number
)
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
;
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
)
1183 QR_add_message(self_res
, QR_get_message(from_res
));
1184 QR_add_notice(self_res
, QR_get_notice(from_res
));
1188 else if (from_res
->sqlstate
[0])
1190 if (!self_res
->sqlstate
[0]
1191 || strncmp(self_res
->sqlstate
, "00", 2) == 0)
1193 else if (strncmp(from_res
->sqlstate
, "01", 2) >= 0)
1197 strcpy(self_res
->sqlstate
, from_res
->sqlstate
);
1202 SC_full_error_copy(StatementClass
* self
, const StatementClass
* from
,
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
;
1219 ER_Destructor(self
->pgerror
);
1220 self
->pgerror
= ER_Dup(from
->pgerror
);
1224 pgerror
= SC_create_errorinfo(from
);
1225 if (!pgerror
->__error_message
[0])
1227 ER_Destructor(pgerror
);
1231 ER_Destructor(self
->pgerror
);
1232 self
->pgerror
= pgerror
;
1235 /* Returns the next SQL error information. */
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
,
1254 time_t SC_get_time(StatementClass
* stmt
)
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
);
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
))
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
);
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
))
1333 SC_pos_reload(self
, self
->currTuple
, &qcount
, 0);
1334 if (SQL_ERROR
== 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
)
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
,
1365 bookmark
->buffer
+ offset
, 0,
1366 LENADDR_SHIFT(bookmark
->used
,
1368 LENADDR_SHIFT(bookmark
->used
,
1372 if (self
->options
.retrieve_data
== SQL_RD_OFF
) /* data isn't required */
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
++)
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
)
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
);
1408 copy_and_convert_field_bindinfo(self
, type
, value
, lf
);
1410 mylog("copy_and_convert: retval = %d\n", retval
);
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.",
1424 case COPY_UNSUPPORTED_CONVERSION
:
1425 SC_set_error(self
, STMT_RESTRICTED_DATA_TYPE_ERROR
,
1426 "Couldn't handle the necessary data type conversion.",
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
;
1440 /* error msg already filled in */
1441 case COPY_GENERAL_ERROR
:
1445 /* This would not be meaningful in SQLFetch. */
1446 case COPY_NO_DATA_FOUND
:
1450 SC_set_error(self
, STMT_INTERNAL_ERROR
,
1451 "Unrecognized return value from copy_and_convert_field.",
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
,
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
)
1491 NeedDataCallfunc func
;
1495 mylog("dequeueNeedDataCallback ret=%d count=%d\n", retcode
,
1496 stmt
->num_callbacks
);
1497 if (SQL_NEED_DATA
== retcode
)
1499 if (stmt
->num_callbacks
<= 0)
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
);
1508 if (SQL_NEED_DATA
!= ret
&& cnt
> 0)
1509 ret
= dequeueNeedDataCallback(ret
, stmt
);
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
);
1527 SC_log_error(const char *func
, const char *desc
,
1528 const StatementClass
* self
)
1531 #ifdef PRN_NULLCHECK
1532 #define nullcheck(a) (a ? a : "(NULL)")
1536 QResultClass
*res
= SC_get_Result(self
);
1537 const ARDFields
*opts
= SC_get_ARDF(self
);
1538 const APDFields
*apdopts
= SC_get_APDF(self
);
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";
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");
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
);
1592 qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n",
1594 mylog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n",
1597 #undef PRN_NULLCHECK
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
)
1617 ENTER_COMMON_CS
; /* short time blocking */
1618 ret
= (STMT_EXECUTING
== self
->status
);
1623 BOOL
SC_SetExecuting(StatementClass
* self
, BOOL on
)
1625 BOOL exeSet
= FALSE
;
1626 ENTER_COMMON_CS
; /* short time blocking */
1629 if (0 == (self
->cancel_info
& CancelRequestSet
))
1631 self
->status
= STMT_EXECUTING
;
1636 self
->cancel_info
= 0;
1637 self
->status
= STMT_FINISHED
;
1644 BOOL
SC_SetCancelRequest(StatementClass
* self
)
1646 BOOL enteredCS
= FALSE
;
1649 if (0 != (self
->cancel_info
& CancelCompleted
))
1651 else if (STMT_EXECUTING
== self
->status
)
1653 self
->cancel_info
|= CancelRequestSet
;
1656 /* try to acquire */
1657 if (TRY_ENTER_STMT_CS(self
))
1660 self
->cancel_info
|= CancelRequestSet
;
1666 BOOL
SC_AcceptedCancelRequest(const StatementClass
* self
)
1668 BOOL shouldCancel
= FALSE
;
1672 cancel_info
& (CancelRequestSet
| CancelRequestAccepted
|
1674 shouldCancel
= TRUE
;
1676 return shouldCancel
;