summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/execute.c')
-rw-r--r--src/interfaces/odbc/execute.c593
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 *) &current_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;
}