mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
A patch to fix the following bugs.
1) [ODBC] Psqlodbc and Centura: here it is a patch posted by Matteo Cavalleli 2) [ODBC] pgsqODBC binding parameters II posted by Ludek Finstrle 3) Invalid Page Fault in PSQLODBC.DLL personal mail from Johann Zuschlag Hiroki Kataoka kataoka@interwiz.koganei.tokyo.jp
This commit is contained in:
@ -143,11 +143,16 @@ SQLBindParameter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Data at exec macro only valid for C char/binary data */
|
/* Data at exec macro only valid for C char/binary data */
|
||||||
if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
|
if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
|
||||||
|
*pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
|
||||||
stmt->parameters[ipar].data_at_exec = TRUE;
|
stmt->parameters[ipar].data_at_exec = TRUE;
|
||||||
else
|
else
|
||||||
stmt->parameters[ipar].data_at_exec = FALSE;
|
stmt->parameters[ipar].data_at_exec = FALSE;
|
||||||
|
|
||||||
|
/* Clear premature result */
|
||||||
|
if (stmt->status == STMT_PREMATURE)
|
||||||
|
SC_recycle_statement(stmt);
|
||||||
|
|
||||||
mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec);
|
mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec);
|
||||||
|
|
||||||
return SQL_SUCCESS;
|
return SQL_SUCCESS;
|
||||||
|
@ -838,7 +838,20 @@ copy_statement_with_parameters(StatementClass *stmt)
|
|||||||
param_number++;
|
param_number++;
|
||||||
|
|
||||||
if (param_number >= stmt->parameters_allocated)
|
if (param_number >= stmt->parameters_allocated)
|
||||||
break;
|
{
|
||||||
|
if (stmt->pre_executing)
|
||||||
|
{
|
||||||
|
strcpy(&new_statement[npos], "NULL");
|
||||||
|
npos += 4;
|
||||||
|
stmt->inaccurate_result = TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_statement[npos++] = '?';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Assign correct buffers based on data at exec param or not */
|
/* Assign correct buffers based on data at exec param or not */
|
||||||
if (stmt->parameters[param_number].data_at_exec)
|
if (stmt->parameters[param_number].data_at_exec)
|
||||||
@ -866,8 +879,18 @@ copy_statement_with_parameters(StatementClass *stmt)
|
|||||||
*/
|
*/
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
{
|
{
|
||||||
new_statement[npos++] = '?';
|
if (stmt->pre_executing)
|
||||||
continue;
|
{
|
||||||
|
strcpy(&new_statement[npos], "NULL");
|
||||||
|
npos += 4;
|
||||||
|
stmt->inaccurate_result = TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_statement[npos++] = '?';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
param_ctype = stmt->parameters[param_number].CType;
|
param_ctype = stmt->parameters[param_number].CType;
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "qresult.h"
|
#include "qresult.h"
|
||||||
#include "convert.h"
|
#include "convert.h"
|
||||||
#include "bind.h"
|
#include "bind.h"
|
||||||
|
#include "pgtypes.h"
|
||||||
#include "lobj.h"
|
#include "lobj.h"
|
||||||
|
|
||||||
extern GLOBAL_VALUES globals;
|
extern GLOBAL_VALUES globals;
|
||||||
@ -222,17 +223,22 @@ SQLExecute(
|
|||||||
*/
|
*/
|
||||||
if (stmt->prepare && stmt->status == STMT_PREMATURE)
|
if (stmt->prepare && stmt->status == STMT_PREMATURE)
|
||||||
{
|
{
|
||||||
stmt->status = STMT_FINISHED;
|
if (stmt->inaccurate_result)
|
||||||
if (stmt->errormsg == NULL)
|
SC_recycle_statement(stmt);
|
||||||
{
|
|
||||||
mylog("%s: premature statement but return SQL_SUCCESS\n", func);
|
|
||||||
return SQL_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SC_log_error(func, "", stmt);
|
stmt->status = STMT_FINISHED;
|
||||||
mylog("%s: premature statement so return SQL_ERROR\n", func);
|
if (stmt->errormsg == NULL)
|
||||||
return SQL_ERROR;
|
{
|
||||||
|
mylog("%s: premature statement but return SQL_SUCCESS\n", func);
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SC_log_error(func, "", stmt);
|
||||||
|
mylog("%s: premature statement so return SQL_ERROR\n", func);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,30 +289,36 @@ SQLExecute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* Check if statement has any data-at-execute parameters when it is not in SC_pre_execute. */
|
||||||
* The bound parameters could have possibly changed since the last
|
if (!stmt->pre_executing)
|
||||||
* 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 bound parameters could have possibly changed since the last
|
||||||
* the statement.
|
* execute of this statement? Therefore check for params and re-copy.
|
||||||
*/
|
*/
|
||||||
if (stmt->data_at_exec > 0)
|
stmt->data_at_exec = -1;
|
||||||
return SQL_NEED_DATA;
|
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("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement);
|
mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement);
|
||||||
@ -777,8 +789,7 @@ SQLPutData(
|
|||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* for handling text fields and small
|
{ /* for handling fields */
|
||||||
* binaries */
|
|
||||||
|
|
||||||
if (cbValue == SQL_NTS)
|
if (cbValue == SQL_NTS)
|
||||||
{
|
{
|
||||||
@ -793,16 +804,35 @@ SQLPutData(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
current_param->EXEC_buffer = malloc(cbValue + 1);
|
Int2 ctype = current_param->CType;
|
||||||
if (!current_param->EXEC_buffer)
|
if (ctype == SQL_C_DEFAULT)
|
||||||
|
ctype = sqltype_to_default_ctype(current_param->SQLType);
|
||||||
|
if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
|
||||||
{
|
{
|
||||||
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
current_param->EXEC_buffer = malloc(cbValue + 1);
|
||||||
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
if (!current_param->EXEC_buffer)
|
||||||
SC_log_error(func, "", stmt);
|
{
|
||||||
return SQL_ERROR;
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
|
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
||||||
|
SC_log_error(func, "", stmt);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
|
||||||
|
current_param->EXEC_buffer[cbValue] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Int4 used = ctype_length(ctype);
|
||||||
|
current_param->EXEC_buffer = malloc(used);
|
||||||
|
if (!current_param->EXEC_buffer)
|
||||||
|
{
|
||||||
|
stmt->errornumber = STMT_NO_MEMORY_ERROR;
|
||||||
|
stmt->errormsg = "Out of memory in SQLPutData (2)";
|
||||||
|
SC_log_error(func, "", stmt);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
memcpy(current_param->EXEC_buffer, rgbValue, used);
|
||||||
}
|
}
|
||||||
memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
|
|
||||||
current_param->EXEC_buffer[cbValue] = '\0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -955,3 +955,56 @@ sqltype_to_default_ctype(Int2 sqltype)
|
|||||||
return SQL_C_CHAR;
|
return SQL_C_CHAR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Int4
|
||||||
|
ctype_length(Int2 ctype)
|
||||||
|
{
|
||||||
|
switch (ctype)
|
||||||
|
{
|
||||||
|
case SQL_C_SSHORT:
|
||||||
|
case SQL_C_SHORT:
|
||||||
|
return sizeof(SWORD);
|
||||||
|
|
||||||
|
case SQL_C_USHORT:
|
||||||
|
return sizeof(UWORD);
|
||||||
|
|
||||||
|
case SQL_C_SLONG:
|
||||||
|
case SQL_C_LONG:
|
||||||
|
return sizeof(SDWORD);
|
||||||
|
|
||||||
|
case SQL_C_ULONG:
|
||||||
|
return sizeof(UDWORD);
|
||||||
|
|
||||||
|
case SQL_C_FLOAT:
|
||||||
|
return sizeof(SFLOAT);
|
||||||
|
|
||||||
|
case SQL_C_DOUBLE:
|
||||||
|
return sizeof(SDOUBLE);
|
||||||
|
|
||||||
|
case SQL_C_BIT:
|
||||||
|
return sizeof(UCHAR);
|
||||||
|
|
||||||
|
case SQL_C_STINYINT:
|
||||||
|
case SQL_C_TINYINT:
|
||||||
|
return sizeof(SCHAR);
|
||||||
|
|
||||||
|
case SQL_C_UTINYINT:
|
||||||
|
return sizeof(UCHAR);
|
||||||
|
|
||||||
|
case SQL_C_DATE:
|
||||||
|
return sizeof(DATE_STRUCT);
|
||||||
|
|
||||||
|
case SQL_C_TIME:
|
||||||
|
return sizeof(TIME_STRUCT);
|
||||||
|
|
||||||
|
case SQL_C_TIMESTAMP:
|
||||||
|
return sizeof(TIMESTAMP_STRUCT);
|
||||||
|
|
||||||
|
case SQL_C_BINARY:
|
||||||
|
case SQL_C_CHAR:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default: /* should never happen */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -92,5 +92,6 @@ char *pgtype_literal_suffix(StatementClass *stmt, Int4 type);
|
|||||||
char *pgtype_create_params(StatementClass *stmt, Int4 type);
|
char *pgtype_create_params(StatementClass *stmt, Int4 type);
|
||||||
|
|
||||||
Int2 sqltype_to_default_ctype(Int2 sqltype);
|
Int2 sqltype_to_default_ctype(Int2 sqltype);
|
||||||
|
Int4 ctype_length(Int2 ctype);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -291,6 +291,9 @@ SC_Constructor(void)
|
|||||||
|
|
||||||
/* Clear Statement Options -- defaults will be set in AllocStmt */
|
/* Clear Statement Options -- defaults will be set in AllocStmt */
|
||||||
memset(&rv->options, 0, sizeof(StatementOptions));
|
memset(&rv->options, 0, sizeof(StatementOptions));
|
||||||
|
|
||||||
|
rv->pre_executing = FALSE;
|
||||||
|
rv->inaccurate_result = FALSE;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -518,6 +521,7 @@ SC_recycle_statement(StatementClass *self)
|
|||||||
QR_Destructor(self->result);
|
QR_Destructor(self->result);
|
||||||
self->result = NULL;
|
self->result = NULL;
|
||||||
}
|
}
|
||||||
|
self->inaccurate_result = FALSE;
|
||||||
|
|
||||||
/****************************************************************/
|
/****************************************************************/
|
||||||
/* Reset only parameters that have anything to do with results */
|
/* Reset only parameters that have anything to do with results */
|
||||||
@ -550,18 +554,33 @@ SC_recycle_statement(StatementClass *self)
|
|||||||
void
|
void
|
||||||
SC_pre_execute(StatementClass *self)
|
SC_pre_execute(StatementClass *self)
|
||||||
{
|
{
|
||||||
|
|
||||||
mylog("SC_pre_execute: status = %d\n", self->status);
|
mylog("SC_pre_execute: status = %d\n", self->status);
|
||||||
|
|
||||||
if (self->status == STMT_READY)
|
if (self->status == STMT_READY)
|
||||||
{
|
{
|
||||||
mylog(" preprocess: status = READY\n");
|
mylog(" preprocess: status = READY\n");
|
||||||
|
|
||||||
SQLExecute(self);
|
if (self->statement_type == STMT_TYPE_SELECT)
|
||||||
|
|
||||||
if (self->status == STMT_FINISHED)
|
|
||||||
{
|
{
|
||||||
mylog(" preprocess: after status = FINISHED, so set PREMATURE\n");
|
char old_pre_executing = self->pre_executing;
|
||||||
|
self->pre_executing = TRUE;
|
||||||
|
self->inaccurate_result = FALSE;
|
||||||
|
|
||||||
|
SQLExecute(self);
|
||||||
|
|
||||||
|
self->pre_executing = old_pre_executing;
|
||||||
|
|
||||||
|
if (self->status == STMT_FINISHED)
|
||||||
|
{
|
||||||
|
mylog(" preprocess: after status = FINISHED, so set PREMATURE\n");
|
||||||
|
self->status = STMT_PREMATURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->result = QR_Constructor();
|
||||||
|
QR_set_status(self->result, PGRES_TUPLES_OK);
|
||||||
|
self->inaccurate_result = TRUE;
|
||||||
self->status = STMT_PREMATURE;
|
self->status = STMT_PREMATURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,9 @@ struct StatementClass_
|
|||||||
* parameter
|
* parameter
|
||||||
* substitution */
|
* substitution */
|
||||||
|
|
||||||
|
char pre_executing; /* This statement is prematurely executing */
|
||||||
|
char inaccurate_result; /* Current status is PREMATURE
|
||||||
|
* but result is inaccurate */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SC_get_conn(a) (a->hdbc)
|
#define SC_get_conn(a) (a->hdbc)
|
||||||
|
Reference in New Issue
Block a user