diff options
Diffstat (limited to 'src/interfaces/odbc/bind.c')
-rw-r--r-- | src/interfaces/odbc/bind.c | 347 |
1 files changed, 234 insertions, 113 deletions
diff --git a/src/interfaces/odbc/bind.c b/src/interfaces/odbc/bind.c index 4635706a866..397d984ec6c 100644 --- a/src/interfaces/odbc/bind.c +++ b/src/interfaces/odbc/bind.c @@ -17,6 +17,7 @@ #include "environ.h" #include "statement.h" +#include "descriptor.h" #include "qresult.h" #include "pgtypes.h" #include <stdlib.h> @@ -41,6 +42,7 @@ PGAPI_BindParameter( { StatementClass *stmt = (StatementClass *) hstmt; static char *func = "PGAPI_BindParameter"; + APDFields *opts; mylog("%s: entering...\n", func); @@ -51,103 +53,54 @@ PGAPI_BindParameter( } SC_clear_error(stmt); - 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"; - SC_log_error(func, "", stmt); - 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; - } - } + opts = SC_get_APD(stmt); + if (opts->allocated < ipar) + extend_parameter_bindings(opts, ipar); /* use zero based column numbers for the below part */ ipar--; /* 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; + opts->parameters[ipar].buflen = cbValueMax; + opts->parameters[ipar].buffer = rgbValue; + opts->parameters[ipar].used = pcbValue; + opts->parameters[ipar].paramType = fParamType; + opts->parameters[ipar].CType = fCType; + opts->parameters[ipar].SQLType = fSqlType; + opts->parameters[ipar].precision = cbColDef; + opts->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) + if (opts->parameters[ipar].EXEC_used) { - free(stmt->parameters[ipar].EXEC_used); - stmt->parameters[ipar].EXEC_used = NULL; + free(opts->parameters[ipar].EXEC_used); + opts->parameters[ipar].EXEC_used = NULL; } - if (stmt->parameters[ipar].EXEC_buffer) + if (opts->parameters[ipar].EXEC_buffer) { - if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY) - free(stmt->parameters[ipar].EXEC_buffer); - stmt->parameters[ipar].EXEC_buffer = NULL; + if (opts->parameters[ipar].SQLType != SQL_LONGVARBINARY) + free(opts->parameters[ipar].EXEC_buffer); + opts->parameters[ipar].EXEC_buffer = NULL; } - if (pcbValue && stmt->options.param_offset_ptr) - pcbValue += (*stmt->options.param_offset_ptr >> 2); + if (pcbValue && opts->param_offset_ptr) + pcbValue += (*opts->param_offset_ptr >> 2); /* Data at exec macro only valid for C char/binary data */ if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC || *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)) - stmt->parameters[ipar].data_at_exec = TRUE; + opts->parameters[ipar].data_at_exec = TRUE; else - stmt->parameters[ipar].data_at_exec = FALSE; + opts->parameters[ipar].data_at_exec = FALSE; /* Clear premature result */ if (stmt->status == STMT_PREMATURE) SC_recycle_statement(stmt); - mylog("PGAPI_BindParamater: 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("PGAPI_BindParamater: 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, opts->parameters[ipar].data_at_exec); return SQL_SUCCESS; } @@ -165,6 +118,7 @@ PGAPI_BindCol( { StatementClass *stmt = (StatementClass *) hstmt; static char *func = "PGAPI_BindCol"; + ARDFields *opts; mylog("%s: entering...\n", func); @@ -178,8 +132,8 @@ PGAPI_BindCol( } - SC_clear_error(stmt); + opts = SC_get_ARD(stmt); if (stmt->status == STMT_EXECUTING) { stmt->errormsg = "Can't bind columns while statement is still executing."; @@ -188,13 +142,14 @@ PGAPI_BindCol( return SQL_ERROR; } + SC_clear_error(stmt); /* If the bookmark column is being bound, then just save it */ if (icol == 0) { if (rgbValue == NULL) { - stmt->bookmark.buffer = NULL; - stmt->bookmark.used = NULL; + opts->bookmark->buffer = NULL; + opts->bookmark->used = NULL; } else { @@ -215,8 +170,8 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); return SQL_ERROR; } - stmt->bookmark.buffer = rgbValue; - stmt->bookmark.used = pcbValue; + opts->bookmark->buffer = rgbValue; + opts->bookmark->used = pcbValue; } return SQL_SUCCESS; } @@ -226,11 +181,11 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); * execution of a statement would have setup the necessary bindings. * But some apps call BindCol before any statement is executed. */ - if (icol > stmt->bindings_allocated) - extend_bindings(stmt, icol); + if (icol > opts->allocated) + extend_column_bindings(opts, icol); /* check to see if the bindings were allocated */ - if (!stmt->bindings) + if (!opts->bindings) { stmt->errormsg = "Could not allocate memory for bindings."; stmt->errornumber = STMT_NO_MEMORY_ERROR; @@ -242,25 +197,29 @@ inolog("Column 0 is type %d not of type SQL_C_BOOKMARK", fCType); icol--; /* Reset for SQLGetData */ - stmt->bindings[icol].data_left = -1; + opts->bindings[icol].data_left = -1; if (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; + opts->bindings[icol].buflen = 0; + opts->bindings[icol].buffer = NULL; + opts->bindings[icol].used = NULL; + opts->bindings[icol].returntype = SQL_C_CHAR; + if (opts->bindings[icol].ttlbuf) + free(opts->bindings[icol].ttlbuf); + opts->bindings[icol].ttlbuf = NULL; + opts->bindings[icol].ttlbuflen = 0; } 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; + opts->bindings[icol].buflen = cbValueMax; + opts->bindings[icol].buffer = rgbValue; + opts->bindings[icol].used = pcbValue; + opts->bindings[icol].returntype = fCType; - mylog(" bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer); + mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer); } return SQL_SUCCESS; @@ -286,6 +245,7 @@ PGAPI_DescribeParam( { StatementClass *stmt = (StatementClass *) hstmt; static char *func = "PGAPI_DescribeParam"; + APDFields *opts; mylog("%s: entering...\n", func); @@ -296,7 +256,8 @@ PGAPI_DescribeParam( } SC_clear_error(stmt); - if ((ipar < 1) || (ipar > stmt->parameters_allocated)) + opts = SC_get_APD(stmt); + if ((ipar < 1) || (ipar > opts->allocated)) { stmt->errormsg = "Invalid parameter number for PGAPI_DescribeParam."; stmt->errornumber = STMT_BAD_PARAMETER_NUMBER_ERROR; @@ -312,16 +273,16 @@ PGAPI_DescribeParam( */ /* parameter markers, not bound parameters. */ if (pfSqlType) - *pfSqlType = stmt->parameters[ipar].SQLType; + *pfSqlType = opts->parameters[ipar].SQLType; if (pcbColDef) - *pcbColDef = stmt->parameters[ipar].precision; + *pcbColDef = opts->parameters[ipar].precision; if (pibScale) - *pibScale = stmt->parameters[ipar].scale; + *pibScale = opts->parameters[ipar].scale; if (pfNullable) - *pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType); + *pfNullable = pgtype_nullable(stmt, opts->parameters[ipar].paramType); return SQL_SUCCESS; } @@ -336,11 +297,13 @@ PGAPI_ParamOptions( { static char *func = "PGAPI_ParamOptions"; StatementClass *stmt = (StatementClass *) hstmt; + APDFields *opts; mylog("%s: entering... %d %x\n", func, crow, pirow); - stmt->options.paramset_size = crow; - stmt->options.param_processed_ptr = (SQLUINTEGER *)pirow; + opts = SC_get_APD(stmt); + opts->paramset_size = crow; + SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow; return SQL_SUCCESS; } @@ -433,46 +396,156 @@ create_empty_bindings(int num_columns) return new_bindings; } +void +extend_parameter_bindings(APDFields *self, int num_params) +{ + static char *func = "extend_parameter_bindings"; + ParameterInfoClass *new_bindings; + + mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params); + + /* + * if we have too few, allocate room for more, and copy the old + * entries into the new structure + */ + if (self->allocated < num_params) + { + new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params); + if (!new_bindings) + { + mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated); + + self->parameters = NULL; + self->allocated = 0; + return; + } + memset(&new_bindings[self->allocated], 0, + sizeof(ParameterInfoClass) * (num_params - self->allocated)); + + self->parameters = new_bindings; + self->allocated = num_params; + } + + mylog("exit extend_parameter_bindings\n"); +} + +void +reset_a_parameter_binding(APDFields *self, int ipar) +{ + static char *func = "reset_a_parameter_binding"; + + mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar); + + if (ipar < 1 || ipar > self->allocated) + return; + + ipar--; + self->parameters[ipar].buflen = 0; + self->parameters[ipar].buffer = 0; + self->parameters[ipar].used = 0; + self->parameters[ipar].paramType = 0; + self->parameters[ipar].CType = 0; + if (self->parameters[ipar].EXEC_used) + { + free(self->parameters[ipar].EXEC_used); + self->parameters[ipar].EXEC_used = NULL; + } + + if (self->parameters[ipar].EXEC_buffer) + { + if (self->parameters[ipar].SQLType != SQL_LONGVARBINARY) + free(self->parameters[ipar].EXEC_buffer); + self->parameters[ipar].EXEC_buffer = NULL; + } + self->parameters[ipar].SQLType = 0; + self->parameters[ipar].precision = 0; + self->parameters[ipar].scale = 0; + self->parameters[ipar].data_at_exec = FALSE; + self->parameters[ipar].lobj_oid = 0; +} + +/* + * Free parameters and free the memory. + */ +void +APD_free_params(APDFields *self, char option) +{ + int i; + + mylog("APD_free_params: ENTER, self=%d\n", self); + + if (!self->parameters) + return; + + for (i = 0; i < self->allocated; i++) + { + if (self->parameters[i].data_at_exec) + { + if (self->parameters[i].EXEC_used) + { + free(self->parameters[i].EXEC_used); + self->parameters[i].EXEC_used = NULL; + } + + if (self->parameters[i].EXEC_buffer) + { + if (self->parameters[i].SQLType != SQL_LONGVARBINARY) + free(self->parameters[i].EXEC_buffer); + self->parameters[i].EXEC_buffer = NULL; + } + } + } + + if (option == STMT_FREE_PARAMS_ALL) + { + if (self->parameters); + free(self->parameters); + self->parameters = NULL; + self->allocated = 0; + } + + mylog("APD_free_params: EXIT\n"); +} void -extend_bindings(StatementClass *stmt, int num_columns) +extend_column_bindings(ARDFields *self, int num_columns) { - static char *func = "extend_bindings"; + static char *func = "extend_column_bindings"; BindInfoClass *new_bindings; int i; - mylog("%s: entering ... stmt=%u, bindings_allocated=%d, num_columns=%d\n", func, stmt, stmt->bindings_allocated, num_columns); + mylog("%s: entering ... self=%u, bindings_allocated=%d, num_columns=%d\n", func, self, self->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) + if (self->allocated < num_columns) { new_bindings = create_empty_bindings(num_columns); if (!new_bindings) { - mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, stmt->bindings_allocated); + mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_columns, self->allocated); - if (stmt->bindings) + if (self->bindings) { - free(stmt->bindings); - stmt->bindings = NULL; + free(self->bindings); + self->bindings = NULL; } - stmt->bindings_allocated = 0; + self->allocated = 0; return; } - if (stmt->bindings) + if (self->bindings) { - for (i = 0; i < stmt->bindings_allocated; i++) - new_bindings[i] = stmt->bindings[i]; + for (i = 0; i < self->allocated; i++) + new_bindings[i] = self->bindings[i]; - free(stmt->bindings); + free(self->bindings); } - stmt->bindings = new_bindings; - stmt->bindings_allocated = num_columns; + self->bindings = new_bindings; + self->allocated = num_columns; } /* @@ -485,5 +558,53 @@ extend_bindings(StatementClass *stmt, int num_columns) /* SQLExecDirect(...) # returns 5 cols */ /* SQLExecDirect(...) # returns 10 cols (now OK) */ - mylog("exit extend_bindings\n"); + mylog("exit extend_column_bindings\n"); +} + +void +reset_a_column_binding(ARDFields *self, int icol) +{ + static char *func = "reset_a_column_binding"; + + mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol); + + if (icol > self->allocated) + return; + + /* use zero based col numbers from here out */ + if (0 == icol) + { + self->bookmark->buffer = NULL; + self->bookmark->used = NULL; + } + else + { + icol--; + + /* we have to unbind the column */ + self->bindings[icol].buflen = 0; + self->bindings[icol].buffer = NULL; + self->bindings[icol].used = NULL; + self->bindings[icol].data_left = -1; + self->bindings[icol].returntype = SQL_C_CHAR; + if (self->bindings[icol].ttlbuf) + free(self->bindings[icol].ttlbuf); + self->bindings[icol].ttlbuf = NULL; + self->bindings[icol].ttlbuflen = 0; + } } + +void ARD_unbind_cols(ARDFields *self, BOOL freeall) +{ + Int2 lf; + + for (lf = 1; lf <= self->allocated; lf++) + reset_a_column_binding(self, lf); + if (freeall) + { + if (self->bindings) + free(self->bindings); + self->bindings = NULL; + self->allocated = 0; + } +} |