diff options
Diffstat (limited to 'src/interfaces/odbc/execute.c')
-rw-r--r-- | src/interfaces/odbc/execute.c | 593 |
1 files changed, 318 insertions, 275 deletions
diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c index 6afbe308c94..960f16ca914 100644 --- a/src/interfaces/odbc/execute.c +++ b/src/interfaces/odbc/execute.c @@ -1,17 +1,17 @@ -
-/* Module: execute.c
- *
- * Description: This module contains routines related to
- * preparing and executing an SQL statement.
- *
- * Classes: n/a
- *
- * API functions: SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact,
- * SQLCancel, SQLNativeSql, SQLParamData, SQLPutData
- *
- * Comments: See "notice.txt" for copyright and license information.
- *
- */
+ +/* Module: execute.c + * + * Description: This module contains routines related to + * preparing and executing an SQL statement. + * + * Classes: n/a + * + * API functions: SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact, + * SQLCancel, SQLNativeSql, SQLParamData, SQLPutData + * + * Comments: See "notice.txt" for copyright and license information. + * + */ #include "psqlodbc.h" #include <stdio.h> @@ -24,6 +24,7 @@ #include "qresult.h" #include "convert.h" #include "bind.h" +#include "lobj.h" // Perform a Prepare on the SQL statement @@ -36,72 +37,29 @@ StatementClass *self = (StatementClass *) hstmt; if ( ! self) return SQL_INVALID_HANDLE; - /* CC: According to the ODBC specs it is valid to call SQLPrepare mulitple times. In that case, - the bound SQL statement is replaced by the new one */ + /* According to the ODBC specs it is valid to call SQLPrepare mulitple times. + In that case, the bound SQL statement is replaced by the new one + */ - switch (self->status) { + switch(self->status) { case STMT_PREMATURE: mylog("**** SQLPrepare: STMT_PREMATURE, recycle\n"); - SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */ + break; - /* NO Break! -- Contiue the same way as with a newly allocated statement ! */ + case STMT_FINISHED: + mylog("**** SQLPrepare: STMT_FINISHED, recycle\n"); + SC_recycle_statement(self); /* recycle the statement, but do not remove parameter bindings */ + break; case STMT_ALLOCATED: - // it is not really necessary to do any conversion of the statement - // here--just copy it, and deal with it when it's ready to be - // executed. mylog("**** SQLPrepare: STMT_ALLOCATED, copy\n"); - - self->statement = make_string(szSqlStr, cbSqlStr, NULL); - if ( ! self->statement) { - self->errornumber = STMT_NO_MEMORY_ERROR; - self->errormsg = "No memory available to store statement"; - return SQL_ERROR; - } - - self->statement_type = statement_type(self->statement); - - // Check if connection is readonly (only selects are allowed) - if ( CC_is_readonly(self->hdbc) && self->statement_type != STMT_TYPE_SELECT ) { - self->errornumber = STMT_EXEC_ERROR; - self->errormsg = "Connection is readonly, only select statements are allowed."; - return SQL_ERROR; - } - - self->prepare = TRUE; self->status = STMT_READY; + break; - return SQL_SUCCESS; - - case STMT_READY: /* SQLPrepare has already been called -- Just changed the SQL statement that is assigned to the handle */ + case STMT_READY: mylog("**** SQLPrepare: STMT_READY, change SQL\n"); - - if (self->statement) - free(self->statement); - - self->statement = make_string(szSqlStr, cbSqlStr, NULL); - if ( ! self->statement) { - self->errornumber = STMT_NO_MEMORY_ERROR; - self->errormsg = "No memory available to store statement"; - return SQL_ERROR; - } - - self->prepare = TRUE; - self->statement_type = statement_type(self->statement); - - // Check if connection is readonly (only selects are allowed) - if ( CC_is_readonly(self->hdbc) && self->statement_type != STMT_TYPE_SELECT ) { - self->errornumber = STMT_EXEC_ERROR; - self->errormsg = "Connection is readonly, only select statements are allowed."; - return SQL_ERROR; - } - - return SQL_SUCCESS; - - case STMT_FINISHED: - mylog("**** SQLPrepare: STMT_FINISHED\n"); - /* No BREAK: continue as with STMT_EXECUTING */ + break; case STMT_EXECUTING: mylog("**** SQLPrepare: STMT_EXECUTING, error!\n"); @@ -116,6 +74,30 @@ StatementClass *self = (StatementClass *) hstmt; self->errormsg = "An Internal Error has occured -- Unknown statement status."; return SQL_ERROR; } + + if (self->statement) + free(self->statement); + + self->statement = make_string(szSqlStr, cbSqlStr, NULL); + if ( ! self->statement) { + self->errornumber = STMT_NO_MEMORY_ERROR; + self->errormsg = "No memory available to store statement"; + return SQL_ERROR; + } + + self->prepare = TRUE; + self->statement_type = statement_type(self->statement); + + // Check if connection is readonly (only selects are allowed) + if ( CC_is_readonly(self->hdbc) && STMT_UPDATE(self)) { + self->errornumber = STMT_EXEC_ERROR; + self->errormsg = "Connection is readonly, only select statements are allowed."; + return SQL_ERROR; + } + + return SQL_SUCCESS; + + } // - - - - - - - - - @@ -150,7 +132,7 @@ StatementClass *stmt = (StatementClass *) hstmt; stmt->statement_type = statement_type(stmt->statement); // Check if connection is readonly (only selects are allowed) - if ( CC_is_readonly(stmt->hdbc) && stmt->statement_type != STMT_TYPE_SELECT ) { + if ( CC_is_readonly(stmt->hdbc) && STMT_UPDATE(stmt)) { stmt->errornumber = STMT_EXEC_ERROR; stmt->errormsg = "Connection is readonly, only select statements are allowed."; return SQL_ERROR; @@ -165,10 +147,10 @@ StatementClass *stmt = (StatementClass *) hstmt; RETCODE SQL_API SQLExecute( HSTMT hstmt) { -StatementClass *stmt = (StatementClass *) hstmt;
+StatementClass *stmt = (StatementClass *) hstmt; ConnectionClass *conn; -int i, retval;
-
+int i, retval; + if ( ! stmt) return SQL_INVALID_HANDLE; @@ -212,45 +194,45 @@ int i, retval; stmt->errornumber = STMT_STATUS_ERROR; stmt->errormsg = "The handle does not point to a statement that is ready to be executed"; return SQL_ERROR; - }
-
-
- /* The bound parameters could have possibly changed since the last execute
- of this statement? Therefore check for params and re-copy.
- */
- stmt->data_at_exec = -1;
- for (i = 0; i < stmt->parameters_allocated; i++) {
- /* Check for data at execution parameters */
- if ( stmt->parameters[i].data_at_exec == TRUE) {
- if (stmt->data_at_exec < 0)
- stmt->data_at_exec = 1;
- else
- stmt->data_at_exec++;
- }
- }
- // If there are some data at execution parameters, return need data
- // SQLParamData and SQLPutData will be used to send params and execute the statement.
- if (stmt->data_at_exec > 0)
- return SQL_NEED_DATA;
-
-
- mylog("SQLExecute: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", conn->transact_status, strlen(stmt->statement), stmt->statement);
-
- // Create the statement with parameters substituted.
- retval = copy_statement_with_parameters(stmt);
- if( retval != SQL_SUCCESS)
- /* error msg passed from above */
- return retval;
-
- mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params);
-
-
- return SC_execute(stmt);
+ } + + + /* The bound parameters could have possibly changed since the last execute + of this statement? Therefore check for params and re-copy. + */ + stmt->data_at_exec = -1; + for (i = 0; i < stmt->parameters_allocated; i++) { + /* Check for data at execution parameters */ + if ( stmt->parameters[i].data_at_exec == TRUE) { + if (stmt->data_at_exec < 0) + stmt->data_at_exec = 1; + else + stmt->data_at_exec++; + } + } + // If there are some data at execution parameters, return need data + // SQLParamData and SQLPutData will be used to send params and execute the statement. + if (stmt->data_at_exec > 0) + return SQL_NEED_DATA; + + + mylog("SQLExecute: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", conn->transact_status, strlen(stmt->statement), stmt->statement); + + // Create the statement with parameters substituted. + retval = copy_statement_with_parameters(stmt); + if( retval != SQL_SUCCESS) + /* error msg passed from above */ + return retval; + + mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params); + + + return SC_execute(stmt); } -
-
-
+ + + // - - - - - - - - - RETCODE SQL_API SQLTransact( @@ -325,24 +307,24 @@ mylog("**** SQLTransact: hdbc=%u, henv=%u\n", hdbc, henv); RETCODE SQL_API SQLCancel( HSTMT hstmt) // Statement to cancel. { -StatementClass *stmt = (StatementClass *) hstmt;
-
- // Check if this can handle canceling in the middle of a SQLPutData?
- if ( ! stmt)
- return SQL_INVALID_HANDLE;
-
- // Not in the middle of SQLParamData/SQLPutData so cancel like a close.
- if (stmt->data_at_exec < 0)
- return SQLFreeStmt(hstmt, SQL_CLOSE);
-
- // In the middle of SQLParamData/SQLPutData, so cancel that.
- // Note, any previous data-at-exec buffers will be freed in the recycle
- // if they call SQLExecDirect or SQLExecute again.
-
- stmt->data_at_exec = -1;
- stmt->current_exec_param = -1;
- stmt->put_data = FALSE;
-
+StatementClass *stmt = (StatementClass *) hstmt; + + // Check if this can handle canceling in the middle of a SQLPutData? + if ( ! stmt) + return SQL_INVALID_HANDLE; + + // Not in the middle of SQLParamData/SQLPutData so cancel like a close. + if (stmt->data_at_exec < 0) + return SQLFreeStmt(hstmt, SQL_CLOSE); + + // In the middle of SQLParamData/SQLPutData, so cancel that. + // Note, any previous data-at-exec buffers will be freed in the recycle + // if they call SQLExecDirect or SQLExecute again. + + stmt->data_at_exec = -1; + stmt->current_exec_param = -1; + stmt->put_data = FALSE; + } // - - - - - - - - - @@ -371,45 +353,63 @@ RETCODE SQL_API SQLNativeSql( RETCODE SQL_API SQLParamData( HSTMT hstmt, PTR FAR *prgbValue) -{
-StatementClass *stmt = (StatementClass *) hstmt;
-int i, retval;
-
- if ( ! stmt)
- return SQL_INVALID_HANDLE;
-
- if (stmt->data_at_exec < 0) {
- stmt->errornumber = STMT_SEQUENCE_ERROR;
- stmt->errormsg = "No execution-time parameters for this statement";
- return SQL_ERROR;
- }
-
- if (stmt->data_at_exec > stmt->parameters_allocated) {
- stmt->errornumber = STMT_SEQUENCE_ERROR;
- stmt->errormsg = "Too many execution-time parameters were present";
- return SQL_ERROR;
- }
-
- /* Done, now copy the params and then execute the statement */
- if (stmt->data_at_exec == 0) {
- retval = copy_statement_with_parameters(stmt);
- if (retval != SQL_SUCCESS)
- return retval;
-
- return SC_execute(stmt);
- }
-
- /* At least 1 data at execution parameter, so Fill in the token value */
- for (i = 0; i < stmt->parameters_allocated; i++) {
- if (stmt->parameters[i].data_at_exec == TRUE) {
- stmt->data_at_exec--;
- stmt->current_exec_param = i;
- stmt->put_data = FALSE;
- *prgbValue = stmt->parameters[i].buffer; /* token */
- }
- }
-
- return SQL_NEED_DATA;
+{ +StatementClass *stmt = (StatementClass *) hstmt; +int i, retval; + + if ( ! stmt) + return SQL_INVALID_HANDLE; + + mylog("SQLParamData, enter: data_at_exec=%d, params_alloc=%d\n", + stmt->data_at_exec, stmt->parameters_allocated); + + if (stmt->data_at_exec < 0) { + stmt->errornumber = STMT_SEQUENCE_ERROR; + stmt->errormsg = "No execution-time parameters for this statement"; + return SQL_ERROR; + } + + if (stmt->data_at_exec > stmt->parameters_allocated) { + stmt->errornumber = STMT_SEQUENCE_ERROR; + stmt->errormsg = "Too many execution-time parameters were present"; + return SQL_ERROR; + } + + /* close the large object */ + if ( stmt->lobj_fd >= 0) { + lo_close(stmt->hdbc, stmt->lobj_fd); + stmt->lobj_fd = -1; + } + + + /* Done, now copy the params and then execute the statement */ + if (stmt->data_at_exec == 0) { + retval = copy_statement_with_parameters(stmt); + if (retval != SQL_SUCCESS) + return retval; + + stmt->current_exec_param = -1; + + return SC_execute(stmt); + } + + /* Set beginning param; if first time SQLParamData is called , start at 0. + Otherwise, start at the last parameter + 1. + */ + i = stmt->current_exec_param >= 0 ? stmt->current_exec_param+1 : 0; + + /* At least 1 data at execution parameter, so Fill in the token value */ + for ( ; i < stmt->parameters_allocated; i++) { + if (stmt->parameters[i].data_at_exec == TRUE) { + stmt->data_at_exec--; + stmt->current_exec_param = i; + stmt->put_data = FALSE; + *prgbValue = stmt->parameters[i].buffer; /* token */ + break; + } + } + + return SQL_NEED_DATA; } // - - - - - - - - - @@ -422,114 +422,157 @@ RETCODE SQL_API SQLPutData( PTR rgbValue, SDWORD cbValue) { -StatementClass *stmt = (StatementClass *) hstmt;
-char *buffer;
-SDWORD *used;
-int old_pos;
-
-
- if ( ! stmt)
- return SQL_INVALID_HANDLE;
-
-
- if (stmt->current_exec_param < 0) {
- stmt->errornumber = STMT_SEQUENCE_ERROR;
- stmt->errormsg = "Previous call was not SQLPutData or SQLParamData";
- return SQL_ERROR;
- }
-
- if ( ! stmt->put_data) { /* first call */
-
- mylog("SQLPutData: (1) cbValue = %d\n", cbValue);
-
- stmt->put_data = TRUE;
-
- used = (SDWORD *) malloc(sizeof(SDWORD));
- if ( ! used) {
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->errormsg = "Out of memory in SQLPutData (1)";
- return SQL_ERROR;
- }
-
- *used = cbValue;
- stmt->parameters[stmt->current_exec_param].EXEC_used = used;
-
- if (cbValue == SQL_NULL_DATA)
- return SQL_SUCCESS;
-
- if (cbValue == SQL_NTS) {
- buffer = strdup(rgbValue);
- if ( ! buffer) {
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->errormsg = "Out of memory in SQLPutData (2)";
- return SQL_ERROR;
- }
- }
- else {
- buffer = malloc(cbValue + 1);
- if ( ! buffer) {
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->errormsg = "Out of memory in SQLPutData (2)";
- return SQL_ERROR;
- }
- memcpy(buffer, rgbValue, cbValue);
- buffer[cbValue] = '\0';
- }
-
- stmt->parameters[stmt->current_exec_param].EXEC_buffer = buffer;
- }
-
- else { /* calling SQLPutData more than once */
-
- mylog("SQLPutData: (>1) cbValue = %d\n", cbValue);
-
- used = stmt->parameters[stmt->current_exec_param].EXEC_used;
- buffer = stmt->parameters[stmt->current_exec_param].EXEC_buffer;
-
- if (cbValue == SQL_NTS) {
- buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1);
- if ( ! buffer) {
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->errormsg = "Out of memory in SQLPutData (3)";
- return SQL_ERROR;
- }
- strcat(buffer, rgbValue);
-
- mylog(" cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer));
-
- *used = cbValue;
-
- }
- else if (cbValue > 0) {
-
- old_pos = *used;
-
- *used += cbValue;
-
- mylog(" cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *used);
-
- buffer = realloc(buffer, *used + 1);
- if ( ! buffer) {
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->errormsg = "Out of memory in SQLPutData (3)";
- return SQL_ERROR;
- }
-
- memcpy(&buffer[old_pos], rgbValue, cbValue);
- buffer[*used] = '\0';
-
- }
- else
- return SQL_ERROR;
-
-
- /* reassign buffer incase realloc moved it */
- stmt->parameters[stmt->current_exec_param].EXEC_buffer = buffer;
-
- }
-
-
- return SQL_SUCCESS;
+StatementClass *stmt = (StatementClass *) hstmt; +int old_pos, retval; +ParameterInfoClass *current_param; +char *buffer; + + + if ( ! stmt) + return SQL_INVALID_HANDLE; + + + if (stmt->current_exec_param < 0) { + stmt->errornumber = STMT_SEQUENCE_ERROR; + stmt->errormsg = "Previous call was not SQLPutData or SQLParamData"; + return SQL_ERROR; + } + + current_param = &(stmt->parameters[stmt->current_exec_param]); + + if ( ! stmt->put_data) { /* first call */ + + mylog("SQLPutData: (1) cbValue = %d\n", cbValue); + + stmt->put_data = TRUE; + + current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD)); + if ( ! current_param->EXEC_used) { + stmt->errornumber = STMT_NO_MEMORY_ERROR; + stmt->errormsg = "Out of memory in SQLPutData (1)"; + return SQL_ERROR; + } + + *current_param->EXEC_used = cbValue; + + if (cbValue == SQL_NULL_DATA) + return SQL_SUCCESS; + + + /* Handle Long Var Binary with Large Objects */ + if ( current_param->SQLType == SQL_LONGVARBINARY) { + + /* store the oid */ + current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE); + if (current_param->lobj_oid == 0) { + stmt->errornumber = STMT_EXEC_ERROR; + stmt->errormsg = "Couldnt create large object."; + return SQL_ERROR; + } + + /* major hack -- to allow convert to see somethings there */ + /* have to modify convert to handle this better */ + current_param->EXEC_buffer = (char *) ¤t_param->lobj_oid; + + /* store the fd */ + stmt->lobj_fd = lo_open(stmt->hdbc, current_param->lobj_oid, INV_WRITE); + if ( stmt->lobj_fd < 0) { + stmt->errornumber = STMT_EXEC_ERROR; + stmt->errormsg = "Couldnt open large object for writing."; + return SQL_ERROR; + } + + retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); + mylog("lo_write: cbValue=%d, wrote %d bytes\n", cbValue, retval); + + } + else { /* for handling text fields and small binaries */ + + if (cbValue == SQL_NTS) { + current_param->EXEC_buffer = strdup(rgbValue); + if ( ! current_param->EXEC_buffer) { + stmt->errornumber = STMT_NO_MEMORY_ERROR; + stmt->errormsg = "Out of memory in SQLPutData (2)"; + return SQL_ERROR; + } + } + else { + current_param->EXEC_buffer = malloc(cbValue + 1); + if ( ! current_param->EXEC_buffer) { + stmt->errornumber = STMT_NO_MEMORY_ERROR; + stmt->errormsg = "Out of memory in SQLPutData (2)"; + return SQL_ERROR; + } + memcpy(current_param->EXEC_buffer, rgbValue, cbValue); + current_param->EXEC_buffer[cbValue] = '\0'; + } + } + } + + else { /* calling SQLPutData more than once */ + + mylog("SQLPutData: (>1) cbValue = %d\n", cbValue); + + if (current_param->SQLType == SQL_LONGVARBINARY) { + + /* the large object fd is in EXEC_buffer */ + retval = lo_write(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValue); + mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", cbValue, retval); + + *current_param->EXEC_used += cbValue; + + } else { + + buffer = current_param->EXEC_buffer; + + if (cbValue == SQL_NTS) { + buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1); + if ( ! buffer) { + stmt->errornumber = STMT_NO_MEMORY_ERROR; + stmt->errormsg = "Out of memory in SQLPutData (3)"; + return SQL_ERROR; + } + strcat(buffer, rgbValue); + + mylog(" cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer)); + + *current_param->EXEC_used = cbValue; + + /* reassign buffer incase realloc moved it */ + current_param->EXEC_buffer = buffer; + + } + else if (cbValue > 0) { + + old_pos = *current_param->EXEC_used; + + *current_param->EXEC_used += cbValue; + + mylog(" cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *current_param->EXEC_used); + + /* dont lose the old pointer in case out of memory */ + buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1); + if ( ! buffer) { + stmt->errornumber = STMT_NO_MEMORY_ERROR; + stmt->errormsg = "Out of memory in SQLPutData (3)"; + return SQL_ERROR; + } + + memcpy(&buffer[old_pos], rgbValue, cbValue); + buffer[*current_param->EXEC_used] = '\0'; + + /* reassign buffer incase realloc moved it */ + current_param->EXEC_buffer = buffer; + + } + else + return SQL_ERROR; + + } + } + + + return SQL_SUCCESS; } |