diff options
author | Hiroshi Inoue <inoue@tpf.co.jp> | 2002-03-28 08:08:07 +0000 |
---|---|---|
committer | Hiroshi Inoue <inoue@tpf.co.jp> | 2002-03-28 08:08:07 +0000 |
commit | 6852741c1879fd2bd5ab5b367c7fc5a130dfd4da (patch) | |
tree | a0f27a6fb623307b0772f2964f31707fd302972e /src/interfaces/odbc/bind.c | |
parent | e6774dc3553d814e6aa500cabe5739b2e6f94df4 (diff) |
[2002-03-28]
1) Prepare to separate 4 kinds of Descriptor handles.
2) Detect the transaction status more naturally.
3) Improve Parse Statement functionality for the use
of updatable cursors.
4) Improve updatable cursors.
5) Implement SQLGetDescField() and improve SQLColAttribute().
6) etc.
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; + } +} |