summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/statement.c
diff options
context:
space:
mode:
authorByron Nikolaidis <byronn@insightdist.com>1998-06-03 20:33:45 +0000
committerByron Nikolaidis <byronn@insightdist.com>1998-06-03 20:33:45 +0000
commit99d21d5b62a54d64b95dc915a35fb35111bbc430 (patch)
tree06f02f33d40f78fd3b73ad6d775b18fd34ffd7e4 /src/interfaces/odbc/statement.c
parent85f91d0e8e2fa996a2c7ec629037387e1a9cfd88 (diff)
Update odbc driver to current version V.0244
Diffstat (limited to 'src/interfaces/odbc/statement.c')
-rw-r--r--src/interfaces/odbc/statement.c453
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;
+}