mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Update odbc driver to current version V.0244
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user