1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-11 05:41:32 +03:00
1998-06-03 20:33:45 +00:00

335 lines
8.7 KiB
C

/* Module: bind.c
*
* Description: This module contains routines related to binding
* columns and parameters.
*
* Classes: BindInfoClass, ParameterInfoClass
*
* API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams,
* SQLParamOptions(NI)
*
* Comments: See "notice.txt" for copyright and license information.
*
*/
#include "bind.h"
#include "environ.h"
#include "statement.h"
#include "qresult.h"
#include "pgtypes.h"
#include <stdlib.h>
#include <malloc.h>
#include <sql.h>
#include <sqlext.h>
// Bind parameters on a statement handle
RETCODE SQL_API SQLBindParameter(
HSTMT hstmt,
UWORD ipar,
SWORD fParamType,
SWORD fCType,
SWORD fSqlType,
UDWORD cbColDef,
SWORD ibScale,
PTR rgbValue,
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
if( ! stmt)
return SQL_INVALID_HANDLE;
if(stmt->parameters_allocated < ipar) {
ParameterInfoClass *old_parameters;
int i, old_parameters_allocated;
old_parameters = stmt->parameters;
old_parameters_allocated = stmt->parameters_allocated;
stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar));
if ( ! stmt->parameters) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
stmt->errormsg = "Could not allocate memory for statement parameters";
return SQL_ERROR;
}
stmt->parameters_allocated = ipar;
// copy the old parameters over
for(i = 0; i < old_parameters_allocated; i++) {
// a structure copy should work
stmt->parameters[i] = old_parameters[i];
}
// get rid of the old parameters, if there were any
if(old_parameters)
free(old_parameters);
// zero out the newly allocated parameters (in case they skipped some,
// so we don't accidentally try to use them later)
for(; i < stmt->parameters_allocated; i++) {
stmt->parameters[i].buflen = 0;
stmt->parameters[i].buffer = 0;
stmt->parameters[i].used = 0;
stmt->parameters[i].paramType = 0;
stmt->parameters[i].CType = 0;
stmt->parameters[i].SQLType = 0;
stmt->parameters[i].precision = 0;
stmt->parameters[i].scale = 0;
stmt->parameters[i].data_at_exec = FALSE;
stmt->parameters[i].lobj_oid = 0;
stmt->parameters[i].EXEC_used = NULL;
stmt->parameters[i].EXEC_buffer = NULL;
}
}
ipar--; /* use zero based column numbers for the below part */
// store the given info
stmt->parameters[ipar].buflen = cbValueMax;
stmt->parameters[ipar].buffer = rgbValue;
stmt->parameters[ipar].used = pcbValue;
stmt->parameters[ipar].paramType = fParamType;
stmt->parameters[ipar].CType = fCType;
stmt->parameters[ipar].SQLType = fSqlType;
stmt->parameters[ipar].precision = cbColDef;
stmt->parameters[ipar].scale = ibScale;
/* If rebinding a parameter that had data-at-exec stuff in it,
then free that stuff
*/
if (stmt->parameters[ipar].EXEC_used) {
free(stmt->parameters[ipar].EXEC_used);
stmt->parameters[ipar].EXEC_used = NULL;
}
if (stmt->parameters[ipar].EXEC_buffer) {
free(stmt->parameters[ipar].EXEC_buffer);
stmt->parameters[ipar].EXEC_buffer = NULL;
}
if (pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
stmt->parameters[ipar].data_at_exec = TRUE;
else
stmt->parameters[ipar].data_at_exec = FALSE;
mylog("SQLBindParamater: ipar = %d, *pcbValue = %d, data_at_exec = %d\n",
ipar, pcbValue ? *pcbValue: -777, stmt->parameters[ipar].data_at_exec);
return SQL_SUCCESS;
}
// - - - - - - - - -
// Associate a user-supplied buffer with a database column.
RETCODE SQL_API SQLBindCol(
HSTMT hstmt,
UWORD icol,
SWORD fCType,
PTR rgbValue,
SDWORD cbValueMax,
SDWORD FAR *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
Int2 numcols;
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
if ( ! stmt)
return SQL_INVALID_HANDLE;
if (icol < 1) {
/* currently we do not support bookmarks */
stmt->errormsg = "Bookmarks are not currently supported.";
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
return SQL_ERROR;
}
icol--; /* use zero based col numbers */
SC_clear_error(stmt);
if( ! stmt->result) {
stmt->errormsg = "Can't bind columns with a NULL query result structure.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
}
if( stmt->status == STMT_EXECUTING) {
stmt->errormsg = "Can't bind columns while statement is still executing.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
}
numcols = QR_NumResultCols(stmt->result);
mylog("SQLBindCol: numcols = %d\n", numcols);
if (icol >= numcols) {
stmt->errornumber = STMT_COLNUM_ERROR;
stmt->errormsg = "Column number too big";
return SQL_ERROR;
}
if ( ! stmt->bindings) {
stmt->errormsg = "Bindings were not allocated properly.";
stmt->errornumber = STMT_SEQUENCE_ERROR;
return SQL_ERROR;
}
if ((cbValueMax == 0) || (rgbValue == NULL)) {
/* we have to unbind the column */
stmt->bindings[icol].buflen = 0;
stmt->bindings[icol].buffer = NULL;
stmt->bindings[icol].used = NULL;
stmt->bindings[icol].returntype = SQL_C_CHAR;
} else {
/* ok, bind that column */
stmt->bindings[icol].buflen = cbValueMax;
stmt->bindings[icol].buffer = rgbValue;
stmt->bindings[icol].used = pcbValue;
stmt->bindings[icol].returntype = fCType;
mylog(" bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
}
return SQL_SUCCESS;
}
// - - - - - - - - -
// Returns the description of a parameter marker.
RETCODE SQL_API SQLDescribeParam(
HSTMT hstmt,
UWORD ipar,
SWORD FAR *pfSqlType,
UDWORD FAR *pcbColDef,
SWORD FAR *pibScale,
SWORD FAR *pfNullable)
{
StatementClass *stmt = (StatementClass *) hstmt;
if( ! stmt)
return SQL_INVALID_HANDLE;
if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
stmt->errormsg = "Invalid parameter number for SQLDescribeParam.";
stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR;
return SQL_ERROR;
}
ipar--;
if(pfSqlType)
*pfSqlType = stmt->parameters[ipar].SQLType;
if(pcbColDef)
*pcbColDef = stmt->parameters[ipar].precision;
if(pibScale)
*pibScale = stmt->parameters[ipar].scale;
if(pfNullable)
*pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);
return SQL_SUCCESS;
}
// - - - - - - - - -
// Sets multiple values (arrays) for the set of parameter markers.
RETCODE SQL_API SQLParamOptions(
HSTMT hstmt,
UDWORD crow,
UDWORD FAR *pirow)
{
return SQL_ERROR;
}
// - - - - - - - - -
// Returns the number of parameters in an SQL statement
RETCODE SQL_API SQLNumParams(
HSTMT hstmt,
SWORD FAR *pcpar)
{
StatementClass *stmt = (StatementClass *) hstmt;
if(!stmt)
return SQL_INVALID_HANDLE;
// If the statement does not have parameters, it should just return 0.
if (pcpar) {
*pcpar = stmt->parameters_allocated;
}
return SQL_SUCCESS;
}
/********************************************************************
* Bindings Implementation
*/
BindInfoClass *
create_empty_bindings(int num_columns)
{
BindInfoClass *new_bindings;
int i;
new_bindings = (BindInfoClass *)malloc(num_columns * sizeof(BindInfoClass));
if(!new_bindings) {
return 0;
}
for(i=0; i < num_columns; i++) {
new_bindings[i].buflen = 0;
new_bindings[i].buffer = NULL;
new_bindings[i].used = NULL;
}
return new_bindings;
}
void
extend_bindings(StatementClass *stmt, int num_columns)
{
BindInfoClass *new_bindings;
int i;
mylog("in extend_bindings: stmt=%u, bindings_allocated=%d, num_columns=%d\n", stmt, stmt->bindings_allocated, num_columns);
/* if we have too few, allocate room for more, and copy the old */
/* entries into the new structure */
if(stmt->bindings_allocated < num_columns) {
new_bindings = create_empty_bindings(num_columns);
if(stmt->bindings) {
for(i=0; i<stmt->bindings_allocated; i++)
new_bindings[i] = stmt->bindings[i];
free(stmt->bindings);
}
stmt->bindings = new_bindings; // null indicates error
stmt->bindings_allocated = num_columns;
} else {
/* if we have too many, make sure the extra ones are emptied out */
/* so we don't accidentally try to use them for anything */
for(i = num_columns; i < stmt->bindings_allocated; i++) {
stmt->bindings[i].buflen = 0;
stmt->bindings[i].buffer = NULL;
stmt->bindings[i].used = NULL;
}
}
mylog("exit extend_bindings\n");
}