diff options
author | Byron Nikolaidis <byronn@insightdist.com> | 1998-06-03 20:33:45 +0000 |
---|---|---|
committer | Byron Nikolaidis <byronn@insightdist.com> | 1998-06-03 20:33:45 +0000 |
commit | 99d21d5b62a54d64b95dc915a35fb35111bbc430 (patch) | |
tree | 06f02f33d40f78fd3b73ad6d775b18fd34ffd7e4 /src/interfaces/odbc/statement.c | |
parent | 85f91d0e8e2fa996a2c7ec629037387e1a9cfd88 (diff) |
Update odbc driver to current version V.0244
Diffstat (limited to 'src/interfaces/odbc/statement.c')
-rw-r--r-- | src/interfaces/odbc/statement.c | 453 |
1 files changed, 247 insertions, 206 deletions
diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c index bea5968dc25..7a5b0d886bd 100644 --- a/src/interfaces/odbc/statement.c +++ b/src/interfaces/odbc/statement.c @@ -1,16 +1,16 @@ -
-/* Module: statement.c
- *
- * Description: This module contains functions related to creating
- * and manipulating a statement.
- *
- * Classes: StatementClass (Functions prefix: "SC_")
- *
- * API functions: SQLAllocStmt, SQLFreeStmt
- *
- * Comments: See "notice.txt" for copyright and license information.
- *
- */
+ +/* Module: statement.c + * + * Description: This module contains functions related to creating + * and manipulating a statement. + * + * Classes: StatementClass (Functions prefix: "SC_") + * + * API functions: SQLAllocStmt, SQLFreeStmt + * + * Comments: See "notice.txt" for copyright and license information. + * + */ #include "statement.h" #include "bind.h" @@ -23,8 +23,25 @@ #include <windows.h> #include <sql.h> -extern GLOBAL_VALUES globals;
-
+extern GLOBAL_VALUES globals; + +/* Map sql commands to statement types */ +static struct { + int type; + char *s; +} Statement_Type[] = { + { STMT_TYPE_SELECT, "SELECT" }, + { STMT_TYPE_INSERT, "INSERT" }, + { STMT_TYPE_UPDATE, "UPDATE" }, + { STMT_TYPE_DELETE, "DELETE" }, + { STMT_TYPE_CREATE, "CREATE" }, + { STMT_TYPE_ALTER, "ALTER" }, + { STMT_TYPE_DROP, "DROP" }, + { STMT_TYPE_GRANT, "GRANT" }, + { STMT_TYPE_REVOKE, "REVOKE" }, + { 0, NULL } +}; + RETCODE SQL_API SQLAllocStmt(HDBC hdbc, HSTMT FAR *phstmt) @@ -103,7 +120,7 @@ StatementClass *stmt = (StatementClass *) hstmt; // errormsg passed in above return SQL_ERROR; - } else if(fOption == SQL_RESET_PARAMS) {
+ } else if(fOption == SQL_RESET_PARAMS) { SC_free_params(stmt, STMT_FREE_PARAMS_ALL); } else { @@ -133,21 +150,28 @@ StatementClass *rv; rv->prepare = FALSE; rv->status = STMT_ALLOCATED; rv->maxRows = 0; // driver returns all rows + rv->rowset_size = 1; + rv->scroll_concurrency = SQL_CONCUR_READ_ONLY; + rv->cursor_type = SQL_CURSOR_FORWARD_ONLY; rv->errormsg = NULL; rv->errornumber = 0; rv->errormsg_created = FALSE; - rv->statement = NULL;
- rv->stmt_with_params[0] = '\0';
+ rv->statement = NULL; + rv->stmt_with_params[0] = '\0'; rv->statement_type = STMT_TYPE_UNKNOWN; rv->bindings = NULL; rv->bindings_allocated = 0; rv->parameters_allocated = 0; rv->parameters = 0; rv->currTuple = -1; + rv->current_col = -1; rv->result = 0; - rv->data_at_exec = -1;
- rv->current_exec_param = -1;
- rv->put_data = FALSE;
+ rv->data_at_exec = -1; + rv->current_exec_param = -1; + rv->put_data = FALSE; + rv->lobj_fd = -1; + rv->internal = FALSE; + rv->cursor_name[0] = '\0'; } return rv; } @@ -172,9 +196,9 @@ SC_Destructor(StatementClass *self) if (self->statement) free(self->statement); -
- SC_free_params(self, STMT_FREE_PARAMS_ALL);
-
+ + SC_free_params(self, STMT_FREE_PARAMS_ALL); + /* the memory pointed to by the bindings is not deallocated by the driver */ /* by by the application that uses that driver, so we don't have to care */ /* about that here. */ @@ -183,62 +207,63 @@ SC_Destructor(StatementClass *self) free(self); + mylog("SC_Destructor: EXIT\n"); + return TRUE; } -
-/* Free parameters and free the memory from the
- data-at-execution parameters that was allocated in SQLPutData.
-*/
-void
-SC_free_params(StatementClass *self, char option)
-{
-int i;
-
- if( ! self->parameters)
- return;
-
- for (i = 0; i < self->parameters_allocated; i++) {
- if (self->parameters[i].data_at_exec == TRUE) {
-
- if (self->parameters[i].EXEC_used) {
- free(self->parameters[i].EXEC_used);
- self->parameters[i].EXEC_used = NULL;
- }
-
- if (self->parameters[i].EXEC_buffer) {
- free(self->parameters[i].EXEC_buffer);
- self->parameters[i].EXEC_buffer = NULL;
- }
- }
- }
- self->data_at_exec = -1;
- self->current_exec_param = -1;
- self->put_data = FALSE;
-
- if (option == STMT_FREE_PARAMS_ALL) {
- free(self->parameters);
- self->parameters = NULL;
- self->parameters_allocated = 0;
- }
-}
-int -statement_type(char *statement) +/* Free parameters and free the memory from the + data-at-execution parameters that was allocated in SQLPutData. +*/ +void +SC_free_params(StatementClass *self, char option) { - if(strnicmp(statement, "SELECT", 6) == 0) - return STMT_TYPE_SELECT; +int i; + + mylog("SC_free_params: ENTER, self=%d\n", self); + + if( ! self->parameters) + return; + + for (i = 0; i < self->parameters_allocated; i++) { + if (self->parameters[i].data_at_exec == TRUE) { + + if (self->parameters[i].EXEC_used) { + free(self->parameters[i].EXEC_used); + self->parameters[i].EXEC_used = NULL; + } + + if (self->parameters[i].EXEC_buffer) { + free(self->parameters[i].EXEC_buffer); + self->parameters[i].EXEC_buffer = NULL; + } + } + } + self->data_at_exec = -1; + self->current_exec_param = -1; + self->put_data = FALSE; + + if (option == STMT_FREE_PARAMS_ALL) { + free(self->parameters); + self->parameters = NULL; + self->parameters_allocated = 0; + } - else if(strnicmp(statement, "INSERT", 6) == 0) - return STMT_TYPE_INSERT; + mylog("SC_free_params: EXIT\n"); +} - else if(strnicmp(statement, "UPDATE", 6) == 0) - return STMT_TYPE_UPDATE; - else if(strnicmp(statement, "DELETE", 6) == 0) - return STMT_TYPE_DELETE; - else - return STMT_TYPE_OTHER; +int +statement_type(char *statement) +{ +int i; + + for (i = 0; Statement_Type[i].s; i++) + if ( ! strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s))) + return Statement_Type[i].type; + + return STMT_TYPE_OTHER; } /* Called from SQLPrepare if STMT_PREMATURE, or @@ -298,16 +323,21 @@ ConnectionClass *conn; } self->status = STMT_READY; + self->manual_result = FALSE; // very important + self->currTuple = -1; + self->current_col = -1; self->errormsg = NULL; self->errornumber = 0; self->errormsg_created = FALSE; -
- // Free any data at exec params before the statement is executed
- // again. If not, then there will be a memory leak when
- // the next SQLParamData/SQLPutData is called.
- SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
+ + self->lobj_fd = -1; + + // Free any data at exec params before the statement is executed + // again. If not, then there will be a memory leak when + // the next SQLParamData/SQLPutData is called. + SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY); return TRUE; } @@ -414,132 +444,143 @@ char rv; return rv; } -RETCODE SC_execute(StatementClass *self)
-{
-ConnectionClass *conn;
-QResultClass *res;
-char ok, was_ok, was_nonfatal;
-Int2 oldstatus, numcols;
-
-
- conn = SC_get_conn(self);
-
- /* Begin a transaction if one is not already in progress */
- /* The reason is because we can't use declare/fetch cursors without
- starting a transaction first.
- */
-
- if ( ! CC_is_in_trans(conn)) {
- mylog(" about to begin a transaction on statement = %u\n", self);
- res = CC_send_query(conn, "BEGIN", NULL, NULL);
- if ( ! res) {
- self->errormsg = "Could not begin a transaction";
- self->errornumber = STMT_EXEC_ERROR;
- return SQL_ERROR;
- }
-
- ok = QR_command_successful(res);
-
- mylog("SQLExecute: ok = %d, status = %d\n", ok, QR_get_status(res));
-
- QR_Destructor(res);
-
- if (!ok) {
- self->errormsg = "Could not begin a transaction";
- self->errornumber = STMT_EXEC_ERROR;
- return SQL_ERROR;
- }
- else
- CC_set_in_trans(conn);
- }
-
-
-
- oldstatus = conn->status;
- conn->status = CONN_EXECUTING;
- self->status = STMT_EXECUTING;
-
-
- // If its a SELECT statement, use a cursor.
- // Note that the declare cursor has already been prepended to the statement
- // in copy_statement...
- if (self->statement_type == STMT_TYPE_SELECT) {
-
- char cursor[32];
- char fetch[64];
-
- sprintf(cursor, "C%u", self);
-
- mylog(" Sending SELECT statement on stmt=%u\n", self);
-
- /* send the declare/select */
- self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
- if (self->result != NULL) {
- /* That worked, so now send the fetch to start getting data back */
- sprintf(fetch, "fetch %d in %s", globals.fetch_max, cursor);
-
- // Save the cursor in the result for later use
- self->result = CC_send_query( conn, fetch, NULL, cursor);
- }
-
- mylog(" done sending the query:\n");
-
- }
- else { // not a SELECT statement so don't use a cursor
- mylog(" its NOT a select statement: stmt=%u\n", self);
- self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
-
- // If we are in autocommit, we must send the commit.
- if (CC_is_in_autocommit(conn)) {
- CC_send_query(conn, "COMMIT", NULL, NULL);
- CC_set_no_trans(conn);
- }
-
- }
-
- conn->status = oldstatus;
- self->status = STMT_FINISHED;
-
- /* Check the status of the result */
- if (self->result) {
-
- was_ok = QR_command_successful(self->result);
- was_nonfatal = QR_command_nonfatal(self->result);
-
- if ( was_ok)
- self->errornumber = STMT_OK;
- else
- self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND;
-
- self->currTuple = -1; /* set cursor before the first tuple in the list */
-
- /* see if the query did return any result columns */
- numcols = QR_NumResultCols(self->result);
-
- /* now allocate the array to hold the binding info */
- if (numcols > 0) {
- extend_bindings(self, numcols);
- if (self->bindings == NULL) {
- self->errornumber = STMT_NO_MEMORY_ERROR;
- self->errormsg = "Could not get enough free memory to store the binding information";
- return SQL_ERROR;
- }
- }
-
- } else { /* Bad Error -- The error message will be in the Connection */
-
- self->errornumber = STMT_EXEC_ERROR;
- self->errormsg = "Error while executing the query";
-
- CC_abort(conn);
- }
-
- if (self->errornumber == STMT_OK)
- return SQL_SUCCESS;
-
- else if (self->errornumber == STMT_INFO_ONLY)
- return SQL_SUCCESS_WITH_INFO;
-
- else
- return SQL_ERROR;
-}
+RETCODE SC_execute(StatementClass *self) +{ +ConnectionClass *conn; +QResultClass *res; +char ok, was_ok, was_nonfatal; +Int2 oldstatus, numcols; + + + conn = SC_get_conn(self); + + /* Begin a transaction if one is not already in progress */ + /* The reason is because we can't use declare/fetch cursors without + starting a transaction first. + */ + if ( ! CC_is_in_trans(conn) && (globals.use_declarefetch || STMT_UPDATE(self))) { + + mylog(" about to begin a transaction on statement = %u\n", self); + res = CC_send_query(conn, "BEGIN", NULL, NULL); + if ( ! res) { + self->errormsg = "Could not begin a transaction"; + self->errornumber = STMT_EXEC_ERROR; + return SQL_ERROR; + } + + ok = QR_command_successful(res); + + mylog("SQLExecute: ok = %d, status = %d\n", ok, QR_get_status(res)); + + QR_Destructor(res); + + if (!ok) { + self->errormsg = "Could not begin a transaction"; + self->errornumber = STMT_EXEC_ERROR; + return SQL_ERROR; + } + else + CC_set_in_trans(conn); + } + + + + oldstatus = conn->status; + conn->status = CONN_EXECUTING; + self->status = STMT_EXECUTING; + + + // If its a SELECT statement, use a cursor. + // Note that the declare cursor has already been prepended to the statement + // in copy_statement... + if (self->statement_type == STMT_TYPE_SELECT) { + + char fetch[128]; + + mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name); + + /* send the declare/select */ + self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL); + + if (globals.use_declarefetch && self->result != NULL) { + /* That worked, so now send the fetch to start getting data back */ + sprintf(fetch, "fetch %d in %s", globals.fetch_max, self->cursor_name); + + // Save the cursor in the result for later use + self->result = CC_send_query( conn, fetch, NULL, self->cursor_name); + } + + mylog(" done sending the query:\n"); + + + + } + else { // not a SELECT statement so don't use a cursor + mylog(" its NOT a select statement: stmt=%u\n", self); + self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL); + + // If we are in autocommit, we must send the commit. + if (CC_is_in_autocommit(conn) && STMT_UPDATE(self)) { + CC_send_query(conn, "COMMIT", NULL, NULL); + CC_set_no_trans(conn); + } + + } + + conn->status = oldstatus; + self->status = STMT_FINISHED; + + /* Check the status of the result */ + if (self->result) { + + was_ok = QR_command_successful(self->result); + was_nonfatal = QR_command_nonfatal(self->result); + + if ( was_ok) + self->errornumber = STMT_OK; + else + self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND; + + self->currTuple = -1; /* set cursor before the first tuple in the list */ + self->current_col = -1; + + /* see if the query did return any result columns */ + numcols = QR_NumResultCols(self->result); + + /* now allocate the array to hold the binding info */ + if (numcols > 0) { + extend_bindings(self, numcols); + if (self->bindings == NULL) { + self->errornumber = STMT_NO_MEMORY_ERROR; + self->errormsg = "Could not get enough free memory to store the binding information"; + return SQL_ERROR; + } + } + + } else { /* Bad Error -- The error message will be in the Connection */ + + if (self->statement_type == STMT_TYPE_CREATE) { + self->errornumber = STMT_CREATE_TABLE_ERROR; + self->errormsg = "Error creating the table"; + /* This would allow the table to already exists, thus appending + rows to it. BUT, if the table didn't have the same attributes, + it would fail. + return SQL_SUCCESS_WITH_INFO; + */ + } + else { + self->errornumber = STMT_EXEC_ERROR; + self->errormsg = "Error while executing the query"; + } + CC_abort(conn); + } + + if (self->errornumber == STMT_OK) + return SQL_SUCCESS; + + else if (self->errornumber == STMT_INFO_ONLY) + return SQL_SUCCESS_WITH_INFO; + + else + return SQL_ERROR; +} |