From 1016a91388873e2d0ba100f05ebf01eb4b5379f3 Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Sat, 25 Oct 2003 04:19:23 +0000 Subject: [PATCH] [7.03.0201] 1) Revise the handling of descriptors and implement SQLCopyDesc. 2) Handle data_at_execution columns for SQLSetPos or SQLBulkOperations. --- bind.c | 339 ++++++++++++++++++++++------- bind.h | 79 ++++--- connection.c | 48 ++++- connection.h | 15 +- convert.c | 205 ++++++++++-------- descriptor.c | 572 +++++++++++++++++++++++++++++++++++++++++++++++++ descriptor.h | 131 ++++++++++-- environ.c | 127 +++++++++++ execute.c | 152 +++++++------ info.c | 68 +++--- misc.c | 2 +- multibyte.c | 2 +- odbcapi.c | 10 +- odbcapi30.c | 61 ++---- odbcapi30w.c | 2 +- odbcapiw.c | 2 +- options.c | 10 +- parse.c | 2 +- pgapi30.c | 442 +++++++++++++++++++++----------------- pgapifunc.h | 15 +- psqlodbc.h | 31 ++- results.c | 579 +++++++++++++++++++++++++++++++++----------------- statement.c | 294 ++++++++++++++----------- statement.h | 54 ++++- version.h | 6 +- win32.mak | 9 + win32_25.mak | 9 + win32_30w.mak | 7 + 28 files changed, 2361 insertions(+), 912 deletions(-) create mode 100644 descriptor.c diff --git a/bind.c b/bind.c index 84f8f6d..550a124 100644 --- a/bind.c +++ b/bind.c @@ -44,6 +44,7 @@ PGAPI_BindParameter( CSTR func = "PGAPI_BindParameter"; APDFields *apdopts; IPDFields *ipdopts; + PutDataInfo *pdata_info; mylog("%s: entering...\n", func); @@ -54,12 +55,15 @@ PGAPI_BindParameter( } SC_clear_error(stmt); - apdopts = SC_get_APD(stmt); + apdopts = SC_get_APDF(stmt); if (apdopts->allocated < ipar) extend_parameter_bindings(apdopts, ipar); - ipdopts = SC_get_IPD(stmt); + ipdopts = SC_get_IPDF(stmt); if (ipdopts->allocated < ipar) extend_iparameter_bindings(ipdopts, ipar); + pdata_info = SC_get_PDTI(stmt); + if (pdata_info->allocated < ipar) + extend_putdata_info(pdata_info, ipar, FALSE); /* use zero based column numbers for the below part */ ipar--; @@ -68,7 +72,6 @@ PGAPI_BindParameter( apdopts->parameters[ipar].buflen = cbValueMax; apdopts->parameters[ipar].buffer = rgbValue; apdopts->parameters[ipar].used = pcbValue; - apdopts->parameters[ipar].paramType = fParamType; apdopts->parameters[ipar].CType = fCType; ipdopts->parameters[ipar].SQLType = fSqlType; ipdopts->parameters[ipar].paramType = fParamType; @@ -99,16 +102,16 @@ PGAPI_BindParameter( * If rebinding a parameter that had data-at-exec stuff in it, then * free that stuff */ - if (apdopts->parameters[ipar].EXEC_used) + if (pdata_info->pdata[ipar].EXEC_used) { - free(apdopts->parameters[ipar].EXEC_used); - apdopts->parameters[ipar].EXEC_used = NULL; + free(pdata_info->pdata[ipar].EXEC_used); + pdata_info->pdata[ipar].EXEC_used = NULL; } - if (apdopts->parameters[ipar].EXEC_buffer) + if (pdata_info->pdata[ipar].EXEC_buffer) { - free(apdopts->parameters[ipar].EXEC_buffer); - apdopts->parameters[ipar].EXEC_buffer = NULL; + free(pdata_info->pdata[ipar].EXEC_buffer); + pdata_info->pdata[ipar].EXEC_buffer = NULL; } if (pcbValue && apdopts->param_offset_ptr) @@ -143,6 +146,8 @@ PGAPI_BindCol( StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_BindCol"; ARDFields *opts; + GetDataInfo *gdata_info; + BindInfoClass *bookmark; mylog("%s: entering...\n", func); @@ -155,9 +160,7 @@ PGAPI_BindCol( return SQL_INVALID_HANDLE; } - - - opts = SC_get_ARD(stmt); + opts = SC_get_ARDF(stmt); if (stmt->status == STMT_EXECUTING) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing."); @@ -169,10 +172,14 @@ PGAPI_BindCol( /* If the bookmark column is being bound, then just save it */ if (icol == 0) { + bookmark = opts->bookmark; if (rgbValue == NULL) { - opts->bookmark->buffer = NULL; - opts->bookmark->used = NULL; + if (bookmark) + { + bookmark->buffer = NULL; + bookmark->used = NULL; + } } else { @@ -191,10 +198,11 @@ inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType); return SQL_ERROR; } - opts->bookmark->buffer = rgbValue; - opts->bookmark->used = pcbValue; - opts->bookmark->buflen = cbValueMax; - opts->bookmark->returntype = fCType; + bookmark = ARD_AllocBookmark(opts); + bookmark->buffer = rgbValue; + bookmark->used = pcbValue; + bookmark->buflen = cbValueMax; + bookmark->returntype = fCType; } return SQL_SUCCESS; } @@ -206,6 +214,9 @@ inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType); */ if (icol > opts->allocated) extend_column_bindings(opts, icol); + gdata_info = SC_get_GDTI(stmt); + if (icol > gdata_info->allocated) + extend_getdata_info(gdata_info, icol, FALSE); /* check to see if the bindings were allocated */ if (!opts->bindings) @@ -219,7 +230,7 @@ inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType); icol--; /* Reset for SQLGetData */ - opts->bindings[icol].data_left = -1; + gdata_info->gdata[icol].data_left = -1; if (rgbValue == NULL) { @@ -228,13 +239,13 @@ inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType); 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; - opts->bindings[icol].ttlbufused = 0; opts->bindings[icol].precision = 0; opts->bindings[icol].scale = 0; + if (gdata_info->gdata[icol].ttlbuf) + free(gdata_info->gdata[icol].ttlbuf); + gdata_info->gdata[icol].ttlbuf = NULL; + gdata_info->gdata[icol].ttlbuflen = 0; + gdata_info->gdata[icol].ttlbufused = 0; } else { @@ -289,14 +300,14 @@ PGAPI_DescribeParam( } SC_clear_error(stmt); - apdopts = SC_get_APD(stmt); + apdopts = SC_get_APDF(stmt); if ((ipar < 1) || (ipar > apdopts->allocated)) { SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam."); SC_log_error(func, "", stmt); return SQL_ERROR; } - ipdopts = SC_get_IPD(stmt); + ipdopts = SC_get_IPDF(stmt); ipar--; @@ -315,7 +326,7 @@ PGAPI_DescribeParam( *pibScale = ipdopts->parameters[ipar].decimal_digits; if (pfNullable) - *pfNullable = pgtype_nullable(stmt, apdopts->parameters[ipar].paramType); + *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType); return SQL_SUCCESS; } @@ -334,9 +345,9 @@ PGAPI_ParamOptions( mylog("%s: entering... %d %x\n", func, crow, pirow); - apdopts = SC_get_APD(stmt); + apdopts = SC_get_APDF(stmt); apdopts->paramset_size = crow; - SC_get_IPD(stmt)->param_processed_ptr = (UInt4 *) pirow; + SC_get_IPDF(stmt)->param_processed_ptr = (UInt4 *) pirow; return SQL_SUCCESS; } @@ -404,7 +415,7 @@ PGAPI_NumParams( /* * Bindings Implementation */ -BindInfoClass * +static BindInfoClass * create_empty_bindings(int num_columns) { BindInfoClass *new_bindings; @@ -419,10 +430,6 @@ create_empty_bindings(int num_columns) new_bindings[i].buflen = 0; new_bindings[i].buffer = NULL; new_bindings[i].used = NULL; - new_bindings[i].data_left = -1; - new_bindings[i].ttlbuf = NULL; - new_bindings[i].ttlbuflen = 0; - new_bindings[i].ttlbufused = 0; } return new_bindings; @@ -508,21 +515,8 @@ reset_a_parameter_binding(APDFields *self, int 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; self->parameters[ipar].data_at_exec = FALSE; - if (self->parameters[ipar].EXEC_used) - { - free(self->parameters[ipar].EXEC_used); - self->parameters[ipar].EXEC_used = NULL; - } - - if (self->parameters[ipar].EXEC_buffer) - { - free(self->parameters[ipar].EXEC_buffer); - self->parameters[ipar].EXEC_buffer = NULL; - } - self->parameters[ipar].lobj_oid = 0; self->parameters[ipar].precision = 0; self->parameters[ipar].scale = 0; } @@ -552,30 +546,11 @@ reset_a_iparameter_binding(IPDFields *self, int ipar) void APD_free_params(APDFields *apdopts, char option) { - int i; - mylog("APD_free_params: ENTER, self=%d\n", apdopts); if (!apdopts->parameters) return; - for (i = 0; i < apdopts->allocated; i++) - { - if (apdopts->parameters[i].data_at_exec) - { - if (apdopts->parameters[i].EXEC_used) - { - free(apdopts->parameters[i].EXEC_used); - apdopts->parameters[i].EXEC_used = NULL; - } - if (apdopts->parameters[i].EXEC_buffer) - { - free(apdopts->parameters[i].EXEC_buffer); - apdopts->parameters[i].EXEC_buffer = NULL; - } - } - } - if (option == STMT_FREE_PARAMS_ALL) { if (apdopts->parameters) @@ -587,6 +562,41 @@ APD_free_params(APDFields *apdopts, char option) mylog("APD_free_params: EXIT\n"); } +void +PDATA_free_params(PutDataInfo *pdata, char option) +{ + int i; + + mylog("PDATA_free_params: ENTER, self=%d\n", pdata); + + if (!pdata->pdata) + return; + + for (i = 0; i < pdata->allocated; i++) + { + if (pdata->pdata[i].EXEC_used) + { + free(pdata->pdata[i].EXEC_used); + pdata->pdata[i].EXEC_used = NULL; + } + if (pdata->pdata[i].EXEC_buffer) + { + free(pdata->pdata[i].EXEC_buffer); + pdata->pdata[i].EXEC_buffer = NULL; + } + } + + if (option == STMT_FREE_PARAMS_ALL) + { + if (pdata->pdata) + free(pdata->pdata); + pdata->pdata = NULL; + pdata->allocated = 0; + } + + mylog("PDATA_free_params: EXIT\n"); +} + /* * Free parameters and free the memory. */ @@ -665,6 +675,7 @@ void reset_a_column_binding(ARDFields *self, int icol) { CSTR func = "reset_a_column_binding"; + BindInfoClass *bookmark; mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol); @@ -674,8 +685,11 @@ reset_a_column_binding(ARDFields *self, int icol) /* use zero based col numbers from here out */ if (0 == icol) { - self->bookmark->buffer = NULL; - self->bookmark->used = NULL; + if (bookmark = self->bookmark, bookmark != NULL) + { + bookmark->buffer = NULL; + bookmark->used = NULL; + } } else { @@ -685,13 +699,7 @@ reset_a_column_binding(ARDFields *self, int icol) 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; - self->bindings[icol].ttlbufused = 0; } } @@ -699,6 +707,7 @@ void ARD_unbind_cols(ARDFields *self, BOOL freeall) { Int2 lf; +inolog("ARD_unbind_cols freeall=%d allocated=%d bindings=%x", freeall, self->allocated, self->bindings); for (lf = 1; lf <= self->allocated; lf++) reset_a_column_binding(self, lf); if (freeall) @@ -708,4 +717,184 @@ void ARD_unbind_cols(ARDFields *self, BOOL freeall) self->bindings = NULL; self->allocated = 0; } -} +} +void GDATA_unbind_cols(GetDataInfo *self, BOOL freeall) +{ + Int2 lf; + +inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x", freeall, self->allocated, self->gdata); + for (lf = 1; lf <= self->allocated; lf++) + reset_a_getdata_info(self, lf); + if (freeall) + { + if (self->gdata) + free(self->gdata); + self->gdata = NULL; + self->allocated = 0; + } +} + +void GetDataInfoInitialize(GetDataInfo *gdata_info) +{ + gdata_info->allocated = 0; + gdata_info->gdata = NULL; +} +static GetDataClass * +create_empty_gdata(int num_columns) +{ + GetDataClass *new_gdata; + int i; + + new_gdata = (GetDataClass *) malloc(num_columns * sizeof(GetDataClass)); + if (!new_gdata) + return NULL; + + for (i = 0; i < num_columns; i++) + { + new_gdata[i].data_left = -1; + new_gdata[i].ttlbuf = NULL; + new_gdata[i].ttlbuflen = 0; + new_gdata[i].ttlbufused = 0; + } + + return new_gdata; +} +void +extend_getdata_info(GetDataInfo *self, int num_columns, BOOL shrink) +{ + CSTR func = "extend_getdata_info"; + GetDataClass *new_gdata; + int i; + + mylog("%s: entering ... self=%u, gdata_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 (self->allocated < num_columns) + { + new_gdata = create_empty_gdata(num_columns); + if (!new_gdata) + { + mylog("%s: unable to create %d new gdata from %d old gdata\n", func, num_columns, self->allocated); + + if (self->gdata) + { + free(self->gdata); + self->gdata = NULL; + } + self->allocated = 0; + return; + } + if (self->gdata) + { + for (i = 0; i < self->allocated; i++) + new_gdata[i] = self->gdata[i]; + free(self->gdata); + } + self->gdata = new_gdata; + self->allocated = num_columns; + } + else if (shrink && self->allocated > num_columns) + { + for (i = self->allocated; i > num_columns; i--) + reset_a_getdata_info(self, i); + self->allocated = num_columns; + if (0 == num_columns) + { + free(self->gdata); + self->gdata = NULL; + } + } + + /* + * There is no reason to zero out extra gdata if there are more + * than needed. If an app has allocated extra gdata, let it worry + * about it by unbinding those columns. + */ + + mylog("exit extend_gdata_info\n"); +} +void reset_a_getdata_info(GetDataInfo *gdata_info, int icol) +{ + if (icol < 1 || icol > gdata_info->allocated) + return; + icol--; + if (gdata_info->gdata[icol].ttlbuf) + { + free(gdata_info->gdata[icol].ttlbuf); + gdata_info->gdata[icol].ttlbuf = NULL; + } + gdata_info->gdata[icol].ttlbuflen = + gdata_info->gdata[icol].ttlbufused = 0; + gdata_info->gdata[icol].data_left = -1; +} + +void PutDataInfoInitialize(PutDataInfo *pdata_info) +{ + pdata_info->allocated = 0; + pdata_info->pdata = NULL; +} +void +extend_putdata_info(PutDataInfo *self, int num_params, BOOL shrink) +{ + CSTR func = "extend_putdata_info"; + PutDataClass *new_pdata; + + 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_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params); + if (!new_pdata) + { + mylog("%s: unable to create %d new pdata from %d old pdata\n", func, num_params, self->allocated); + + self->pdata = NULL; + self->allocated = 0; + return; + } + memset(&new_pdata[self->allocated], 0, + sizeof(PutDataClass) * (num_params - self->allocated)); + + self->pdata = new_pdata; + self->allocated = num_params; + } + else if (shrink && self->allocated > num_params) + { + int i; + + for (i = self->allocated; i > num_params; i--) + reset_a_putdata_info(self, i); + self->allocated = num_params; + if (0 == num_params) + { + free(self->pdata); + self->pdata = NULL; + } + } + + mylog("exit extend_putdata_info\n"); +} +void reset_a_putdata_info(PutDataInfo *pdata_info, int ipar) +{ + if (ipar < 1 || ipar > pdata_info->allocated) + return; + ipar--; + if (pdata_info->pdata[ipar].EXEC_used) + { + free(pdata_info->pdata[ipar].EXEC_used); + pdata_info->pdata[ipar].EXEC_used = NULL; + } + if (pdata_info->pdata[ipar].EXEC_buffer) + { + free(pdata_info->pdata[ipar].EXEC_buffer); + pdata_info->pdata[ipar].EXEC_buffer = NULL; + } + pdata_info->pdata[ipar].lobj_oid = 0; +} diff --git a/bind.h b/bind.h index 02c9b11..9fba18b 100644 --- a/bind.h +++ b/bind.h @@ -16,40 +16,49 @@ */ struct BindInfoClass_ { - Int4 buflen; /* size of buffer */ - Int4 data_left; /* amount of data left to read - * (SQLGetData) */ - char *buffer; /* pointer to the buffer */ - Int4 *used; /* used space in the buffer (for strings - * not counting the '\0') */ - char *ttlbuf; /* to save the large result */ - Int4 ttlbuflen; /* the buffer length */ - Int4 ttlbufused; /* used length of the buffer */ - Int2 returntype; /* kind of conversion to be applied when - * returning (SQL_C_DEFAULT, - * SQL_C_CHAR...) */ + Int4 buflen; /* size of buffer */ + char *buffer; /* pointer to the buffer */ + Int4 *used; /* used space in the buffer (for strings + * not counting the '\0') */ + Int2 returntype; /* kind of conversion to be applied when + * returning (SQL_C_DEFAULT, + * SQL_C_CHAR... etc) */ Int2 precision; /* the precision for numeric or timestamp type */ Int2 scale; /* the scale for numeric type */ + /* area for work variables */ + char dummy_data; /* currently not used */ }; +typedef struct +{ + char *ttlbuf; /* to save the large result */ + Int4 ttlbuflen; /* the buffer length */ + Int4 ttlbufused; /* used length of the buffer */ + Int4 data_left; /* amount of data left to read + * (SQLGetData) */ +} GetDataClass; /* * ParameterInfoClass -- stores information about a bound parameter */ struct ParameterInfoClass_ { - Int4 buflen; - char *buffer; - Int4 *used; - Int2 paramType; - Int2 CType; - Oid lobj_oid; - Int4 *EXEC_used; /* amount of data */ - char *EXEC_buffer; /* the data */ - Int2 precision; /* the precision for numeric or timestamp type */ - Int2 scale; /* the scale for numeric type */ - char data_at_exec; + Int4 buflen; + char *buffer; + Int4 *used; + Int2 CType; + Int2 precision; /* the precision for numeric or timestamp type */ + Int2 scale; /* the scale for numeric type */ + /* area for work variables */ + char data_at_exec; }; +typedef struct +{ + Int4 *EXEC_used; /* amount of data */ + char *EXEC_buffer; /* the data */ + Oid lobj_oid; +} PutDataClass; + /* * ParameterImplClass -- stores implemntation information about a parameter */ @@ -64,12 +73,30 @@ struct ParameterImplClass_ Int2 scale; /* the scale for numeric type */ }; -BindInfoClass *create_empty_bindings(int num_columns); +typedef struct +{ + Int4 allocated; + GetDataClass *gdata; +} GetDataInfo; +typedef struct +{ + Int4 allocated; + PutDataClass *pdata; +} PutDataInfo; + void extend_column_bindings(ARDFields *opts, int num_columns); void reset_a_column_binding(ARDFields *opts, int icol); -void extend_parameter_bindings(APDFields *opts, int num_columns); -void extend_iparameter_bindings(IPDFields *opts, int num_columns); +void extend_parameter_bindings(APDFields *opts, int num_params); +void extend_iparameter_bindings(IPDFields *opts, int num_params); void reset_a_parameter_binding(APDFields *opts, int ipar); void reset_a_iparameter_binding(IPDFields *opts, int ipar); +void GetDataInfoInitialize(GetDataInfo *gdata); +void extend_getdata_info(GetDataInfo *gdata, int num_columns, BOOL shrink); +void reset_a_getdata_info(GetDataInfo *gdata, int icol); +void GDATA_unbind_cols(GetDataInfo *gdata, BOOL freeall); +void PutDataInfoInitialize(PutDataInfo *pdata); +void extend_putdata_info(PutDataInfo *pdata, int num_params, BOOL shrink); +void reset_a_putdata_info(PutDataInfo *pdata, int ipar); +void PDATA_free_params(PutDataInfo *pdata, char option); #endif diff --git a/connection.c b/connection.c index e2c9f55..cfd4555 100644 --- a/connection.c +++ b/connection.c @@ -277,6 +277,14 @@ CC_Constructor() memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT); rv->num_stmts = STMT_INCREMENT; +#if (ODBCVER >= 0x0300) + rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT); + if (!rv->descs) + return NULL; + memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT); + + rv->num_descs = STMT_INCREMENT; +#endif /* ODBCVER */ rv->lobj_type = PG_TYPE_LO_UNDEFINED; @@ -332,6 +340,13 @@ CC_Destructor(ConnectionClass *self) free(self->stmts); self->stmts = NULL; } +#if (ODBCVER >= 0x0300) + if (self->descs) + { + free(self->descs); + self->descs = NULL; + } +#endif /* ODBCVER */ mylog("after free statement holders\n"); if (self->__error_message) @@ -454,6 +469,7 @@ CC_cleanup(ConnectionClass *self) { int i; StatementClass *stmt; + DescriptorClass *desc; if (self->status == CONN_EXECUTING) return FALSE; @@ -489,6 +505,20 @@ CC_cleanup(ConnectionClass *self) self->stmts[i] = NULL; } } +#if (ODBCVER >= 0x0300) + /* Free all the descs on this connection */ + for (i = 0; i < self->num_descs; i++) + { + desc = self->descs[i]; + if (desc) + { + DC_get_conn(desc) = NULL; /* prevent any more dbase interactions */ + DC_Destructor(desc); + free(desc); + self->descs[i] = NULL; + } + } +#endif /* ODBCVER */ /* Check for translation dll */ #ifdef WIN32 @@ -1196,8 +1226,6 @@ void CC_on_abort(ConnectionClass *conn, UDWORD opt) * (i.e., C3326857) for SQL select statements. This cursor is then used in future * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements. */ - - QResultClass * CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) { @@ -1810,7 +1838,7 @@ CC_send_settings(ConnectionClass *self) stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */ /* Set the Datestyle to the format the driver expects it to be in */ - result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) status = FALSE; @@ -1819,7 +1847,7 @@ CC_send_settings(ConnectionClass *self) /* Disable genetic optimizer based on global flag */ if (ci->drivers.disable_optimizer) { - result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) status = FALSE; @@ -1830,7 +1858,7 @@ CC_send_settings(ConnectionClass *self) /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */ if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1)) { - result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) status = FALSE; @@ -1841,7 +1869,7 @@ CC_send_settings(ConnectionClass *self) /* extra_float_digits (applicable since 7.4) */ if (PG_VERSION_GT(self, 7.3)) { - result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) status = FALSE; @@ -1860,7 +1888,7 @@ CC_send_settings(ConnectionClass *self) #endif /* HAVE_STRTOK_R */ while (ptr) { - result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS); + result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) status = FALSE; @@ -1887,7 +1915,7 @@ CC_send_settings(ConnectionClass *self) #endif /* HAVE_STRTOK_R */ while (ptr) { - result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS); + result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) status = FALSE; @@ -1934,7 +1962,7 @@ CC_lookup_lo(ConnectionClass *self) return; stmt = (StatementClass *) hstmt; - result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { PGAPI_FreeStmt(hstmt, SQL_DROP); @@ -2020,7 +2048,7 @@ CC_lookup_pg_version(ConnectionClass *self) stmt = (StatementClass *) hstmt; /* get the server's version if possible */ - result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { PGAPI_FreeStmt(hstmt, SQL_DROP); diff --git a/connection.h b/connection.h index 406dc3e..7ad2818 100644 --- a/connection.h +++ b/connection.h @@ -334,6 +334,10 @@ struct ConnectionClass_ int be_key; /* auth code needed to send cancel */ UInt4 isolation; char *current_schema; +#if (ODBCVER >= 0x0300) + int num_descs; + DescriptorClass **descs; +#endif /* ODBCVER */ #if defined(WIN_MULTITHREAD_SUPPORT) CRITICAL_SECTION cs; #elif defined(POSIX_MULTITHREAD_SUPPORT) @@ -349,7 +353,7 @@ struct ConnectionClass_ #define CC_get_DSN(x) (x->connInfo.dsn) #define CC_get_username(x) (x->connInfo.username) #define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1') - + /* for CC_DSN_info */ #define CONN_DONT_OVERWRITE 0 #define CONN_OVERWRITE 1 @@ -367,7 +371,12 @@ char CC_abort(ConnectionClass *self); int CC_set_translation(ConnectionClass *self); char CC_connect(ConnectionClass *self, char password_req, char *salt); char CC_add_statement(ConnectionClass *self, StatementClass *stmt); -char CC_remove_statement(ConnectionClass *self, StatementClass *stmt); +char CC_remove_statement(ConnectionClass *self, StatementClass *stmt) +; +#if (ODBCVER >= 0x0300) +char CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc); +char CC_remove_descriptor(ConnectionClass *self, DescriptorClass *desc); +#endif /* ODBCVER */ void CC_set_error(ConnectionClass *self, int number, const char *message); void CC_set_errormsg(ConnectionClass *self, const char *message); char CC_get_error(ConnectionClass *self, int *number, char **message); @@ -380,7 +389,7 @@ void CC_lookup_lo(ConnectionClass *conn); void CC_lookup_pg_version(ConnectionClass *conn); void CC_initialize_pg_version(ConnectionClass *conn); void CC_log_error(const char *func, const char *desc, const ConnectionClass *self); -int CC_get_max_query_len(const ConnectionClass *self); +int CC_get_max_query_len(const ConnectionClass *self); int CC_send_cancel_request(const ConnectionClass *conn); void CC_on_commit(ConnectionClass *conn); void CC_on_abort(ConnectionClass *conn, UDWORD opt); diff --git a/convert.c b/convert.c index 92d178c..a173835 100644 --- a/convert.c +++ b/convert.c @@ -351,7 +351,7 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col) { - ARDFields *opts = SC_get_ARD(stmt); + ARDFields *opts = SC_get_ARDF(stmt); BindInfoClass *bic = &(opts->bindings[col]); UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; @@ -366,7 +366,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue) { CSTR func = "copy_and_convert_field"; - ARDFields *opts = SC_get_ARD(stmt); + ARDFields *opts = SC_get_ARDF(stmt); + GetDataInfo *gdata = SC_get_GDTI(stmt); Int4 len = 0, copy_len = 0; SIMPLE_TIME std_time; @@ -390,8 +391,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 const char *neut_str = value; char midtemp[2][32]; int mtemp_cnt = 0; - static BindInfoClass sbic; - BindInfoClass *pbic; + static GetDataClass sgdc; + GetDataClass *pgdc; #ifdef UNICODE_SUPPORT BOOL wchanged = FALSE; #endif /* UNICODE_SUPPORT */ @@ -402,19 +403,25 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 if (stmt->current_col >= 0) { - pbic = &opts->bindings[stmt->current_col]; - if (pbic->data_left == -2) - pbic->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be * + if (stmt->current_col >= opts->allocated) + { + return SQL_ERROR; + } + if (gdata->allocated != opts->allocated) + extend_getdata_info(gdata, opts->allocated, TRUE); + pgdc = &gdata->gdata[stmt->current_col]; + if (pgdc->data_left == -2) + pgdc->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be * * needed by ADO ? */ - if (pbic->data_left == 0) + if (pgdc->data_left == 0) { - if (pbic->ttlbuf != NULL) + if (pgdc->ttlbuf != NULL) { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; - pbic->ttlbuflen = 0; + free(pgdc->ttlbuf); + pgdc->ttlbuf = NULL; + pgdc->ttlbuflen = 0; } - pbic->data_left = -2; /* needed by ADO ? */ + pgdc->data_left = -2; /* needed by ADO ? */ return COPY_NO_DATA_FOUND; } } @@ -732,12 +739,12 @@ inolog("2stime fr=%d\n", std_time.fr); default: if (stmt->current_col < 0) { - pbic = &sbic; - pbic->data_left = -1; + pgdc = &sgdc; + pgdc->data_left = -1; } else - pbic = &opts->bindings[stmt->current_col]; - if (pbic->data_left < 0) + pgdc = &gdata->gdata[stmt->current_col]; + if (pgdc->data_left < 0) { BOOL lf_conv = conn->connInfo.lf_conversion; #ifdef UNICODE_SUPPORT @@ -779,69 +786,69 @@ inolog("2stime fr=%d\n", std_time.fr); #endif /* WIN_UNICODE_SUPPORT */ break; } - if (!pbic->ttlbuf) - pbic->ttlbuflen = 0; + if (!pgdc->ttlbuf) + pgdc->ttlbuflen = 0; if (changed || len >= cbValueMax) { - if (len >= (int) pbic->ttlbuflen) + if (len >= (int) pgdc->ttlbuflen) { - pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1); - pbic->ttlbuflen = len + 1; + pgdc->ttlbuf = realloc(pgdc->ttlbuf, len + 1); + pgdc->ttlbuflen = len + 1; } #ifdef UNICODE_SUPPORT if (fCType == SQL_C_WCHAR) { - utf8_to_ucs2_lf(neut_str, -1, lf_conv, (SQLWCHAR *) pbic->ttlbuf, len / 2); + utf8_to_ucs2_lf(neut_str, -1, lf_conv, (SQLWCHAR *) pgdc->ttlbuf, len / 2); } else #endif /* UNICODE_SUPPORT */ if (PG_TYPE_BYTEA == field_type) { - len = convert_from_pgbinary(neut_str, pbic->ttlbuf, pbic->ttlbuflen); - pg_bin2hex(pbic->ttlbuf, pbic->ttlbuf, len); + len = convert_from_pgbinary(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen); + pg_bin2hex(pgdc->ttlbuf, pgdc->ttlbuf, len); len *= 2; } else #ifdef WIN_UNICODE_SUPPORT if (fCType == SQL_C_CHAR) { - len = WideCharToMultiByte(CP_ACP, 0, allocbuf, wstrlen, pbic->ttlbuf, pbic->ttlbuflen, NULL, NULL); + len = WideCharToMultiByte(CP_ACP, 0, allocbuf, wstrlen, pgdc->ttlbuf, pgdc->ttlbuflen, NULL, NULL); free(allocbuf); allocbuf = NULL; } else #endif /* WIN_UNICODE_SUPPORT */ - convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, lf_conv, &changed); - ptr = pbic->ttlbuf; - pbic->ttlbufused = len; + convert_linefeeds(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen, lf_conv, &changed); + ptr = pgdc->ttlbuf; + pgdc->ttlbufused = len; } else { - if (pbic->ttlbuf) + if (pgdc->ttlbuf) { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; + free(pgdc->ttlbuf); + pgdc->ttlbuf = NULL; } ptr = neut_str; } } else { - ptr = pbic->ttlbuf; - len = pbic->ttlbufused; + ptr = pgdc->ttlbuf; + len = pgdc->ttlbufused; } mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr); if (stmt->current_col >= 0) { - if (pbic->data_left > 0) + if (pgdc->data_left > 0) { - ptr += len - pbic->data_left; - len = pbic->data_left; + ptr += len - pgdc->data_left; + len = pgdc->data_left; } else - pbic->data_left = len; + pgdc->data_left = len; } if (cbValueMax > 0) @@ -886,7 +893,7 @@ inolog("2stime fr=%d\n", std_time.fr); /* Adjust data_left for next time */ if (stmt->current_col >= 0) - pbic->data_left -= copy_len; + pgdc->data_left -= copy_len; } /* @@ -897,10 +904,10 @@ inolog("2stime fr=%d\n", std_time.fr); result = COPY_RESULT_TRUNCATED; else { - if (pbic->ttlbuf != NULL) + if (pgdc->ttlbuf != NULL) { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; + free(pgdc->ttlbuf); + pgdc->ttlbuf = NULL; } } @@ -1239,14 +1246,14 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival); if (stmt->current_col < 0) { - pbic = &sbic; - pbic->data_left = -1; + pgdc = &sgdc; + pgdc->data_left = -1; } else - pbic = &opts->bindings[stmt->current_col]; - if (!pbic->ttlbuf) - pbic->ttlbuflen = 0; - if (pbic->data_left < 0) + pgdc = &gdata->gdata[stmt->current_col]; + if (!pgdc->ttlbuf) + pgdc->ttlbuflen = 0; + if (pgdc->data_left < 0) { if (cbValueMax <= 0) { @@ -1254,17 +1261,17 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival); result = COPY_RESULT_TRUNCATED; break; } - if (len = strlen(neut_str), len >= (int) pbic->ttlbuflen) + if (len = strlen(neut_str), len >= (int) pgdc->ttlbuflen) { - pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1); - pbic->ttlbuflen = len + 1; + pgdc->ttlbuf = realloc(pgdc->ttlbuf, len + 1); + pgdc->ttlbuflen = len + 1; } - len = convert_from_pgbinary(neut_str, pbic->ttlbuf, pbic->ttlbuflen); - pbic->ttlbufused = len; + len = convert_from_pgbinary(neut_str, pgdc->ttlbuf, pgdc->ttlbuflen); + pgdc->ttlbufused = len; } else - len = pbic->ttlbufused; - ptr = pbic->ttlbuf; + len = pgdc->ttlbufused; + ptr = pgdc->ttlbuf; if (stmt->current_col >= 0) { @@ -1272,15 +1279,15 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival); * Second (or more) call to SQLGetData so move the * pointer */ - if (pbic->data_left > 0) + if (pgdc->data_left > 0) { - ptr += len - pbic->data_left; - len = pbic->data_left; + ptr += len - pgdc->data_left; + len = pgdc->data_left; } /* First call to SQLGetData so initialize data_left */ else - pbic->data_left = len; + pgdc->data_left = len; } @@ -1293,7 +1300,7 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival); /* Adjust data_left for next time */ if (stmt->current_col >= 0) - pbic->data_left -= copy_len; + pgdc->data_left -= copy_len; } /* @@ -1302,10 +1309,10 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival); */ if (len > cbValueMax) result = COPY_RESULT_TRUNCATED; - else if (pbic->ttlbuf) + else if (pgdc->ttlbuf) { - free(pbic->ttlbuf); - pbic->ttlbuf = NULL; + free(pgdc->ttlbuf); + pgdc->ttlbuf = NULL; } mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len); break; @@ -1320,7 +1327,7 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival); *((SDWORD *) pcbValueBindRow) = len; if (result == COPY_OK && stmt->current_col >= 0) - opts->bindings[stmt->current_col].data_left = 0; + gdata->gdata[stmt->current_col].data_left = 0; return result; } @@ -1392,6 +1399,7 @@ typedef struct _QueryBuild { int param_number; APDFields *apdopts; IPDFields *ipdopts; + PutDataInfo *pdata; UInt4 load_stmt_len; UInt4 flags; BOOL lf_conv; @@ -1414,12 +1422,14 @@ QB_initialize(QueryBuild *qb, UInt4 size, StatementClass *stmt, ConnectionClass qb->stmt = stmt; qb->apdopts = NULL; qb->ipdopts = NULL; + qb->pdata = NULL; if (conn) qb->conn = conn; else if (stmt) { - qb->apdopts = SC_get_APD(stmt); - qb->ipdopts = SC_get_IPD(stmt); + qb->apdopts = SC_get_APDF(stmt); + qb->ipdopts = SC_get_IPDF(stmt); + qb->pdata = SC_get_PDTI(stmt); qb->conn = SC_get_conn(stmt); if (stmt->pre_executing) qb->flags |= FLGB_PRE_EXECUTING; @@ -2381,9 +2391,7 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform) chrform[newlen++] = '-'; for (i = len - 1; i >= ns->scale; i--) chrform[newlen++] = calv[i] + '0'; - if (!newlen) - chrform[newlen++] = '0'; - if (ns->scale > 0) + if (ns->scale > 0) { chrform[newlen++] = '.'; for (; i >= 0; i--) @@ -2408,6 +2416,7 @@ ResolveOneParam(QueryBuild *qb) ConnInfo *ci = &(conn->connInfo); const APDFields *apdopts = qb->apdopts; const IPDFields *ipdopts = qb->ipdopts; + PutDataInfo *pdata = qb->pdata; int param_number; char param_string[128], tmp[256], @@ -2449,7 +2458,7 @@ ResolveOneParam(QueryBuild *qb) return SQL_ERROR; } } - if (SQL_PARAM_OUTPUT == apdopts->parameters[param_number].paramType) + if (SQL_PARAM_OUTPUT == ipdopts->parameters[param_number].paramType) { qb->errormsg = "Output parameter isn't available"; qb->errornumber = STMT_NOT_IMPLEMENTED_ERROR; @@ -2468,9 +2477,11 @@ ResolveOneParam(QueryBuild *qb) /* Assign correct buffers based on data at exec param or not */ if (apdopts->parameters[param_number].data_at_exec) { - used = apdopts->parameters[param_number].EXEC_used ? *apdopts->parameters[param_number].EXEC_used : SQL_NTS; - buffer = apdopts->parameters[param_number].EXEC_buffer; - if (apdopts->parameters[param_number].lobj_oid) + if (pdata->allocated != apdopts->allocated) + extend_putdata_info(pdata, apdopts->allocated, TRUE); + used = pdata->pdata[param_number].EXEC_used ? *pdata->pdata[param_number].EXEC_used : SQL_NTS; + buffer = pdata->pdata[param_number].EXEC_buffer; + if (pdata->pdata[param_number].lobj_oid) handling_large_object = TRUE; } else @@ -2563,17 +2574,25 @@ ResolveOneParam(QueryBuild *qb) case SQL_C_BINARY: buf = buffer; break; - case SQL_C_CHAR: #ifdef WIN_UNICODE_SUPPORT - if (SQL_NTS == used) - used = strlen(buffer); - allocbuf = malloc(2 * (used + 1)); - used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer, - used, (LPWSTR) allocbuf, used + 1); - buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, &used, FALSE); - free(allocbuf); - allocbuf = buf; + switch (param_sqltype) + { + case SQL_WCHAR: + case SQL_WVARCHAR: + case SQL_WLONGVARCHAR: + if (SQL_NTS == used) + used = strlen(buffer); + allocbuf = malloc(2 * (used + 1)); + used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer, + used, (LPWSTR) allocbuf, used + 1); + buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, &used, FALSE); + free(allocbuf); + allocbuf = buf; + break; + default: + buf = buffer; + } #else buf = buffer; #endif /* WIN_UNICODE_SUPPORT */ @@ -2853,7 +2872,7 @@ ResolveOneParam(QueryBuild *qb) } if (apdopts->parameters[param_number].data_at_exec) - lobj_oid = apdopts->parameters[param_number].lobj_oid; + lobj_oid = pdata->pdata[param_number].lobj_oid; else { /* begin transaction if needed */ @@ -3793,10 +3812,10 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, int retval, result, left = -1; - BindInfoClass *bindInfo = NULL; + GetDataClass *gdata = NULL; ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); - ARDFields *opts = SC_get_ARD(stmt); + GetDataInfo *gdata_info = SC_get_GDTI(stmt); int factor; switch (fCType) @@ -3814,8 +3833,8 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, /* If using SQLGetData, then current_col will be set */ if (stmt->current_col >= 0) { - bindInfo = &opts->bindings[stmt->current_col]; - left = bindInfo->data_left; + gdata = &gdata_info->gdata[stmt->current_col]; + left = gdata->data_left; } /* @@ -3823,7 +3842,7 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, * for reading */ - if (!bindInfo || bindInfo->data_left == -1) + if (!gdata || gdata->data_left == -1) { /* begin transaction if needed */ if (!CC_is_in_trans(conn)) @@ -3848,8 +3867,8 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, if (retval >= 0) { left = lo_tell(conn, stmt->lobj_fd); - if (bindInfo) - bindInfo->data_left = left; + if (gdata) + gdata->data_left = left; /* return to beginning */ lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET); @@ -3897,10 +3916,10 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, if (pcbValue) *pcbValue = left < 0 ? SQL_NO_TOTAL : left * factor; - if (bindInfo && bindInfo->data_left > 0) - bindInfo->data_left -= retval; + if (gdata && gdata->data_left > 0) + gdata->data_left -= retval; - if (!bindInfo || bindInfo->data_left == 0) + if (!gdata || gdata->data_left == 0) { lo_close(conn, stmt->lobj_fd); diff --git a/descriptor.c b/descriptor.c new file mode 100644 index 0000000..cf1074e --- /dev/null +++ b/descriptor.c @@ -0,0 +1,572 @@ +/*------- + * Module: descriptor.c + * + * Description: This module contains functions related to creating + * and manipulating a statement. + * + * Classes: DescriptorClass (Functions prefix: "DC_") + * + * + * Comments: See "notice.txt" for copyright and license information. + *------- + */ + +#include "environ.h" +#include "connection.h" +#include "descriptor.h" +#include "statement.h" + +#include +#include +#include + +#include "pgapifunc.h" + + +void DC_Constructor(DescriptorClass *self, BOOL embedded, StatementClass *stmt) +{ + memset(self, 0, sizeof(DescriptorClass)); + self->embedded = embedded; +} + +static void ARDFields_free(ARDFields * self) +{ +inolog("ARDFields_free %x bookmark=%x", self, self->bookmark); + if (self->bookmark) + { + free(self->bookmark); + self->bookmark = NULL; + } + /* + * the memory pointed to by the bindings is not deallocated by the + * driver but by the application that uses that driver, so we don't + * have to care + */ + ARD_unbind_cols(self, TRUE); +} + +static void APDFields_free(APDFields * self) +{ + if (self->bookmark) + { + free(self->bookmark); + self->bookmark = NULL; + } + /* param bindings */ + APD_free_params(self, STMT_FREE_PARAMS_ALL); +} + +static void IRDFields_free(IRDFields * self) +{ + /* Free the parsed field information */ + if (self->fi) + { + int i; + + for (i = 0; i < (int) self->nfields; i++) + { + if (self->fi[i]) + { + if (self->fi[i]->schema) + free(self->fi[i]->schema); + free(self->fi[i]); + } + } + free(self->fi); + self->fi = NULL; + } +} + +static void IPDFields_free(IPDFields * self) +{ + /* param bindings */ + IPD_free_params(self, STMT_FREE_PARAMS_ALL); +} + +void DC_Destructor(DescriptorClass *self) +{ + if (self->__error_message) + { + free(self->__error_message); + self->__error_message = NULL; + } + if (self->pgerror) + { + ER_Destructor(self->pgerror); + self->pgerror = NULL; + } + if (self->type_defined) + { + switch (self->desc_type) + { + case SQL_ATTR_APP_ROW_DESC: + ARDFields_free((ARDFields *) (self + 1)); + break; + case SQL_ATTR_APP_PARAM_DESC: + APDFields_free((APDFields *) (self + 1)); + break; + case SQL_ATTR_IMP_ROW_DESC: + IRDFields_free((IRDFields *) (self + 1)); + break; + case SQL_ATTR_IMP_PARAM_DESC: + IPDFields_free((IPDFields *) (self + 1)); + break; + } + } +} + +void InitializeEmbeddedDescriptor(DescriptorClass *desc, StatementClass *stmt, + UInt4 desc_type) +{ + DC_Constructor(desc, TRUE, stmt); + DC_get_conn(desc) = SC_get_conn(stmt); + desc->type_defined = TRUE; + desc->desc_type = desc_type; + switch (desc_type) + { + case SQL_ATTR_APP_ROW_DESC: + memset(desc + 1, 0, sizeof(ARDFields)); + stmt->ard = (ARDClass *) desc; + break; + case SQL_ATTR_APP_PARAM_DESC: + memset(desc + 1, 0, sizeof(APDFields)); + stmt->apd = (APDClass *) desc; + break; + case SQL_ATTR_IMP_ROW_DESC: + memset(desc + 1, 0, sizeof(IRDFields)); + stmt->ird = (IRDClass *) desc; + stmt->ird->irdopts.stmt = stmt; + break; + case SQL_ATTR_IMP_PARAM_DESC: + memset(desc + 1, 0, sizeof(IPDFields)); + stmt->ipd = (IPDClass *) desc; + break; + } +} + +/* + * ARDFields initialize + */ +void +InitializeARDFields(ARDFields *opt) +{ + memset(opt, 0, sizeof(ARDFields)); +#if (ODBCVER >= 0x0300) + opt->size_of_rowset = 1; +#endif /* ODBCVER */ + opt->bind_size = 0; /* default is to bind by column */ + opt->size_of_rowset_odbc2 = 1; +} +/* + * APDFields initialize + */ +void +InitializeAPDFields(APDFields *opt) +{ + memset(opt, 0, sizeof(APDFields)); + opt->paramset_size = 1; + opt->param_bind_type = 0; /* default is to bind by column */ + opt->paramset_size_dummy = 1; /* dummy setting */ +} + +BindInfoClass *ARD_AllocBookmark(ARDFields *ardopts) +{ + if (!ardopts->bookmark) + { + ardopts->bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass)); + memset(ardopts->bookmark, 0, sizeof(BindInfoClass)); + } + return ardopts->bookmark; +} + +#if (ODBCVER >= 0x0300) + +#define DESC_INCREMENT 10 +char CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc) +{ + int i; + + mylog("CC_add_descriptor: self=%u, desc=%u\n", self, desc); + + for (i = 0; i < self->num_descs; i++) + { + if (!self->descs[i]) + { + DC_get_conn(desc) = self; + self->descs[i] = desc; + return TRUE; + } + } + /* no more room -- allocate more memory */ + self->descs = (DescriptorClass **) realloc(self->descs, sizeof(DescriptorClass *) * (DESC_INCREMENT + self->num_descs)); + if (!self->descs) + return FALSE; + + memset(&self->descs[self->num_descs], 0, sizeof(DescriptorClass *) * + DESC_INCREMENT); + DC_get_conn(desc) = self; + self->descs[self->num_descs] = desc; + self->num_descs += DESC_INCREMENT; + + return TRUE; +} + +/* + * This API allocates a Application descriptor. + */ +RETCODE SQL_API PGAPI_AllocDesc(HDBC ConnectionHandle, + SQLHDESC *DescriptorHandle) +{ + CSTR func = "PGAPI_AllocDesc"; + ConnectionClass *conn = (ConnectionClass *) ConnectionHandle; + RETCODE ret = SQL_SUCCESS; + DescriptorClass *desc = (DescriptorClass *) malloc(sizeof(DescriptorAlloc)); + + mylog("%s: entering...\n", func); + if (desc) + { + memset(desc, 0, sizeof(DescriptorAlloc)); + DC_get_conn(desc) = conn; + if (CC_add_descriptor(conn, desc)) + *DescriptorHandle = desc; + else + { + free(desc); + CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of descriptors exceeded"); + ret = SQL_ERROR; + } + } + else + { + CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory ti allocate a further descriptor"); + ret = SQL_ERROR; + } + return ret; +} + +RETCODE SQL_API PGAPI_FreeDesc(SQLHDESC DescriptorHandle) +{ + CSTR func = "PGAPI_FreeDesc"; + DescriptorClass *desc = (DescriptorClass *) DescriptorHandle; + RETCODE ret = SQL_SUCCESS; + + mylog("%s: entering...\n", func); + DC_Destructor(desc); + if (!desc->embedded) + { + int i; + ConnectionClass *conn = DC_get_conn(desc); + + for (i = 0; i < conn->num_descs; i++) + { + if (conn->descs[i] == desc) + { + conn->descs[i] = NULL; + break; + } + } + free(desc); + } + return ret; +} + +static void BindInfoClass_copy(const BindInfoClass *src, BindInfoClass *target) +{ + memcpy(target, src, sizeof(BindInfoClass)); +} +static void ARDFields_copy(const ARDFields *src, ARDFields *target) +{ + memcpy(target, src, sizeof(ARDFields)); + target->bookmark = NULL; + if (src->bookmark) + { + BindInfoClass *bookmark = ARD_AllocBookmark(target); + BindInfoClass_copy(src->bookmark, bookmark); + } + if (src->allocated <= 0) + { + target->allocated = 0; + target->bindings = NULL; + } + else + { + int i; + + target->bindings = malloc(target->allocated * sizeof(BindInfoClass)); + for (i = 0; i < target->allocated; i++) + BindInfoClass_copy(&src->bindings[i], &target->bindings[i]); + } +} + +static void ParameterInfoClass_copy(const ParameterInfoClass *src, ParameterInfoClass *target) +{ + memcpy(target, src, sizeof(ParameterInfoClass)); +} +static void APDFields_copy(const APDFields *src, APDFields *target) +{ + memcpy(target, src, sizeof(APDFields)); + if (src->bookmark) + { + target->bookmark = malloc(sizeof(BindInfoClass)); + ParameterInfoClass_copy(src->bookmark, target->bookmark); + } + if (src->allocated <= 0) + { + target->allocated = 0; + target->parameters = NULL; + } + else + { + int i; + + target->parameters = malloc(target->allocated * sizeof(ParameterInfoClass)); + for (i = 0; i < target->allocated; i++) + ParameterInfoClass_copy(&src->parameters[i], &target->parameters[i]); + } +} + +static void ParameterImplClass_copy(const ParameterImplClass *src, ParameterImplClass *target) +{ + memcpy(target, src, sizeof(ParameterImplClass)); +} +static void IPDFields_copy(const IPDFields *src, IPDFields *target) +{ + memcpy(target, src, sizeof(IPDFields)); + if (src->allocated <= 0) + { + target->allocated = 0; + target->parameters = NULL; + } + else + { + int i; + + target->parameters = (ParameterImplClass *) malloc(target->allocated * sizeof(ParameterInfoClass)); + for (i = 0; i < target->allocated; i++) + ParameterImplClass_copy(&src->parameters[i], &target->parameters[i]); + } +} + +RETCODE SQL_API +PGAPI_CopyDesc(SQLHDESC SourceDescHandle, + SQLHDESC TargetDescHandle) +{ + CSTR func = "PGAPI_CopyDesc"; + RETCODE ret = SQL_ERROR; + DescriptorClass *src, *target; + ARDFields *ard_src, *ard_tgt; + APDFields *apd_src, *apd_tgt; + IPDFields *ipd_src, *ipd_tgt; + + mylog("%s: entering...\n", func); + src = (DescriptorClass *) SourceDescHandle; + target = (DescriptorClass *) TargetDescHandle; + if (!src->type_defined) + { + mylog("source type undefined\n"); + DC_set_error(target, DESC_EXEC_ERROR, "source handle type undefined"); + return ret; + } + if (target->type_defined) + { +inolog("CopyDesc source type=%d -> target type=%d\n", src->desc_type, target->desc_type); + if (SQL_ATTR_IMP_ROW_DESC == target->desc_type) + { + mylog("can't modify IRD\n"); + DC_set_error(target, DESC_EXEC_ERROR, "can't copy to IRD"); + return ret; + } + else if (target->desc_type != src->desc_type) + { + mylog("src type != target type\n"); + DC_set_error(target, DESC_EXEC_ERROR, "src descriptor != target type"); + return ret; + } + DC_Destructor(target); + } + ret = SQL_SUCCESS; + switch (src->desc_type) + { + case SQL_ATTR_APP_ROW_DESC: +inolog("src=%x target=%x type=%d", src, target, src->desc_type); + if (!target->type_defined) + { + target->desc_type = src->desc_type; + } + ard_src = (ARDFields *) (src + 1); +inolog(" rowset_size=%d bind_size=%d ope_ptr=%x off_ptr=%x\n", +ard_src->size_of_rowset, ard_src->bind_size, +ard_src->row_operation_ptr, ard_src->row_offset_ptr); + ard_tgt = (ARDFields *) (target + 1); +inolog(" target=%x", ard_tgt); + ARDFields_copy(ard_src, ard_tgt); +inolog(" offset_ptr=%x\n", ard_tgt->row_offset_ptr); + break; + case SQL_ATTR_APP_PARAM_DESC: + if (!target->type_defined) + { + target->desc_type = src->desc_type; + } + apd_src = (APDFields *) (src + 1); + apd_tgt = (APDFields *) (target + 1); + APDFields_copy(apd_src, apd_tgt); + break; + case SQL_ATTR_IMP_PARAM_DESC: + if (!target->type_defined) + { + target->desc_type = src->desc_type; + } + ipd_src = (IPDFields *) (src + 1); + ipd_tgt = (IPDFields *) (target + 1); + IPDFields_copy(ipd_src, ipd_tgt); + break; + default: + mylog("invalid descriptor handle type=%d\n", src->desc_type); + DC_set_error(target, DESC_EXEC_ERROR, "invalid descriptor type"); + ret = SQL_ERROR; + } + + if (SQL_SUCCESS == ret) + target->type_defined = TRUE; + return ret; +} + +void DC_clear_error(DescriptorClass *self) +{ + if (self->__error_message) + { + free(self->__error_message); + self->__error_message = NULL; + } + if (self->pgerror) + { + ER_Destructor(self->pgerror); + self->pgerror = NULL; + } + self->__error_number = 0; + self->error_row = 0; + self->error_index = 0; +} + +void DC_set_error(DescriptorClass *desc, int errornumber, const char *errormsg) +{ + if (desc->__error_message) + free(desc->__error_message); + desc->__error_number = errornumber; + desc->__error_message = errormsg ? strdup(errormsg) : NULL; +} +void DC_set_errormsg(DescriptorClass *desc, const char *errormsg) +{ + if (desc->__error_message) + free(desc->__error_message); + desc->__error_message = errormsg ? strdup(errormsg) : NULL; +} +const char *DC_get_errormsg(const DescriptorClass *desc) +{ + return desc->__error_message; +} +int DC_get_errornumber(const DescriptorClass *desc) +{ + return desc->__error_number; +} + +/* Map sql commands to statement types */ +static struct +{ + int number; + const char * ver3str; + const char * ver2str; +} Descriptor_sqlstate[] = + +{ + { DESC_OK, "00000", "00000" }, /* OK */ + { DESC_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */ + { DESC_STATUS_ERROR, "HY010", "S1010" }, + { DESC_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */ + { DESC_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */ + { DESC_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */ + { DESC_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */ + { DESC_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */ + { DESC_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */ + { DESC_STILL_EXECUTING, "HY010", "S1010" }, + { DESC_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not + * capable' */ + { DESC_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" }, + { DESC_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" }, + { DESC_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" }, + { DESC_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" }, + { DESC_INVALID_CURSOR_STATE_ERROR, "07005", "24000" }, + { DESC_OPTION_VALUE_CHANGED, "01S02", "01S02" }, + { DESC_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */ + { DESC_NO_CURSOR_NAME, "S1015", "S1015" }, + { DESC_INVALID_CURSOR_NAME, "34000", "34000" }, + { DESC_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */ + { DESC_ROW_OUT_OF_RANGE, "HY107", "S1107" }, + { DESC_OPERATION_CANCELLED, "HY008", "S1008" }, + { DESC_INVALID_CURSOR_POSITION, "HY109", "S1109" }, + { DESC_VALUE_OUT_OF_RANGE, "HY019", "22003" }, + { DESC_OPERATION_INVALID, "HY011", "S1011" }, + { DESC_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" }, + { DESC_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */ + { DESC_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" }, + { DESC_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" }, + { DESC_ERROR_IN_ROW, "01S01", "01S01" }, + { DESC_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" }, + { DESC_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" }, + { DESC_FETCH_OUT_OF_RANGE, "HY106", "S1106" }, + { DESC_COUNT_FIELD_INCORRECT, "07002", "07002" }, +}; + +static PG_ErrorInfo *DC_create_errorinfo(const DescriptorClass *desc) +{ + PG_ErrorInfo *error; + ConnectionClass *conn; + EnvironmentClass *env; + Int4 errornum; + + if (desc->pgerror) + return desc->pgerror; + errornum = desc->__error_number; + error = ER_Constructor(errornum, desc->__error_message); + if (!error) + return error; + conn = DC_get_conn(desc); + env = (EnvironmentClass *) conn->henv; + if (errornum < 0 || + errornum >= sizeof(Descriptor_sqlstate) / sizeof(Descriptor_sqlstate[0])) + errornum = 1; + strcpy(error->sqlstate, EN_is_odbc3(env) ? Descriptor_sqlstate[errornum].ver3str : Descriptor_sqlstate[errornum].ver2str); + return error; +} +void +DC_log_error(const char *func, const char *desc, const DescriptorClass *self) +{ +#define nullcheck(a) (a ? a : "(NULL)") + if (self) + { + qlog("DESCRIPTOR ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message)); + mylog("DESCRIPTOR ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message)); + } +} + +/* Returns the next SQL error information. */ +RETCODE SQL_API +PGAPI_DescError( SQLHDESC hdesc, + SWORD RecNumber, + UCHAR FAR * szSqlState, + SDWORD FAR * pfNativeError, + UCHAR FAR * szErrorMsg, + SWORD cbErrorMsgMax, + SWORD FAR * pcbErrorMsg, + UWORD flag) +{ + /* CC: return an error of a hdesc */ + DescriptorClass *desc = (DescriptorClass *) hdesc; + + desc->pgerror = DC_create_errorinfo(desc); + return ER_ReturnError(desc->pgerror, RecNumber, szSqlState, + pfNativeError, szErrorMsg, cbErrorMsgMax, + pcbErrorMsg, flag); +} + +#endif /* ODBCVER */ diff --git a/descriptor.h b/descriptor.h index 072a04f..f05cfcd 100644 --- a/descriptor.h +++ b/descriptor.h @@ -5,7 +5,7 @@ * * Comments: See "notice.txt" for copyright and license information. * - * $Id: descriptor.h,v 1.10 2003/07/31 01:57:50 hinoue Exp $ + * $Id: descriptor.h,v 1.11 2003/10/25 04:19:19 hinoue Exp $ * */ @@ -46,14 +46,29 @@ typedef struct Int4 FI_precision(const FIELD_INFO *); Int4 FI_scale(const FIELD_INFO *); +typedef struct DescriptorHeader_ +{ + ConnectionClass *conn_conn; + char embedded; + char type_defined; + UInt4 desc_type; + UInt4 error_row; /* 1-based row */ + UInt4 error_index; /* 1-based index */ + Int4 __error_number; + char *__error_message; + PG_ErrorInfo *pgerror; +} DescriptorClass; + +/* + * ARD and APD are(must be) of the same format + */ struct ARDFields_ { - StatementClass *stmt; #if (ODBCVER >= 0x0300) - int size_of_rowset; /* for ODBC3 fetch operations */ + int size_of_rowset; /* for ODBC3 fetch operation */ #endif /* ODBCVER */ - int bind_size; /* size of each structure if using Row - * Binding */ + int bind_size; /* size of each structure if using + * Row-wise Binding */ UInt2 *row_operation_ptr; UInt4 *row_offset_ptr; BindInfoClass *bookmark; @@ -62,16 +77,20 @@ struct ARDFields_ int size_of_rowset_odbc2; /* for SQLExtendedFetch */ }; +/* + * APD must be of the same format as ARD + */ struct APDFields_ { - StatementClass *stmt; int paramset_size; - int param_bind_type; /* size of each structure if using Param - * Binding */ - UInt2 *param_operation_ptr; - UInt4 *param_offset_ptr; + int param_bind_type; /* size of each structure if using + * Row-wsie Parameter Binding */ + UInt2 *param_operation_ptr; + UInt4 *param_offset_ptr; + ParameterInfoClass *bookmark; /* dummy item to fit APD to ARD */ ParameterInfoClass *parameters; - int allocated; + int allocated; + int paramset_size_dummy; /* dummy item to fit APD to ARD */ }; struct IRDFields_ @@ -85,26 +104,102 @@ struct IRDFields_ struct IPDFields_ { - StatementClass *stmt; UInt4 *param_processed_ptr; UInt2 *param_status_ptr; ParameterImplClass *parameters; int allocated; }; +typedef struct +{ + DescriptorClass deschd; + union { + ARDFields ard; + APDFields apd; + IRDFields ird; + IPDFields ipd; + } flds; +} DescriptorAlloc; +typedef struct +{ + DescriptorClass deschd; + ARDFields ardopts; +} ARDClass; +typedef struct +{ + DescriptorClass deschd; + APDFields apdopts; +} APDClass; +typedef struct +{ + DescriptorClass deschd; + IRDFields irdopts; +} IRDClass; +typedef struct +{ + DescriptorClass deschd; + IPDFields ipdopts; +} IPDClass; + +#define DC_get_conn(a) (a->conn_conn) + +void InitializeEmbeddedDescriptor(DescriptorClass *, StatementClass *stmt, + UInt4 desc_type); +void DC_Destructor(desc); void InitializeARDFields(ARDFields *self); void InitializeAPDFields(APDFields *self); /* void InitializeIRDFields(IRDFields *self); void InitializeIPDFiedls(IPDFields *self); */ -void ARDFields_free(ARDFields *self); -void APDFields_free(APDFields *self); -void IRDFields_free(IRDFields *self); -void IPDFields_free(IPDFields *self); +BindInfoClass *ARD_AllocBookmark(ARDFields *self); void ARD_unbind_cols(ARDFields *self, BOOL freeall); void APD_free_params(APDFields *self, char option); void IPD_free_params(IPDFields *self, char option); #if (ODBCVER >= 0x0300) -void Desc_set_error(SQLHDESC hdesc, int errornumber, const char * errormsg); +RETCODE DC_set_stmt(DescriptorClass *desc, StatementClass *stmt); +void DC_clear_error(DescriptorClass *desc); +void DC_set_error(DescriptorClass *desc, int errornumber, const char * errormsg); +void DC_set_errormsg(DescriptorClass *desc, const char * errormsg); +PG_ErrorInfo *DC_get_error(DescriptorClass *self); +int DC_get_errornumber(const DescriptorClass *self); +const char *DC_get_errormsg(const DescriptorClass *self); +void DC_log_error(const char *func, const char *desc, const DescriptorClass *self); #endif /* ODBCVER */ -#endif +/* Error numbers about descriptor handle */ +#define DESC_OK 0 +#define DESC_EXEC_ERROR 1 +#define DESC_STATUS_ERROR 2 +#define DESC_SEQUENCE_ERROR 3 +#define DESC_NO_MEMORY_ERROR 4 +#define DESC_COLNUM_ERROR 5 +#define DESC_NO_STMTSTRING 6 +#define DESC_ERROR_TAKEN_FROM_BACKEND 7 +#define DESC_INTERNAL_ERROR 8 +#define DESC_STILL_EXECUTING 9 +#define DESC_NOT_IMPLEMENTED_ERROR 10 +#define DESC_BAD_PARAMETER_NUMBER_ERROR 11 +#define DESC_OPTION_OUT_OF_RANGE_ERROR 12 +#define DESC_INVALID_COLUMN_NUMBER_ERROR 13 +#define DESC_RESTRICTED_DATA_TYPE_ERROR 14 +#define DESC_INVALID_CURSOR_STATE_ERROR 15 +#define DESC_OPTION_VALUE_CHANGED 16 +#define DESC_CREATE_TABLE_ERROR 17 +#define DESC_NO_CURSOR_NAME 18 +#define DESC_INVALID_CURSOR_NAME 19 +#define DESC_INVALID_ARGUMENT_NO 20 +#define DESC_ROW_OUT_OF_RANGE 21 +#define DESC_OPERATION_CANCELLED 22 +#define DESC_INVALID_CURSOR_POSITION 23 +#define DESC_VALUE_OUT_OF_RANGE 24 +#define DESC_OPERATION_INVALID 25 +#define DESC_PROGRAM_TYPE_OUT_OF_RANGE 26 +#define DESC_BAD_ERROR 27 +#define DESC_INVALID_OPTION_IDENTIFIER 28 +#define DESC_RETURN_NULL_WITHOUT_INDICATOR 29 +#define DESC_ERROR_IN_ROW 30 +#define DESC_INVALID_DESCRIPTOR_IDENTIFIER 31 +#define DESC_OPTION_NOT_FOR_THE_DRIVER 32 +#define DESC_FETCH_OUT_OF_RANGE 33 +#define DESC_COUNT_FIELD_INCORRECT 34 + +#endif /* __DESCRIPTOR_H__ */ diff --git a/environ.c b/environ.c index a37ff18..b9cf9d3 100644 --- a/environ.c +++ b/environ.c @@ -89,6 +89,133 @@ pg_sqlstate_set(const EnvironmentClass *env, UCHAR *szSqlState, const UCHAR *ver strcpy(szSqlState, EN_is_odbc3(env) ? ver3str : ver2str); } +PG_ErrorInfo *ER_Constructor(SDWORD errnumber, const char *msg) +{ + PG_ErrorInfo *error; + Int4 aladd, errsize; + + if (DESC_OK == errnumber) + return NULL; + if (msg) + { + errsize = strlen(msg); + aladd = errsize; + } + else + { + errsize = -1; + aladd = 0; + } + error = (PG_ErrorInfo *) malloc(sizeof(PG_ErrorInfo) + aladd); + if (error) + { + memset(error, 0, sizeof(PG_ErrorInfo)); + error->status = errnumber; + error->errorsize = errsize; + if (errsize > 0) + memcpy(error->__error_message, msg, errsize); + error->__error_message[aladd] = '\0'; + error->recsize = -1; + } + return error; +} +void +ER_Destructor(PG_ErrorInfo *self) +{ + if (self->__error_message) + free(self->__error_message); + free(self); +} + +#define DRVMNGRDIV 511 +/* Returns the next SQL error information. */ +RETCODE SQL_API +ER_ReturnError(PG_ErrorInfo *error, + SWORD RecNumber, + UCHAR FAR * szSqlState, + SDWORD FAR * pfNativeError, + UCHAR FAR * szErrorMsg, + SWORD cbErrorMsgMax, + SWORD FAR * pcbErrorMsg, + UWORD flag) +{ + /* CC: return an error of a hstmt */ + BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0), + clear_str = ((flag & PODBC_ERROR_CLEAR) != 0); + const char *msg; + SWORD msglen, stapos, wrtlen, pcblen; + + if (!error) + return SQL_NO_DATA_FOUND; + msg = error->__error_message; + mylog("ER_GetError: status = %d, msg = #%s#\n", error->status, msg); + msglen = (SWORD) strlen(msg); + /* + * Even though an application specifies a larger error message + * buffer, the driver manager changes it silently. + * Therefore we divide the error message into ... + */ + if (error->recsize < 0) + { + if (cbErrorMsgMax > 0) + error->recsize = cbErrorMsgMax - 1; /* apply the first request */ + else + error->recsize = DRVMNGRDIV; + } + if (RecNumber < 0) + { + if (0 == error->errorpos) + RecNumber = 1; + else + RecNumber = 2 + (error->errorpos - 1) / error->recsize; + } + stapos = (RecNumber - 1) * error->recsize; + if (stapos > msglen) + return SQL_NO_DATA_FOUND; + pcblen = wrtlen = msglen - stapos; + if (pcblen > error->recsize) + pcblen = error->recsize; + if (0 == cbErrorMsgMax) + wrtlen = 0; + else if (wrtlen >= cbErrorMsgMax) + { + if (partial_ok) + wrtlen = cbErrorMsgMax - 1; + else if (cbErrorMsgMax <= error->recsize) + wrtlen = 0; + else + wrtlen = error->recsize; + } + if (wrtlen > pcblen) + wrtlen = pcblen; + if (NULL != pcbErrorMsg) + *pcbErrorMsg = pcblen; + + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + { + memcpy(szErrorMsg, msg + stapos, wrtlen); + szErrorMsg[wrtlen] = '\0'; + } + + if (NULL != pfNativeError) + *pfNativeError = error->status; + + if (NULL != szSqlState) + strncpy(szSqlState, error->sqlstate, 6); + + mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg); + if (clear_str) + { + error->errorpos = stapos + wrtlen; + if (error->errorpos >= msglen) + ER_Destructor(error); + } + if (wrtlen == 0) + return SQL_SUCCESS_WITH_INFO; + else + return SQL_SUCCESS; +} + #define DRVMNGRDIV 511 /* Returns the next SQL error information. */ RETCODE SQL_API diff --git a/execute.c b/execute.c index 140d375..87777c4 100644 --- a/execute.c +++ b/execute.c @@ -39,7 +39,7 @@ PGAPI_Prepare(HSTMT hstmt, CSTR func = "PGAPI_Prepare"; StatementClass *self = (StatementClass *) hstmt; - mylog("%s: entering... len=%d\n", func, cbSqlStr); + mylog("%s: entering...\n", func); if (!self) { @@ -130,7 +130,8 @@ RETCODE SQL_API PGAPI_ExecDirect( HSTMT hstmt, UCHAR FAR * szSqlStr, - SDWORD cbSqlStr) + SDWORD cbSqlStr, + UWORD flag) { StatementClass *stmt = (StatementClass *) hstmt; RETCODE result; @@ -183,7 +184,7 @@ PGAPI_ExecDirect( mylog("%s: calling PGAPI_Execute...\n", func); - result = PGAPI_Execute(hstmt); + result = PGAPI_Execute(hstmt, flag); mylog("%s: returned %hd from PGAPI_Execute\n", func, result); return result; @@ -293,8 +294,6 @@ RETCODE Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end) if (kres = res->next, kres) { - if (kres->fields) - CI_Destructor(kres->fields); kres->fields = res->fields; res->fields = NULL; kres->num_fields = res->num_fields; @@ -326,7 +325,7 @@ RETCODE Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end) } } #if (ODBCVER >= 0x0300) - ipdopts = SC_get_IPD(stmt); + ipdopts = SC_get_IPDF(stmt); if (ipdopts->param_status_ptr) { switch (retval) @@ -345,7 +344,7 @@ RETCODE Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end) #endif /* ODBCVER */ if (end_row = stmt->exec_end_row, end_row < 0) { - apdopts = SC_get_APD(stmt); + apdopts = SC_get_APDF(stmt); end_row = apdopts->paramset_size - 1; } if (stmt->inaccurate_result || @@ -373,8 +372,7 @@ RETCODE Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end) /* Execute a prepared SQL statement */ RETCODE SQL_API -PGAPI_Execute( - HSTMT hstmt) +PGAPI_Execute(HSTMT hstmt, UWORD flag) { CSTR func = "PGAPI_Execute"; StatementClass *stmt = (StatementClass *) hstmt; @@ -393,7 +391,7 @@ PGAPI_Execute( return SQL_INVALID_HANDLE; } - apdopts = SC_get_APD(stmt); + apdopts = SC_get_APDF(stmt); /* * If the statement is premature, it means we already executed it from * an SQLPrepare/SQLDescribeCol type of scenario. So just return @@ -487,7 +485,7 @@ PGAPI_Execute( end_row = apdopts->paramset_size - 1; if (stmt->exec_current_row < 0) stmt->exec_current_row = start_row; - ipdopts = SC_get_IPD(stmt); + ipdopts = SC_get_IPDF(stmt); if (stmt->exec_current_row == start_row) { if (ipdopts->param_processed_ptr) @@ -748,6 +746,7 @@ PGAPI_Cancel( stmt->data_at_exec = -1; stmt->current_exec_param = -1; stmt->put_data = FALSE; + cancelNeedDataState(stmt); return SQL_SUCCESS; } @@ -817,11 +816,11 @@ PGAPI_ParamData( PTR FAR * prgbValue) { CSTR func = "PGAPI_ParamData"; - StatementClass *stmt = (StatementClass *) hstmt; + StatementClass *stmt = (StatementClass *) hstmt, *estmt; APDFields *apdopts; IPDFields *ipdopts; - int i, - retval; + RETCODE retval; + int i; ConnInfo *ci; mylog("%s: entering...\n", func); @@ -832,18 +831,19 @@ PGAPI_ParamData( return SQL_INVALID_HANDLE; } ci = &(SC_get_conn(stmt)->connInfo); - apdopts = SC_get_APD(stmt); - mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, stmt->data_at_exec, apdopts->allocated); + estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt; + apdopts = SC_get_APDF(estmt); + mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, estmt->data_at_exec, apdopts->allocated); - if (stmt->data_at_exec < 0) + if (estmt->data_at_exec < 0) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement"); SC_log_error(func, "", stmt); return SQL_ERROR; } - if (stmt->data_at_exec > apdopts->allocated) + if (estmt->data_at_exec > apdopts->allocated) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present"); SC_log_error(func, "", stmt); @@ -851,33 +851,36 @@ PGAPI_ParamData( } /* close the large object */ - if (stmt->lobj_fd >= 0) + if (estmt->lobj_fd >= 0) { - lo_close(stmt->hdbc, stmt->lobj_fd); + lo_close(estmt->hdbc, estmt->lobj_fd); /* commit transaction if needed */ - if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) + if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(estmt->hdbc)) { - if (!CC_commit(stmt->hdbc)) + if (!CC_commit(estmt->hdbc)) { SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction"); SC_log_error(func, "", stmt); return SQL_ERROR; } } - stmt->lobj_fd = -1; + estmt->lobj_fd = -1; } /* Done, now copy the params and then execute the statement */ - ipdopts = SC_get_IPD(stmt); - if (stmt->data_at_exec == 0) + ipdopts = SC_get_IPDF(estmt); + if (estmt->data_at_exec == 0) { BOOL exec_end; - retval = Exec_with_parameters_resolved(stmt, &exec_end); + retval = Exec_with_parameters_resolved(estmt, &exec_end); if (exec_end) - return retval; - if (retval = PGAPI_Execute(stmt), SQL_NEED_DATA != retval) + { + stmt->execute_delegate = NULL; + return dequeueNeedDataCallback(retval, stmt); + } + if (retval = PGAPI_Execute(estmt, 0), SQL_NEED_DATA != retval) return retval; } @@ -885,17 +888,29 @@ PGAPI_ParamData( * 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; + i = estmt->current_exec_param >= 0 ? estmt->current_exec_param + 1 : 0; /* At least 1 data at execution parameter, so Fill in the token value */ for (; i < apdopts->allocated; i++) { if (apdopts->parameters[i].data_at_exec) { - stmt->data_at_exec--; - stmt->current_exec_param = i; - stmt->put_data = FALSE; - *prgbValue = apdopts->parameters[i].buffer; /* token */ + estmt->data_at_exec--; + estmt->current_exec_param = i; + estmt->put_data = FALSE; + if (prgbValue) + { + /* returns token here */ + if (stmt->execute_delegate) + { + UInt4 offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0; + UInt4 perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen; + + *prgbValue = apdopts->parameters[i].buffer + offset + estmt->exec_current_row * perrow; + } + else + *prgbValue = apdopts->parameters[i].buffer; + } break; } } @@ -915,17 +930,19 @@ PGAPI_PutData( SDWORD cbValue) { CSTR func = "PGAPI_PutData"; - StatementClass *stmt = (StatementClass *) hstmt; + StatementClass *stmt = (StatementClass *) hstmt, *estmt; ConnectionClass *conn; APDFields *apdopts; IPDFields *ipdopts; + PutDataInfo *pdata; int old_pos, retval; ParameterInfoClass *current_param; ParameterImplClass *current_iparam; + PutDataClass *current_pdata; char *buffer, *putbuf, *allocbuf = NULL; Int2 ctype; - SDWORD putlen; + SDWORD putlen; BOOL lenset = FALSE; mylog("%s: entering...\n", func); @@ -936,20 +953,23 @@ PGAPI_PutData( return SQL_INVALID_HANDLE; } - apdopts = SC_get_APD(stmt); - if (stmt->current_exec_param < 0) + estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt; + apdopts = SC_get_APDF(estmt); + if (estmt->current_exec_param < 0) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData"); SC_log_error(func, "", stmt); return SQL_ERROR; } - current_param = &(apdopts->parameters[stmt->current_exec_param]); - ipdopts = SC_get_IPD(stmt); - current_iparam = &(ipdopts->parameters[stmt->current_exec_param]); + current_param = &(apdopts->parameters[estmt->current_exec_param]); + ipdopts = SC_get_IPDF(estmt); + current_iparam = &(ipdopts->parameters[estmt->current_exec_param]); + pdata = SC_get_PDTI(estmt); + current_pdata = &(pdata->pdata[estmt->current_exec_param]); ctype = current_param->CType; - conn = SC_get_conn(stmt); + conn = SC_get_conn(estmt); if (ctype == SQL_C_DEFAULT) ctype = sqltype_to_default_ctype(conn, current_iparam->SQLType); if (SQL_NTS == cbValue) @@ -994,21 +1014,21 @@ PGAPI_PutData( } } - if (!stmt->put_data) + if (!estmt->put_data) { /* first call */ mylog("PGAPI_PutData: (1) cbValue = %d\n", cbValue); - stmt->put_data = TRUE; + estmt->put_data = TRUE; - current_param->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD)); - if (!current_param->EXEC_used) + current_pdata->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD)); + if (!current_pdata->EXEC_used) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)"); SC_log_error(func, "", stmt); return SQL_ERROR; } - *current_param->EXEC_used = putlen; + *current_pdata->EXEC_used = putlen; if (cbValue == SQL_NULL_DATA) return SQL_SUCCESS; @@ -1018,9 +1038,9 @@ PGAPI_PutData( if (current_iparam->PGType == conn->lobj_type) { /* begin transaction if needed */ - if (!CC_is_in_trans(stmt->hdbc)) + if (!CC_is_in_trans(conn)) { - if (!CC_begin(stmt->hdbc)) + if (!CC_begin(conn)) { SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction"); SC_log_error(func, "", stmt); @@ -1029,8 +1049,8 @@ PGAPI_PutData( } /* store the oid */ - current_param->lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE); - if (current_param->lobj_oid == 0) + current_pdata->lobj_oid = lo_creat(conn, INV_READ | INV_WRITE); + if (current_pdata->lobj_oid == 0) { SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object."); SC_log_error(func, "", stmt); @@ -1044,28 +1064,28 @@ PGAPI_PutData( /***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) + estmt->lobj_fd = lo_open(conn, current_pdata->lobj_oid, INV_WRITE); + if (estmt->lobj_fd < 0) { SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing."); SC_log_error(func, "", stmt); return SQL_ERROR; } - retval = lo_write(stmt->hdbc, stmt->lobj_fd, putbuf, putlen); + retval = lo_write(conn, estmt->lobj_fd, putbuf, putlen); mylog("lo_write: cbValue=%d, wrote %d bytes\n", putlen, retval); } else { - current_param->EXEC_buffer = malloc(putlen + 1); - if (!current_param->EXEC_buffer) + current_pdata->EXEC_buffer = malloc(putlen + 1); + if (!current_pdata->EXEC_buffer) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)"); SC_log_error(func, "", stmt); return SQL_ERROR; } - memcpy(current_param->EXEC_buffer, putbuf, putlen); - current_param->EXEC_buffer[putlen] = '\0'; + memcpy(current_pdata->EXEC_buffer, putbuf, putlen); + current_pdata->EXEC_buffer[putlen] = '\0'; } } else @@ -1077,23 +1097,23 @@ PGAPI_PutData( if (current_iparam->PGType == conn->lobj_type) { /* the large object fd is in EXEC_buffer */ - retval = lo_write(stmt->hdbc, stmt->lobj_fd, putbuf, putlen); + retval = lo_write(conn, estmt->lobj_fd, putbuf, putlen); mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", putlen, retval); - *current_param->EXEC_used += putlen; + *current_pdata->EXEC_used += putlen; } else { - buffer = current_param->EXEC_buffer; - old_pos = *current_param->EXEC_used; + buffer = current_pdata->EXEC_buffer; + old_pos = *current_pdata->EXEC_used; if (putlen > 0) { - *current_param->EXEC_used += putlen; + *current_pdata->EXEC_used += putlen; - mylog(" cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, *current_param->EXEC_used); + mylog(" cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, *current_pdata->EXEC_used); /* dont lose the old pointer in case out of memory */ - buffer = realloc(current_param->EXEC_buffer, *current_param->EXEC_used + 1); + buffer = realloc(current_pdata->EXEC_buffer, *current_pdata->EXEC_used + 1); if (!buffer) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)"); @@ -1102,10 +1122,10 @@ PGAPI_PutData( } memcpy(&buffer[old_pos], putbuf, putlen); - buffer[*current_param->EXEC_used] = '\0'; + buffer[*current_pdata->EXEC_used] = '\0'; /* reassign buffer incase realloc moved it */ - current_param->EXEC_buffer = buffer; + current_pdata->EXEC_buffer = buffer; } else { diff --git a/info.c b/info.c index d10baed..2164ad0 100644 --- a/info.c +++ b/info.c @@ -819,7 +819,7 @@ PGAPI_GetTypeInfo( #else result_cols = 15; #endif /* ODBCVER */ - extend_column_bindings(SC_get_ARD(stmt), result_cols); + extend_column_bindings(SC_get_ARDF(stmt), result_cols); QR_set_num_fields(res, result_cols); QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING); @@ -1110,12 +1110,14 @@ PGAPI_GetFunctions( case SQL_API_SQLSETCURSORNAME: *pfExists = TRUE; break; +#if (ODBCVER < 0x0300) case SQL_API_SQLSETPARAM: *pfExists = FALSE; break; /* odbc 1.0 */ case SQL_API_SQLTRANSACT: *pfExists = TRUE; break; +#endif /* ODBCVER */ /* ODBC level 1 functions */ case SQL_API_SQLBINDPARAMETER: @@ -1204,9 +1206,11 @@ PGAPI_GetFunctions( case SQL_API_SQLNUMPARAMS: *pfExists = TRUE; break; +#if (ODBCVER < 0x0300) case SQL_API_SQLPARAMOPTIONS: *pfExists = TRUE; break; +#endif /* ODBCVER */ case SQL_API_SQLPRIMARYKEYS: *pfExists = TRUE; break; @@ -1225,9 +1229,11 @@ PGAPI_GetFunctions( case SQL_API_SQLSETPOS: *pfExists = TRUE; break; +#if (ODBCVER < 0x0300) case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = TRUE; break; /* odbc 1.0 */ +#endif /* ODBCVER */ case SQL_API_SQLTABLEPRIVILEGES: *pfExists = TRUE; break; @@ -1460,7 +1466,7 @@ PGAPI_Tables( else strcat(tables_query, " and usesysid = relowner order by relname"); - result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); + result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, htbl_stmt); @@ -1517,7 +1523,7 @@ PGAPI_Tables( * a statement is actually executed, so we'll have to do this * ourselves. */ - extend_column_bindings(SC_get_ARD(stmt), 5); + extend_column_bindings(SC_get_ARDF(stmt), 5); /* set the field names */ QR_set_num_fields(res, 5); @@ -1734,8 +1740,6 @@ PGAPI_Columns( ConnectionClass *conn; SWORD internal_asis_type = SQL_C_CHAR; const char *likeeq = "like"; - const char *mzTableOwner = szTableOwner, *mzTableName = szTableName, - *mzColumnName = szColumnName; mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); @@ -1778,19 +1782,12 @@ PGAPI_Columns( if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) { - likeeq = "="; - } - else - { - } - if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) - { - my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, mzTableName, cbTableName); + my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); if (conn->schema_support) - schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, mzTableOwner, cbTableOwner, mzTableName, cbTableName, conn); + schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn); else - my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, mzTableOwner, cbTableOwner); - my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, mzColumnName, cbColumnName); + my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner); + my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName); } else { @@ -1798,13 +1795,12 @@ PGAPI_Columns( int escTbnamelen; escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc); - mzTableName = esc_table_name; - my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, mzTableName, escTbnamelen); + my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, esc_table_name, escTbnamelen); if (conn->schema_support) - schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, mzTableName, cbTableName, conn); + schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, szTableName, cbTableName, conn); else - my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, mzTableOwner, cbTableOwner); - my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, mzColumnName, cbColumnName); + my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, szTableOwner, cbTableOwner); + my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, szColumnName, cbColumnName); } /* @@ -1827,8 +1823,7 @@ PGAPI_Columns( mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt); - result = PGAPI_ExecDirect(hcol_stmt, columns_query, - strlen(columns_query)); + result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, col_stmt); @@ -1968,7 +1963,7 @@ PGAPI_Columns( reserved_cols = 12; #endif /* ODBCVER */ result_cols = reserved_cols + 2; - extend_column_bindings(SC_get_ARD(stmt), result_cols); + extend_column_bindings(SC_get_ARDF(stmt), result_cols); /* set the field names */ QR_set_num_fields(res, result_cols); @@ -2315,8 +2310,7 @@ PGAPI_SpecialColumns( mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt); - result = PGAPI_ExecDirect(hcol_stmt, columns_query, - strlen(columns_query)); + result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, col_stmt); @@ -2367,7 +2361,7 @@ PGAPI_SpecialColumns( res = QR_Constructor(); SC_set_Result(stmt, res); - extend_column_bindings(SC_get_ARD(stmt), 8); + extend_column_bindings(SC_get_ARDF(stmt), 8); QR_set_num_fields(res, 8); QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2); @@ -2533,7 +2527,7 @@ PGAPI_Statistics( * a statement is actually executed, so we'll have to do this * ourselves. */ - extend_column_bindings(SC_get_ARD(stmt), 13); + extend_column_bindings(SC_get_ARDF(stmt), 13); /* set the field names */ QR_set_num_fields(res, 13); @@ -2675,7 +2669,7 @@ PGAPI_Statistics( else strcat(index_query, " i.indisunique, c.relname"); - result = PGAPI_ExecDirect(hindx_stmt, index_query, strlen(index_query)); + result = PGAPI_ExecDirect(hindx_stmt, index_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { /* @@ -2982,7 +2976,7 @@ PGAPI_PrimaryKeys( * ourselves. */ result_cols = 6; - extend_column_bindings(SC_get_ARD(stmt), result_cols); + extend_column_bindings(SC_get_ARDF(stmt), result_cols); /* set the field names */ QR_set_num_fields(res, result_cols); @@ -3107,7 +3101,7 @@ PGAPI_PrimaryKeys( } mylog("%s: tables_query='%s'\n", func, tables_query); - result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); + result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, tbl_stmt); @@ -3494,7 +3488,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; #else result_cols = 14; #endif /* ODBCVER */ - extend_column_bindings(SC_get_ARD(stmt), result_cols); + extend_column_bindings(SC_get_ARDF(stmt), result_cols); /* set the field names */ QR_set_num_fields(res, result_cols); @@ -3639,7 +3633,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; "AND (pt.tgconstrrelid=pc1.oid)) ", fk_table_needed); - result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); + result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { @@ -4013,7 +4007,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; " )", pk_table_needed); - result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); + result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); @@ -4337,7 +4331,7 @@ PGAPI_ProcedureColumns( #else result_cols = 13; #endif /* ODBCVER */ - extend_column_bindings(SC_get_ARD(stmt), result_cols); + extend_column_bindings(SC_get_ARDF(stmt), result_cols); /* set the field names */ QR_set_num_fields(res, result_cols); @@ -4516,7 +4510,7 @@ PGAPI_Procedures( * results can be retrieved. */ stmt->status = STMT_FINISHED; - extend_column_bindings(SC_get_ARD(stmt), 8); + extend_column_bindings(SC_get_ARDF(stmt), 8); /* set up the current tuple pointer for SQLFetch */ stmt->currTuple = -1; stmt->rowset_start = -1; @@ -4605,7 +4599,7 @@ PGAPI_TablePrivileges( * ourselves. */ result_cols = 7; - extend_column_bindings(SC_get_ARD(stmt), result_cols); + extend_column_bindings(SC_get_ARDF(stmt), result_cols); /* set the field names */ stmt->manual_result = TRUE; diff --git a/misc.c b/misc.c index c9a6541..bd835a2 100644 --- a/misc.c +++ b/misc.c @@ -110,12 +110,12 @@ logs_on_off(int cnopen, int mylog_onoff, int qlog_onoff) } #ifdef MY_LOG +static FILE *LOGFP = NULL; void mylog(char *fmt,...) { va_list args; char filebuf[80]; - static FILE *LOGFP = NULL; ENTER_MYLOG_CS; if (mylog_on) diff --git a/multibyte.c b/multibyte.c index c4ac9e8..8b2c4f2 100644 --- a/multibyte.c +++ b/multibyte.c @@ -348,7 +348,7 @@ CC_lookup_cs_old(ConnectionClass *self) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) return encstr; - result = PGAPI_ExecDirect(hstmt, "Show Client_Encoding", SQL_NTS); + result = PGAPI_ExecDirect(hstmt, "Show Client_Encoding", SQL_NTS, 0); if (result == SQL_SUCCESS_WITH_INFO) { char sqlState[8], errormsg[128], enc[32]; diff --git a/odbcapi.c b/odbcapi.c index 1cbea25..2d1d75a 100644 --- a/odbcapi.c +++ b/odbcapi.c @@ -312,7 +312,7 @@ SQLExecDirect(HSTMT StatementHandle, mylog("[SQLExecDirect]"); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength); + ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, 0); LEAVE_STMT_CS(stmt); return ret; } @@ -326,7 +326,7 @@ SQLExecute(HSTMT StatementHandle) mylog("[SQLExecute]"); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_Execute(StatementHandle); + ret = PGAPI_Execute(StatementHandle, 0); LEAVE_STMT_CS(stmt); return ret; } @@ -343,8 +343,8 @@ SQLFetch(HSTMT StatementHandle) #if (ODBCVER >= 0x0300) if (SC_get_conn(stmt)->driver_version >= 0x0300) { - IRDFields *irdopts = SC_get_IRD(stmt); - ARDFields *ardopts = SC_get_ARD(stmt); + IRDFields *irdopts = SC_get_IRDF(stmt); + ARDFields *ardopts = SC_get_ARDF(stmt); SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray; SQLINTEGER *pcRow = irdopts->rowsFetched; @@ -997,7 +997,7 @@ SQLExtendedFetch( mylog("[SQLExtendedFetch]"); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0, SC_get_ARD(stmt)->size_of_rowset_odbc2); + ret = PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0, SC_get_ARDF(stmt)->size_of_rowset_odbc2); stmt->transition_status = 7; LEAVE_STMT_CS(stmt); return ret; diff --git a/odbcapi30.c b/odbcapi30.c index 2d438ee..9f98bae 100644 --- a/odbcapi30.c +++ b/odbcapi30.c @@ -56,9 +56,9 @@ SQLAllocHandle(SQLSMALLINT HandleType, case SQL_HANDLE_DESC: conn = (ConnectionClass *) InputHandle; ENTER_CONN_CS(conn); - CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "can't alloc Desc Handle yet"); + ret = PGAPI_AllocDesc(InputHandle, OutputHandle); LEAVE_CONN_CS(conn); - ret = SQL_ERROR; + mylog("Descriptor OutputHandle=%x\n", *OutputHandle); break; default: ret = SQL_ERROR; @@ -119,48 +119,17 @@ SQLColAttribute(HSTMT StatementHandle, return ret; } -static HSTMT -descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) -{ - switch (descType) - { - case SQL_ATTR_APP_ROW_DESC: /* 10010 */ - return StatementHandle; /* this is bogus */ - case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ - return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */ - case SQL_ATTR_IMP_ROW_DESC: /* 10012 */ - return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */ - case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */ - return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */ - } - return (HSTMT) 0; -} -static HSTMT -statementHandleFromDescHandle(HSTMT DescHandle, SQLINTEGER *descType) -{ - SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4; - switch (res) - { - case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */ - break; - case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */ - break; - case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */ - break; - case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */ - break; - } - return (HSTMT) ((SQLUINTEGER) DescHandle - res); -} - /* new function */ RETCODE SQL_API SQLCopyDesc(SQLHDESC SourceDescHandle, SQLHDESC TargetDescHandle) { + RETCODE ret; + mylog("[[SQLCopyDesc]]\n"); - mylog("Error not implemented\n"); - return SQL_ERROR; + DC_clear_error((DescriptorClass *) TargetDescHandle); + ret = PGAPI_CopyDesc(SourceDescHandle, TargetDescHandle); + return ret; } /* SQLTransact -> SQLEndTran */ @@ -199,7 +168,7 @@ SQLFetchScroll(HSTMT StatementHandle, CSTR func = "SQLFetchScroll"; StatementClass *stmt = (StatementClass *) StatementHandle; RETCODE ret = SQL_SUCCESS; - IRDFields *irdopts = SC_get_IRD(stmt); + IRDFields *irdopts = SC_get_IRDF(stmt); SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray; SQLINTEGER *pcRow = irdopts->rowsFetched, bkmarkoff = 0; @@ -223,7 +192,7 @@ mylog("bookmark=%u FetchOffset = %d\n", FetchOffset, bkmarkoff); } if (SQL_SUCCESS == ret) { - ARDFields *opts = SC_get_ARD(stmt); + ARDFields *opts = SC_get_ARDF(stmt); ret = PGAPI_ExtendedFetch(StatementHandle, FetchOrientation, FetchOffset, pcRow, rowStatusArray, bkmarkoff, opts->size_of_rowset); @@ -252,6 +221,9 @@ SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) case SQL_HANDLE_STMT: ret = PGAPI_FreeStmt(Handle, SQL_DROP); break; + case SQL_HANDLE_DESC: + ret = PGAPI_FreeDesc(Handle); + break; default: ret = SQL_ERROR; break; @@ -269,6 +241,7 @@ SQLGetDescField(SQLHDESC DescriptorHandle, RETCODE ret; mylog("[[SQLGetDescField]]\n"); + DC_clear_error((DescriptorClass *) DescriptorHandle); ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); return ret; @@ -285,6 +258,7 @@ SQLGetDescRec(SQLHDESC DescriptorHandle, { mylog("[[SQLGetDescRec]]\n"); mylog("Error not implemented\n"); + DC_clear_error((DescriptorClass *) DescriptorHandle); return SQL_ERROR; } @@ -414,6 +388,7 @@ SQLSetDescField(SQLHDESC DescriptorHandle, RETCODE ret; mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value); + DC_clear_error((DescriptorClass *) DescriptorHandle); ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength); return ret; @@ -432,6 +407,7 @@ SQLSetDescRec(SQLHDESC DescriptorHandle, mylog("[[SQLSetDescRec]]\n"); mylog("Error not implemented\n"); + DC_clear_error((DescriptorClass *) DescriptorHandle); return SQL_ERROR; } @@ -579,7 +555,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) SQL_FUNC_ESET(pfExists, SQL_API_SQLSTATISTICS); /* 53 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */ if (ci->drivers.lie) - SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 not implemented yet */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 not implmented yet */ if (ci->drivers.lie) SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */ SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES); /* 57 */ @@ -608,8 +584,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) SQL_FUNC_ESET(pfExists, SQL_API_SQLALLOCHANDLE); /* 1001 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDPARAM); /* 1002 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLCLOSECURSOR); /* 1003 */ - if (ci->drivers.lie) - SQL_FUNC_ESET(pfExists, SQL_API_SQLCOPYDESC); /* 1004 not implemented yet */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLCOPYDESC); /* 1004 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLENDTRAN); /* 1005 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLFREEHANDLE); /* 1006 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETCONNECTATTR); /* 1007 */ diff --git a/odbcapi30w.c b/odbcapi30w.c index 512e768..b82fcaf 100644 --- a/odbcapi30w.c +++ b/odbcapi30w.c @@ -174,7 +174,7 @@ SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField, if (SQL_SUCCESS == ret && blen * 2 > cbValueMax) { ret = SQL_SUCCESS_WITH_INFO; - Desc_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc."); + DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc."); } if (pcbValue) *pcbValue = blen * 2; diff --git a/odbcapiw.c b/odbcapiw.c index ba2123d..49859f8 100644 --- a/odbcapiw.c +++ b/odbcapiw.c @@ -216,7 +216,7 @@ RETCODE SQL_API SQLExecDirectW(HSTMT StatementHandle, mylog("[SQLExecDirectW]"); stxt = ucs2_to_utf8(StatementText, TextLength, &slen, FALSE); ENTER_STMT_CS((StatementClass *) StatementHandle); - ret = PGAPI_ExecDirect(StatementHandle, stxt, slen); + ret = PGAPI_ExecDirect(StatementHandle, stxt, slen, 0); LEAVE_STMT_CS((StatementClass *) StatementHandle); if (stxt) free(stxt); diff --git a/options.c b/options.c index b9fcc1b..0a8a4d9 100644 --- a/options.c +++ b/options.c @@ -55,7 +55,7 @@ set_statement_option(ConnectionClass *conn, if (conn) conn->ardOptions.bind_size = vParam; if (stmt) - SC_get_ARD(stmt)->bind_size = vParam; + SC_get_ARDF(stmt)->bind_size = vParam; break; case SQL_CONCURRENCY: @@ -215,7 +215,7 @@ set_statement_option(ConnectionClass *conn, */ if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0) - stmt->save_rowset_size = SC_get_ARD(stmt)->size_of_rowset_odbc2; + stmt->save_rowset_size = SC_get_ARDF(stmt)->size_of_rowset_odbc2; if (vParam < 1) { @@ -226,7 +226,7 @@ set_statement_option(ConnectionClass *conn, if (conn) conn->ardOptions.size_of_rowset_odbc2 = vParam; if (stmt) - SC_get_ARD(stmt)->size_of_rowset_odbc2 = vParam; + SC_get_ARDF(stmt)->size_of_rowset_odbc2 = vParam; break; case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */ @@ -699,7 +699,7 @@ PGAPI_GetStmtOption( break; case SQL_BIND_TYPE: - *((SDWORD *) pvParam) = SC_get_ARD(stmt)->bind_size; + *((SDWORD *) pvParam) = SC_get_ARDF(stmt)->bind_size; break; case SQL_CONCURRENCY: /* NOT REALLY SUPPORTED */ @@ -739,7 +739,7 @@ PGAPI_GetStmtOption( break; case SQL_ROWSET_SIZE: - *((SDWORD *) pvParam) = SC_get_ARD(stmt)->size_of_rowset_odbc2; + *((SDWORD *) pvParam) = SC_get_ARDF(stmt)->size_of_rowset_odbc2; break; case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */ diff --git a/parse.c b/parse.c index b418d6d..559043b 100644 --- a/parse.c +++ b/parse.c @@ -350,7 +350,7 @@ parse_statement(StatementClass *stmt) ConnectionClass *conn = stmt->hdbc; HSTMT hcol_stmt; StatementClass *col_stmt; - IRDFields *irdflds = SC_get_IRD(stmt); + IRDFields *irdflds = SC_get_IRDF(stmt); RETCODE result; BOOL updatable = TRUE; diff --git a/pgapi30.c b/pgapi30.c index 9eaa507..43e4e38 100644 --- a/pgapi30.c +++ b/pgapi30.c @@ -27,7 +27,6 @@ #include "qresult.h" #include "pgapifunc.h" -static HSTMT statementHandleFromDescHandle(SQLHDESC, SQLINTEGER *descType); /* SQLError -> SQLDiagRec */ RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, @@ -57,8 +56,8 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, TextLength, 0); break; case SQL_HANDLE_DESC: - ret = PGAPI_StmtError(statementHandleFromDescHandle(Handle, NULL), - RecNumber, Sqlstate, NativeError, + ret = PGAPI_DescError(Handle, RecNumber, Sqlstate, + NativeError, MessageText, BufferLength, TextLength, 0); break; @@ -81,7 +80,6 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, { RETCODE ret = SQL_ERROR, rtn; ConnectionClass *conn; - SQLHANDLE stmtHandle; StatementClass *stmt; SDWORD rc; SWORD pcbErrm; @@ -295,13 +293,13 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, *StringLengthPtr = sizeof(SQLINTEGER); ret = SQL_SUCCESS; break; - case SQL_DIAG_ROW_NUMBER: + case SQL_DIAG_ROW_NUMBER: *((SQLINTEGER *) DiagInfoPtr) = SQL_ROW_NUMBER_UNKNOWN; if (StringLengthPtr) *StringLengthPtr = sizeof(SQLINTEGER); ret = SQL_SUCCESS; break; - case SQL_DIAG_COLUMN_NUMBER: + case SQL_DIAG_COLUMN_NUMBER: *((SQLINTEGER *) DiagInfoPtr) = SQL_COLUMN_NUMBER_UNKNOWN; if (StringLengthPtr) *StringLengthPtr = sizeof(SQLINTEGER); @@ -312,8 +310,7 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, } break; case SQL_HANDLE_DESC: - stmtHandle = statementHandleFromDescHandle(Handle, NULL); - conn = (ConnectionClass *) SC_get_conn(((StatementClass *) stmtHandle)); + conn = DC_get_conn(((DescriptorClass *) Handle)); switch (DiagIdentifier) { case SQL_DIAG_CLASS_ORIGIN: @@ -334,10 +331,13 @@ PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, case SQL_DIAG_NATIVE: case SQL_DIAG_NUMBER: case SQL_DIAG_SQLSTATE: - ret = PGAPI_GetDiagField(SQL_HANDLE_STMT, - stmtHandle, RecNumber, - DiagIdentifier, DiagInfoPtr, - BufferLength, StringLengthPtr); + ret = PGAPI_DescError(Handle, RecNumber, + DiagInfoPtr, NULL, NULL, + 0, NULL, 0); + if (StringLengthPtr) + *StringLengthPtr = 5; + if (SQL_SUCCESS_WITH_INFO == ret) + ret = SQL_SUCCESS; break; case SQL_DIAG_RETURNCODE: /* driver manager returns */ break; @@ -396,51 +396,21 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle, static SQLHDESC descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType) { + StatementClass *stmt = (StatementClass *) StatementHandle; + switch (descType) { case SQL_ATTR_APP_ROW_DESC: /* 10010 */ - return StatementHandle; /* this is bogus */ - case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ - return (HSTMT) ((SQLUINTEGER) StatementHandle + 1) ; /* this is bogus */ + return (HSTMT) stmt->ard; + case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ + return (HSTMT) stmt->apd; case SQL_ATTR_IMP_ROW_DESC: /* 10012 */ - return (HSTMT) ((SQLUINTEGER) StatementHandle + 2); /* this is bogus */ - case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */ - return (HSTMT) ((SQLUINTEGER) StatementHandle + 3); /* this is bogus */ + return (HSTMT) stmt->ird; + case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */ + return (HSTMT) stmt->ipd; } return (HSTMT) 0; } -static HSTMT -statementHandleFromDescHandle(SQLHDESC DescHandle, SQLINTEGER *descType) -{ - SQLUINTEGER res = (SQLUINTEGER) DescHandle % 4; - if (descType) - { - switch (res) - { - case 0: *descType = SQL_ATTR_APP_ROW_DESC; /* 10010 */ - break; - case 1: *descType = SQL_ATTR_APP_PARAM_DESC; /* 10011 */ - break; - case 2: *descType = SQL_ATTR_IMP_ROW_DESC; /* 10012 */ - break; - case 3: *descType = SQL_ATTR_IMP_PARAM_DESC; /* 10013 */ - break; - } - } - return (HSTMT) ((SQLUINTEGER) DescHandle - res); -} - -void Desc_set_error(SQLHDESC hdesc, int errornumber, const char *errormsg) -{ - SQLINTEGER descType; - HSTMT hstmt = statementHandleFromDescHandle(hdesc, &descType); - StatementClass *stmt; - - if (!hstmt) - return; - stmt = (StatementClass *) hstmt; - SC_set_error(stmt, errornumber, errormsg); -} static void column_bindings_set(ARDFields *opts, int cols, BOOL maxset) { @@ -466,12 +436,12 @@ static void column_bindings_set(ARDFields *opts, int cols, BOOL maxset) } static RETCODE SQL_API -ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, +ARDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { RETCODE ret = SQL_SUCCESS; PTR tptr; - ARDFields *opts = SC_get_ARD(stmt); + ARDFields *opts = (ARDFields *) (desc + 1); SQLSMALLINT row_idx; switch (FieldIdentifier) @@ -500,29 +470,31 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, } if (RecNumber < 0 || RecNumber > opts->allocated) { - SC_set_errornumber(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR); + DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number"); return SQL_ERROR; } if (0 == RecNumber) /* bookmark column */ { + BindInfoClass *bookmark = ARD_AllocBookmark(opts); + switch (FieldIdentifier) { case SQL_DESC_DATA_PTR: - opts->bookmark->buffer = Value; + bookmark->buffer = Value; break; case SQL_DESC_INDICATOR_PTR: - tptr = opts->bookmark->used; + tptr = bookmark->used; if (Value != tptr) { - SC_set_error(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); ret = SQL_ERROR; } break; case SQL_DESC_OCTET_LENGTH_PTR: - opts->bookmark->used = Value; + bookmark->used = Value; break; default: - SC_set_errornumber(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR); + DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number"); ret = SQL_ERROR; } return ret; @@ -567,7 +539,7 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, if (Value != tptr) { ret = SQL_ERROR; - SC_set_error(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); } break; case SQL_DESC_OCTET_LENGTH_PTR: @@ -587,7 +559,8 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_LENGTH: case SQL_DESC_NUM_PREC_RADIX: default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } return ret; } @@ -639,11 +612,11 @@ static void parameter_ibindings_set(IPDFields *opts, int params, BOOL maxset) } static RETCODE SQL_API -APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, +APDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { RETCODE ret = SQL_SUCCESS; - APDFields *opts = SC_get_APD(stmt); + APDFields *opts = (APDFields *) (desc + 1); SQLSMALLINT para_idx; switch (FieldIdentifier) @@ -672,7 +645,8 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, } if (RecNumber <=0 || RecNumber > opts->allocated) { - SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR); + DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR, + "bad parameter number"); return SQL_ERROR; } para_idx = RecNumber - 1; @@ -714,7 +688,7 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, if (Value != opts->parameters[para_idx].used) { ret = SQL_ERROR; - SC_set_error(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR"); } break; case SQL_DESC_OCTET_LENGTH: @@ -734,17 +708,18 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_LENGTH: case SQL_DESC_NUM_PREC_RADIX: default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invaid descriptor identifier"); } return ret; } static RETCODE SQL_API -IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, +IRDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { RETCODE ret = SQL_SUCCESS; - IRDFields *opts = SC_get_IRD(stmt); + IRDFields *opts = (IRDFields *) (desc + 1); switch (FieldIdentifier) { @@ -789,17 +764,18 @@ IRDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_UNSIGNED: /* read-only */ case SQL_DESC_UPDATABLE: /* read-only */ default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } return ret; } static RETCODE SQL_API -IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, +IPDSetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { RETCODE ret = SQL_SUCCESS; - IPDFields *ipdopts = SC_get_IPD(stmt); + IPDFields *ipdopts = (IPDFields *) (desc + 1); SQLSMALLINT para_idx; switch (FieldIdentifier) @@ -814,7 +790,8 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, if (SQL_UNNAMED != (SQLUINTEGER) Value) { ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } return ret; case SQL_DESC_COUNT: @@ -828,7 +805,8 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, } if (RecNumber <= 0 || RecNumber > ipdopts->allocated) { - SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR); + DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR, + "bad parameter number"); return SQL_ERROR; } para_idx = RecNumber - 1; @@ -886,39 +864,41 @@ IPDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_TYPE_NAME: /* read-only */ case SQL_DESC_UNSIGNED: /* read-only */ default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } return ret; } static RETCODE SQL_API -ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, +ARDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength) { RETCODE ret = SQL_SUCCESS; SQLINTEGER len, ival, rettype = 0; PTR ptr = NULL; - const ARDFields *opts = SC_get_ARD(stmt); + const ARDFields *opts = (ARDFields *) (desc + 1); SQLSMALLINT row_idx; len = 4; if (0 == RecNumber) /* bookmark */ { + BindInfoClass *bookmark = opts->bookmark; switch (FieldIdentifier) { case SQL_DESC_DATA_PTR: rettype = SQL_IS_POINTER; - ptr = opts->bookmark->buffer; + ptr = bookmark ? bookmark->buffer : NULL; break; case SQL_DESC_INDICATOR_PTR: rettype = SQL_IS_POINTER; - ptr = opts->bookmark->used; + ptr = bookmark ? bookmark->used : NULL; break; case SQL_DESC_OCTET_LENGTH_PTR: rettype = SQL_IS_POINTER; - ptr = opts->bookmark->used; + ptr = bookmark ? bookmark->used : NULL; break; } if (ptr) @@ -940,7 +920,8 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, default: if (RecNumber <= 0 || RecNumber > opts->allocated) { - SC_set_errornumber(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR); + DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, + "invalid column number"); return SQL_ERROR; } } @@ -1012,7 +993,10 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ival = opts->bindings[row_idx].buflen; break; case SQL_DESC_ALLOC_TYPE: /* read-only */ - ival = SQL_DESC_ALLOC_AUTO; + if (desc->embedded) + ival = SQL_DESC_ALLOC_AUTO; + else + ival = SQL_DESC_ALLOC_USER; break; case SQL_DESC_PRECISION: ival = opts->bindings[row_idx].precision; @@ -1026,7 +1010,8 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_DATETIME_INTERVAL_PRECISION: case SQL_DESC_LENGTH: default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } switch (rettype) { @@ -1047,14 +1032,14 @@ ARDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, } static RETCODE SQL_API -APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, +APDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength) { RETCODE ret = SQL_SUCCESS; SQLINTEGER ival = 0, len, rettype = 0; PTR ptr = NULL; - const APDFields *opts = SC_get_APD(stmt); + const APDFields *opts = (const APDFields *) (desc + 1); SQLSMALLINT para_idx; len = 4; @@ -1068,7 +1053,8 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, break; default:if (RecNumber <= 0 || RecNumber > opts->allocated) { - SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR); + DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR, + "bad parameter number"); return SQL_ERROR; } } @@ -1142,7 +1128,10 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, ival = opts->allocated; break; case SQL_DESC_ALLOC_TYPE: /* read-only */ - ival = SQL_DESC_ALLOC_AUTO; + if (desc->embedded) + ival = SQL_DESC_ALLOC_AUTO; + else + ival = SQL_DESC_ALLOC_USER; break; case SQL_DESC_NUM_PREC_RADIX: ival = 10; @@ -1156,7 +1145,8 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_DATETIME_INTERVAL_PRECISION: case SQL_DESC_LENGTH: default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifer"); } switch (rettype) { @@ -1177,7 +1167,7 @@ APDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, } static RETCODE SQL_API -IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, +IRDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength) { @@ -1185,7 +1175,7 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, SQLINTEGER ival = 0, len, rettype = 0; PTR ptr = NULL; BOOL bCallColAtt = FALSE; - const IRDFields *opts = SC_get_IRD(stmt); + const IRDFields *opts = (IRDFields *) (desc + 1); switch (FieldIdentifier) { @@ -1239,12 +1229,15 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, bCallColAtt = TRUE; break; default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } if (bCallColAtt) { SQLSMALLINT pcbL; + StatementClass *stmt; + stmt = opts->stmt; ret = PGAPI_ColAttributes(stmt, RecNumber, FieldIdentifier, Value, (SQLSMALLINT) BufferLength, &pcbL, &ival); @@ -1273,14 +1266,14 @@ IRDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, } static RETCODE SQL_API -IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, +IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength) { RETCODE ret = SQL_SUCCESS; SQLINTEGER ival = 0, len, rettype = 0; PTR ptr = NULL; - const IPDFields *ipdopts = SC_get_IPD(stmt); + const IPDFields *ipdopts = (const IPDFields *) (desc + 1); SQLSMALLINT para_idx; switch (FieldIdentifier) @@ -1291,7 +1284,8 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, break; default:if (RecNumber <= 0 || RecNumber > ipdopts->allocated) { - SC_set_errornumber(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR); + DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR, + "bad parameter number"); return SQL_ERROR; } } @@ -1382,7 +1376,8 @@ IPDGetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_TYPE_NAME: /* read-only */ case SQL_DESC_UNSIGNED: /* read-only */ default:ret = SQL_ERROR; - SC_set_errornumber(stmt, STMT_INVALID_DESCRIPTOR_IDENTIFIER); + DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, + "invalid descriptor identifier"); } switch (rettype) { @@ -1421,47 +1416,47 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle, len = 4; break; case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */ - *((SQLUINTEGER **) Value) = SC_get_APD(stmt)->param_offset_ptr; + *((SQLUINTEGER **) Value) = SC_get_APDF(stmt)->param_offset_ptr; len = 4; break; case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */ - *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->param_bind_type; + *((SQLUINTEGER *) Value) = SC_get_APDF(stmt)->param_bind_type; len = 4; break; case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */ - *((SQLUSMALLINT **) Value) = SC_get_APD(stmt)->param_operation_ptr; + *((SQLUSMALLINT **) Value) = SC_get_APDF(stmt)->param_operation_ptr; len = 4; break; case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */ - *((SQLUSMALLINT **) Value) = SC_get_IPD(stmt)->param_status_ptr; + *((SQLUSMALLINT **) Value) = SC_get_IPDF(stmt)->param_status_ptr; len = 4; break; case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */ - *((SQLUINTEGER **) Value) = SC_get_IPD(stmt)->param_processed_ptr; + *((SQLUINTEGER **) Value) = SC_get_IPDF(stmt)->param_processed_ptr; len = 4; break; case SQL_ATTR_PARAMSET_SIZE: /* 22 */ - *((SQLUINTEGER *) Value) = SC_get_APD(stmt)->paramset_size; + *((SQLUINTEGER *) Value) = SC_get_APDF(stmt)->paramset_size; len = 4; break; case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */ - *((SQLUINTEGER **) Value) = SC_get_ARD(stmt)->row_offset_ptr; + *((SQLUINTEGER **) Value) = SC_get_ARDF(stmt)->row_offset_ptr; len = 4; break; case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */ - *((SQLUSMALLINT **) Value) = SC_get_ARD(stmt)->row_operation_ptr; + *((SQLUSMALLINT **) Value) = SC_get_ARDF(stmt)->row_operation_ptr; len = 4; break; case SQL_ATTR_ROW_STATUS_PTR: /* 25 */ - *((SQLUSMALLINT **) Value) = SC_get_IRD(stmt)->rowStatusArray; + *((SQLUSMALLINT **) Value) = SC_get_IRDF(stmt)->rowStatusArray; len = 4; break; case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */ - *((SQLUINTEGER **) Value) = SC_get_IRD(stmt)->rowsFetched; + *((SQLUINTEGER **) Value) = SC_get_IRDF(stmt)->rowsFetched; len = 4; break; case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */ - *((SQLUINTEGER *) Value) = SC_get_ARD(stmt)->size_of_rowset; + *((SQLUINTEGER *) Value) = SC_get_ARDF(stmt)->size_of_rowset; len = 4; break; case SQL_ATTR_APP_ROW_DESC: /* 10010 */ @@ -1539,51 +1534,46 @@ PGAPI_GetDescField(SQLHDESC DescriptorHandle, PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength) { - RETCODE ret = SQL_SUCCESS; - HSTMT hstmt; - SQLUINTEGER descType; - StatementClass *stmt; CSTR func = "PGAPI_GetDescField"; + RETCODE ret = SQL_SUCCESS; + DescriptorClass *desc = (DescriptorClass *) DescriptorHandle; mylog("%s h=%u rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength); - hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType); - mylog("stmt=%x type=%d\n", hstmt, descType); - stmt = (StatementClass *) hstmt; - switch (descType) + switch (desc->desc_type) { case SQL_ATTR_APP_ROW_DESC: - ret = ARDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); + ret = ARDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; case SQL_ATTR_APP_PARAM_DESC: - ret = APDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); + ret = APDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; case SQL_ATTR_IMP_ROW_DESC: - ret = IRDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); + ret = IRDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; case SQL_ATTR_IMP_PARAM_DESC: - ret = IPDGetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); + ret = IPDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; default:ret = SQL_ERROR; - SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error not implemented"); + DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented"); } if (ret == SQL_ERROR) { - if (!SC_get_errormsg(stmt)) + if (!DC_get_errormsg(desc)) { - switch (SC_get_errornumber(stmt)) + switch (DC_get_errornumber(desc)) { case STMT_INVALID_DESCRIPTOR_IDENTIFIER: - SC_set_errormsg(stmt, "can't SQLGetDescField for this descriptor identifier"); + DC_set_errormsg(desc, "can't SQLGetDescField for this descriptor identifier"); break; case STMT_INVALID_COLUMN_NUMBER_ERROR: - SC_set_errormsg(stmt, "can't SQLGetDescField for this column number"); + DC_set_errormsg(desc, "can't SQLGetDescField for this column number"); break; case STMT_BAD_PARAMETER_NUMBER_ERROR: - SC_set_errormsg(stmt, "can't SQLGetDescField for this parameter number"); + DC_set_errormsg(desc, "can't SQLGetDescField for this parameter number"); break; } } - SC_log_error(func, "", stmt); + DC_log_error(func, "", desc); } return ret; } @@ -1594,51 +1584,46 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { - RETCODE ret = SQL_SUCCESS; - HSTMT hstmt; - SQLUINTEGER descType; - StatementClass *stmt; CSTR func = "PGAPI_SetDescField"; + RETCODE ret = SQL_SUCCESS; + DescriptorClass *desc = (DescriptorClass *) DescriptorHandle; mylog("%s h=%u rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength); - hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType); - mylog("stmt=%x type=%d\n", hstmt, descType); - stmt = (StatementClass *) hstmt; - switch (descType) + switch (desc->desc_type) { case SQL_ATTR_APP_ROW_DESC: - ret = ARDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength); + ret = ARDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; case SQL_ATTR_APP_PARAM_DESC: - ret = APDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength); + ret = APDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; case SQL_ATTR_IMP_ROW_DESC: - ret = IRDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength); + ret = IRDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; case SQL_ATTR_IMP_PARAM_DESC: - ret = IPDSetField(stmt, RecNumber, FieldIdentifier, Value, BufferLength); + ret = IPDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; default:ret = SQL_ERROR; - SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error not implemented"); + DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented"); } if (ret == SQL_ERROR) { - if (!SC_get_errormsg(stmt)) + if (!DC_get_errormsg(desc)) { - switch (SC_get_errornumber(stmt)) + switch (DC_get_errornumber(desc)) { case STMT_INVALID_DESCRIPTOR_IDENTIFIER: - SC_set_errormsg(stmt, "can't SQLSetDescField for this descriptor identifier"); + DC_set_errormsg(desc, "can't SQLSetDescField for this descriptor identifier"); case STMT_INVALID_COLUMN_NUMBER_ERROR: - SC_set_errormsg(stmt, "can't SQLSetDescField for this column number"); + DC_set_errormsg(desc, "can't SQLSetDescField for this column number"); break; case STMT_BAD_PARAMETER_NUMBER_ERROR: - SC_set_errormsg(stmt, "can't SQLSetDescField for this parameter number"); + DC_set_errormsg(desc, "can't SQLSetDescField for this parameter number"); break; break; } } - SC_log_error(func, "", stmt); + DC_log_error(func, "", desc); } return ret; } @@ -1649,6 +1634,7 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, SQLINTEGER Attribute, PTR Value, SQLINTEGER StringLength) { + RETCODE ret = SQL_SUCCESS; CSTR func = "PGAPI_SetStmtAttr"; StatementClass *stmt = (StatementClass *) StatementHandle; @@ -1660,8 +1646,6 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */ - case SQL_ATTR_APP_ROW_DESC: /* 10010 */ - case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ case SQL_ATTR_AUTO_IPD: /* 10001 */ /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */ case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */ @@ -1676,43 +1660,63 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, return SQL_ERROR; case SQL_ATTR_METADATA_ID: /* 10014 */ - stmt->options.metadata_id = (SQLUINTEGER) Value; + stmt->options.metadata_id = (SQLUINTEGER) Value; + break; + case SQL_ATTR_APP_ROW_DESC: /* 10010 */ + if (SQL_NULL_HDESC == Value) + { + stmt->ard = &(stmt->ardi); + } + else + { + stmt->ard = (ARDClass *) Value; + } + break; + case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ + if (SQL_NULL_HDESC == Value) + { + stmt->apd = &(stmt->apdi); + } + else + { + stmt->apd = (APDClass *) Value; + } break; case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */ stmt->options.bookmark_ptr = Value; break; case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */ - SC_get_APD(stmt)->param_offset_ptr = (SQLUINTEGER *) Value; + SC_get_APDF(stmt)->param_offset_ptr = (SQLUINTEGER *) Value; break; case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */ - SC_get_APD(stmt)->param_bind_type = (SQLUINTEGER) Value; + SC_get_APDF(stmt)->param_bind_type = (SQLUINTEGER) Value; break; case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */ - SC_get_APD(stmt)->param_operation_ptr = Value; + SC_get_APDF(stmt)->param_operation_ptr = Value; break; case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */ - SC_get_IPD(stmt)->param_status_ptr = (SQLUSMALLINT *) Value; + SC_get_IPDF(stmt)->param_status_ptr = (SQLUSMALLINT *) Value; break; case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */ - SC_get_IPD(stmt)->param_processed_ptr = (SQLUINTEGER *) Value; + SC_get_IPDF(stmt)->param_processed_ptr = (SQLUINTEGER *) Value; break; case SQL_ATTR_PARAMSET_SIZE: /* 22 */ - SC_get_APD(stmt)->paramset_size = (SQLUINTEGER) Value; + SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) Value; break; case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */ - SC_get_ARD(stmt)->row_offset_ptr = (SQLUINTEGER *) Value; + SC_get_ARDF(stmt)->row_offset_ptr = (SQLUINTEGER *) Value; break; case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */ - SC_get_ARD(stmt)->row_operation_ptr = Value; + SC_get_ARDF(stmt)->row_operation_ptr = Value; break; case SQL_ATTR_ROW_STATUS_PTR: /* 25 */ - SC_get_IRD(stmt)->rowStatusArray = (SQLUSMALLINT *) Value; + SC_get_IRDF(stmt)->rowStatusArray = (SQLUSMALLINT *) Value; break; case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */ - SC_get_IRD(stmt)->rowsFetched = (SQLUINTEGER *) Value; + SC_get_IRDF(stmt)->rowsFetched = (SQLUINTEGER *) Value; break; case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */ - SC_get_ARD(stmt)->size_of_rowset = (SQLUINTEGER) Value; + SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) Value; break; default: return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value); @@ -1725,73 +1729,119 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, (book->buffer + offset + \ (bind_size > 0 ? bind_size : (SQL_C_VARBOOKMARK == book->returntype ? book->buflen : sizeof(UInt4))) * index) -RETCODE SQL_API -PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operation) +/* SQL_NEED_DATA callback for PGAPI_BulkOperations */ +typedef struct { - CSTR func = "PGAPI_BulkOperations"; - StatementClass *stmt = (StatementClass *) hstmt; - ARDFields *opts = SC_get_ARD(stmt); - RETCODE ret; - UInt4 offset, bind_size = opts->bind_size, - global_idx; - int i, processed; + StatementClass *stmt; + SQLSMALLINT operation; + char need_data_callback; + char auto_commit_needed; + ARDFields *opts; + int idx, processed; +} bop_cdata; + +static +RETCODE bulk_ope_callback(RETCODE retcode, bop_cdata *s) +{ + RETCODE ret = retcode; + UInt4 offset, bind_size, global_idx; ConnectionClass *conn; - BOOL auto_commit_needed = FALSE; QResultClass *res; + IRDFields *irdflds; BindInfoClass *bookmark; - mylog("%s operation = %d\n", func, operation); - SC_clear_error(stmt); - offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; - - if (SQL_FETCH_BY_BOOKMARK != operation) + if (s->need_data_callback) { - conn = SC_get_conn(stmt); - if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed) - PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + mylog("bulk_ope_callback in\n"); + s->processed++; + s->idx++; } - if (SQL_ADD != operation) + else { - if (!(bookmark = opts->bookmark) || !(bookmark->buffer)) - { - SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified"); - return SQL_ERROR; - } + s->idx = s->processed = 0; } - for (i = 0, processed = 0; i < opts->size_of_rowset; i++) + s->need_data_callback = FALSE; + bookmark = s->opts->bookmark; + offset = s->opts->row_offset_ptr ? *(s->opts->row_offset_ptr) : 0; + bind_size = s->opts->bind_size; + for (; SQL_ERROR != ret && s->idx < s->opts->size_of_rowset; s->idx++) { - if (SQL_ADD != operation) + if (SQL_ADD != s->operation) { - memcpy(&global_idx, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, i), sizeof(UInt4)); + memcpy(&global_idx, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, s->idx), sizeof(UInt4)); global_idx--; } /* Note opts->row_operation_ptr is ignored */ - switch (operation) + switch (s->operation) { case SQL_ADD: - ret = SC_pos_add(stmt, (UWORD) i); + ret = SC_pos_add(s->stmt, (UWORD) s->idx); break; case SQL_UPDATE_BY_BOOKMARK: - ret = SC_pos_update(stmt, (UWORD) i, global_idx); + ret = SC_pos_update(s->stmt, (UWORD) s->idx, global_idx); break; case SQL_DELETE_BY_BOOKMARK: - ret = SC_pos_delete(stmt, (UWORD) i, global_idx); + ret = SC_pos_delete(s->stmt, (UWORD) s->idx, global_idx); break; case SQL_FETCH_BY_BOOKMARK: - ret = SC_pos_refresh(stmt, (UWORD) i, global_idx); + ret = SC_pos_refresh(s->stmt, (UWORD) s->idx, global_idx); break; } - processed++; - if (SQL_ERROR == ret) - break; + if (SQL_NEED_DATA == ret) + { + bop_cdata *cbdata = (bop_cdata *) malloc(sizeof(bop_cdata)); + memcpy(cbdata, s, sizeof(bop_cdata)); + cbdata->need_data_callback = TRUE; + enqueueNeedDataCallback(s->stmt, bulk_ope_callback, cbdata); + return ret; + } + s->processed++; } - if (auto_commit_needed) + conn = SC_get_conn(s->stmt); + if (s->auto_commit_needed) PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); - if (SC_get_IRD(stmt)->rowsFetched) - *(SC_get_IRD(stmt)->rowsFetched) = processed; + irdflds = SC_get_IRDF(s->stmt); + if (irdflds->rowsFetched) + *(irdflds->rowsFetched) = s->processed; + + if (res = SC_get_Curres(s->stmt), res) + res->recent_processed_row_count = s->stmt->diag_row_count = s->processed; + return ret; +} + +RETCODE SQL_API +PGAPI_BulkOperations(HSTMT hstmt, SQLSMALLINT operationX) +{ + CSTR func = "PGAPI_BulkOperations"; + bop_cdata s; + RETCODE ret; + ConnectionClass *conn; + BindInfoClass *bookmark; + + mylog("%s operation = %d\n", func, operationX); + s.stmt = (StatementClass *) hstmt; + s.operation = operationX; + SC_clear_error(s.stmt); + s.opts = SC_get_ARDF(s.stmt); + + s.auto_commit_needed = FALSE; + if (SQL_FETCH_BY_BOOKMARK != s.operation) + { + conn = SC_get_conn(s.stmt); + if (s.auto_commit_needed = (char) CC_is_in_autocommit(conn), s.auto_commit_needed) + PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + } + if (SQL_ADD != s.operation) + { + if (!(bookmark = s.opts->bookmark) || !(bookmark->buffer)) + { + SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified"); + return SQL_ERROR; + } + } - if (res = SC_get_Curres(stmt), res) - res->recent_processed_row_count = stmt->diag_row_count = processed; + s.need_data_callback = FALSE; + ret = bulk_ope_callback(SQL_SUCCESS, &s); return ret; } #endif /* DRIVER_CURSOR_IMPLEMENT */ diff --git a/pgapifunc.h b/pgapifunc.h index ae05621..16ed196 100644 --- a/pgapifunc.h +++ b/pgapifunc.h @@ -12,6 +12,8 @@ /* Internal flags for catalog functions */ #define PODBC_NOT_SEARCH_PATTERN 1L +/* Internal flags for PGAPI_Exec... functions */ +#define PODBC_WITH_HOLD 1L /* Flags for the error handling */ #define PODBC_ALLOW_PARTIAL_EXTRACT 1L #define PODBC_ERROR_CLEAR (1L << 1) @@ -75,8 +77,8 @@ RETCODE SQL_API PGAPI_StmtError(HSTMT StatementHandle, SWORD RecNumber, SQLSMALLINT *TextLength, UWORD flag); RETCODE SQL_API PGAPI_ExecDirect(HSTMT StatementHandle, - SQLCHAR *StatementText, SQLINTEGER TextLength); -RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle); + SQLCHAR *StatementText, SQLINTEGER TextLength, UWORD flag); +RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle, UWORD flag); RETCODE SQL_API PGAPI_Fetch(HSTMT StatementHandle); RETCODE SQL_API PGAPI_FreeConnect(HDBC ConnectionHandle); RETCODE SQL_API PGAPI_FreeEnv(HENV EnvironmentHandle); @@ -287,11 +289,20 @@ RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle, SQLINTEGER StringLength); RETCODE SQL_API PGAPI_BulkOperations(HSTMT StatementHandle, SQLSMALLINT operation); +RETCODE SQL_API PGAPI_AllocDesc(HDBC ConnectionHandle, + SQLHDESC *DescriptorHandle); +RETCODE SQL_API PGAPI_FreeDesc(SQLHDESC DescriptorHandle); +RETCODE SQL_API PGAPI_CopyDesc(SQLHDESC SourceDescHandle, + SQLHDESC TargetDescHandle); RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength); RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength); +RETCODE SQL_API PGAPI_DescError(SQLHDESC DescriptorHandle, SWORD RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength, UWORD flag); #endif /* ODBCVER */ #endif /* define_PG_API_FUNC_H__ */ diff --git a/psqlodbc.h b/psqlodbc.h index 0949531..616d5e5 100644 --- a/psqlodbc.h +++ b/psqlodbc.h @@ -5,7 +5,7 @@ * * Comments: See "notice.txt" for copyright and license information. * - * $Id: psqlodbc.h,v 1.78 2003/08/27 10:17:53 hinoue Exp $ + * $Id: psqlodbc.h,v 1.79 2003/10/25 04:19:22 hinoue Exp $ * */ @@ -87,6 +87,19 @@ typedef UInt4 Oid; #define snprintf _snprintf #endif +#ifndef SQL_ATTR_APP_ROW_DESC +#define SQL_ATTR_APP_ROW_DESC 10010 +#endif +#ifndef SQL_ATTR_APP_PARAM_DESC +#define SQL_ATTR_APP_PARAM_DESC 10011 +#endif +#ifndef SQL_ATTR_IMP_ROW_DESC +#define SQL_ATTR_IMP_ROW_DESC 10012 +#endif +#ifndef SQL_ATTR_IMP_PARAM_DESC +#define SQL_ATTR_IMP_PARAM_DESC 10013 +#endif + /* Driver stuff */ #define DRIVERNAME "PostgreSQL ODBC" @@ -255,6 +268,22 @@ typedef struct QueryInfo_ char *cursor; } QueryInfo; +/* Used to save the error information */ +typedef struct +{ + SDWORD status; + SDWORD errorsize; + SWORD recsize; + SWORD errorpos; + char sqlstate[8]; + Int4 diag_row_count; + char __error_message[1]; +} PG_ErrorInfo; +PG_ErrorInfo *ER_Constructor(SDWORD errornumber, const char *errormsg); +void ER_Destructor(PG_ErrorInfo *); +RETCODE SQL_API ER_ReturnError(PG_ErrorInfo *, SWORD, UCHAR FAR *, + SDWORD FAR *, UCHAR FAR *, SWORD, SWORD FAR *, UWORD); + void logs_on_off(int cnopen, int, int); #define PG_TYPE_LO_UNDEFINED (-999) /* hack until permanent diff --git a/results.c b/results.c index 1e10c3d..ce8cdaa 100644 --- a/results.c +++ b/results.c @@ -126,7 +126,7 @@ PGAPI_NumResultCols( if (stmt->parse_status != STMT_PARSE_FATAL) { parse_ok = TRUE; - *pccol = SC_get_IRD(stmt)->nfields; + *pccol = SC_get_IRDF(stmt)->nfields; mylog("PARSE: PGAPI_NumResultCols: *pccol = %d\n", *pccol); } } @@ -198,7 +198,7 @@ PGAPI_DescribeCol( SC_clear_error(stmt); - irdflds = SC_get_IRD(stmt); + irdflds = SC_get_IRDF(stmt); #if (ODBCVER >= 0x0300) if (0 == icol) /* bookmark column */ { @@ -414,7 +414,7 @@ PGAPI_ColAttributes( if (pcbDesc) *pcbDesc = 0; - irdflds = SC_get_IRD(stmt); + irdflds = SC_get_IRDF(stmt); conn = SC_get_conn(stmt); ci = &(conn->connInfo); @@ -985,6 +985,7 @@ PGAPI_Fetch( StatementClass *stmt = (StatementClass *) hstmt; ARDFields *opts; QResultClass *res; + BindInfoClass *bookmark; mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt)); @@ -1004,8 +1005,8 @@ PGAPI_Fetch( } /* Not allowed to bind a bookmark column when using SQLFetch. */ - opts = SC_get_ARD(stmt); - if (opts->bookmark->buffer) + opts = SC_get_ARDF(stmt); + if ((bookmark = opts->bookmark) && bookmark->buffer) { SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch"); SC_log_error(func, "", stmt); @@ -1140,6 +1141,7 @@ PGAPI_ExtendedFetch( StatementClass *stmt = (StatementClass *) hstmt; ARDFields *opts; QResultClass *res; + BindInfoClass *bookmark; int num_tuples, i, save_rowset_size, @@ -1182,12 +1184,12 @@ PGAPI_ExtendedFetch( return SQL_ERROR; } - opts = SC_get_ARD(stmt); + opts = SC_get_ARDF(stmt); /* * If a bookmark colunmn is bound but bookmark usage is off, then * error */ - if (opts->bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF) + if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF) { SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled"); SC_log_error(func, "", stmt); @@ -1852,7 +1854,7 @@ SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logCh UInt4 oid, blocknum; QResultClass *res, *qres; - IRDFields *irdflds = SC_get_IRD(stmt); + IRDFields *irdflds = SC_get_IRDF(stmt); RETCODE ret = SQL_ERROR; char tidval[32]; @@ -1939,7 +1941,7 @@ SC_pos_reload_needed(StatementClass *stmt, UDWORD flag) Int4 i, limitrow; UWORD qcount; QResultClass *res; - IRDFields *irdflds = SC_get_IRD(stmt); + IRDFields *irdflds = SC_get_IRDF(stmt); RETCODE ret = SQL_ERROR; ConnectionClass *conn = SC_get_conn(stmt); UInt4 oid, blocknum, lodlen; @@ -2221,6 +2223,56 @@ irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow } return ret; } + +/* SQL_NEED_DATA callback for SC_pos_update */ +typedef struct +{ + BOOL updyes; + QResultClass *res; + StatementClass *stmt, *qstmt; + IRDFields *irdflds; + UWORD irow; + UDWORD global_ridx; +} pup_cdata; +static RETCODE +pos_update_callback(RETCODE retcode, pup_cdata *s) +{ + RETCODE ret = retcode; + + if (s->updyes) + { + mylog("pos_update_callback in\n"); + ret = irow_update(ret, s->stmt, s->qstmt, s->irow, s->global_ridx); + PGAPI_FreeStmt(s->qstmt, SQL_DROP); + } + s->updyes = FALSE; + if (SQL_SUCCESS == ret && s->res->keyset) + { + ConnectionClass *conn = SC_get_conn(s->stmt); + + if (CC_is_in_trans(conn)) + { + s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING); + } + else + s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED); + } +#if (ODBCVER >= 0x0300) + if (s->irdflds->rowStatusArray) + { + switch (ret) + { + case SQL_SUCCESS: + s->irdflds->rowStatusArray[s->irow] = SQL_ROW_UPDATED; + break; + default: + s->irdflds->rowStatusArray[s->irow] = ret; + } + } +#endif /* ODBCVER */ + + return ret; +} RETCODE SC_pos_update(StatementClass *stmt, UWORD irow, UDWORD global_ridx) @@ -2228,44 +2280,48 @@ SC_pos_update(StatementClass *stmt, int i, num_cols, upd_cols; - QResultClass *res; - ConnectionClass *conn = SC_get_conn(stmt); - ARDFields *opts = SC_get_ARD(stmt); - IRDFields *irdflds = SC_get_IRD(stmt); + pup_cdata s; + ConnectionClass *conn; + ARDFields *opts = SC_get_ARDF(stmt); BindInfoClass *bindings = opts->bindings; - FIELD_INFO **fi = SC_get_IRD(stmt)->fi; + FIELD_INFO **fi; char updstr[4096]; RETCODE ret; UInt4 oid, offset, blocknum; UInt2 pgoffset; Int4 *used, bind_size = opts->bind_size; - if (!(res = SC_get_Curres(stmt))) + s.stmt = stmt; + s.irow = irow; + s.global_ridx = global_ridx; + s.irdflds = SC_get_IRDF(s.stmt); + fi = s.irdflds->fi; + if (!(s.res = SC_get_Curres(s.stmt))) { - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update."); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update."); return SQL_ERROR; } - mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, res->base, fi, stmt->ti); - if (!stmt->ti) - parse_statement(stmt); /* not preferable */ - if (!stmt->updatable) + mylog("POS UPDATE %d+%d fi=%x ti=%x\n", s.irow, s.res->base, fi, s.stmt->ti); + if (!s.stmt->ti) + parse_statement(s.stmt); /* not preferable */ + if (!s.stmt->updatable) { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only"); + s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; + SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only"); return SQL_ERROR; } - if (!(oid = getOid(res, global_ridx))) + if (!(oid = getOid(s.res, s.global_ridx))) { - SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?"); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?"); return SQL_ERROR; } - getTid(res, global_ridx, &blocknum, &pgoffset); + getTid(s.res, s.global_ridx, &blocknum, &pgoffset); - if (stmt->ti[0]->schema[0]) - sprintf(updstr, "update \"%s\".\"%s\" set", stmt->ti[0]->schema, stmt->ti[0]->name); + if (s.stmt->ti[0]->schema[0]) + sprintf(updstr, "update \"%s\".\"%s\" set", s.stmt->ti[0]->schema, s.stmt->ti[0]->name); else - sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name); - num_cols = irdflds->nfields; + sprintf(updstr, "update \"%s\" set", s.stmt->ti[0]->name); + num_cols = s.irdflds->nfields; offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; for (i = upd_cols = 0; i < num_cols; i++) { @@ -2273,9 +2329,9 @@ SC_pos_update(StatementClass *stmt, { used += (offset >> 2); if (bind_size > 0) - used += (bind_size * irow / 4); + used += (bind_size * s.irow / 4); else - used += irow; + used += s.irow; mylog("%d used=%d,%x\n", i, *used, used); if (*used != SQL_IGNORE && fi[i]->updatable) { @@ -2289,13 +2345,14 @@ SC_pos_update(StatementClass *stmt, else mylog("%d null bind\n", i); } + conn = SC_get_conn(s.stmt); + s.updyes = FALSE; if (upd_cols > 0) { HSTMT hstmt; int j; - int res_cols = QR_NumResultCols(res); + int res_cols = QR_NumResultCols(s.res); ConnInfo *ci = &(conn->connInfo); - StatementClass *qstmt; APDFields *apdopts; Int4 fieldtype = 0; @@ -2306,11 +2363,11 @@ SC_pos_update(StatementClass *stmt, mylog("updstr=%s\n", updstr); if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS) { - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error"); + SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error"); return SQL_ERROR; } - qstmt = (StatementClass *) hstmt; - apdopts = SC_get_APD(qstmt); + s.qstmt = (StatementClass *) hstmt; + apdopts = SC_get_APDF(s.qstmt); apdopts->param_bind_type = opts->bind_size; apdopts->param_offset_ptr = opts->row_offset_ptr; for (i = j = 0; i < num_cols; i++) @@ -2319,67 +2376,49 @@ SC_pos_update(StatementClass *stmt, { used += (offset >> 2); if (bind_size > 0) - used += (bind_size * irow / 4); + used += (bind_size * s.irow / 4); else - used += irow; + used += s.irow; mylog("%d used=%d\n", i, *used); if (*used != SQL_IGNORE && fi[i]->updatable) { - fieldtype = QR_get_field_type(res, i); - PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j, - SQL_PARAM_INPUT, bindings[i].returntype, - pgtype_to_concise_type(stmt, fieldtype), - fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes), - (SQLSMALLINT) fi[i]->decimal_digits, - bindings[i].buffer, - bindings[i].buflen, - bindings[i].used); + fieldtype = QR_get_field_type(s.res, i); + PGAPI_BindParameter(hstmt, + (SQLUSMALLINT) ++j, + SQL_PARAM_INPUT, + bindings[i].returntype, + pgtype_to_concise_type(s.stmt, fieldtype), + fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes), + (SQLSMALLINT) fi[i]->decimal_digits, + bindings[i].buffer, + bindings[i].buflen, + bindings[i].used); } } } - qstmt->exec_start_row = qstmt->exec_end_row = irow; - ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr)); + s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow; + s.updyes = TRUE; + ret = PGAPI_ExecDirect(hstmt, updstr, SQL_NTS, 0); if (ret == SQL_ERROR) { - SC_error_copy(stmt, qstmt); + SC_error_copy(s.stmt, s.qstmt); } else if (ret == SQL_NEED_DATA) /* must be fixed */ { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "SetPos with data_at_exec not yet supported"); - ret = SQL_ERROR; + pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata)); + memcpy(cbdata, &s, sizeof(pup_cdata)); + s.stmt->execute_delegate = s.qstmt; + enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata); + return ret; } - ret = irow_update(ret, stmt, qstmt, irow, global_ridx); - PGAPI_FreeStmt(hstmt, SQL_DROP); } else { ret = SQL_SUCCESS_WITH_INFO; - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null"); - } - if (SQL_SUCCESS == ret && res->keyset) - { - if (CC_is_in_trans(conn)) - { - res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING); - } - else - res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null"); } -#if (ODBCVER >= 0x0300) - if (irdflds->rowStatusArray) - { - switch (ret) - { - case SQL_SUCCESS: - irdflds->rowStatusArray[irow] = SQL_ROW_UPDATED; - break; - default: - irdflds->rowStatusArray[irow] = ret; - } - } -#endif /* ODBCVER */ + ret = pos_update_callback(ret, &s); return ret; } RETCODE @@ -2389,8 +2428,8 @@ SC_pos_delete(StatementClass *stmt, UWORD offset; QResultClass *res, *qres; ConnectionClass *conn = SC_get_conn(stmt); - ARDFields *opts = SC_get_ARD(stmt); - IRDFields *irdflds = SC_get_IRD(stmt); + ARDFields *opts = SC_get_ARDF(stmt); + IRDFields *irdflds = SC_get_IRDF(stmt); BindInfoClass *bindings = opts->bindings; char dltstr[4096]; RETCODE ret; @@ -2495,7 +2534,7 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos { int addcnt; UInt4 oid; - ARDFields *opts = SC_get_ARD(stmt); + ARDFields *opts = SC_get_ARDF(stmt); QResultClass *ires = SC_get_Curres(istmt); const char *cmdstr; BindInfoClass *bookmark; @@ -2522,7 +2561,7 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos return qret; } bookmark = opts->bookmark; - if (bookmark->buffer) + if (bookmark && bookmark->buffer) { char buf[32]; UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; @@ -2545,6 +2584,65 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos } return ret; } + +/* SQL_NEED_DATA callback for SC_pos_add */ +typedef struct +{ + BOOL updyes; + QResultClass *res; + StatementClass *stmt, *qstmt; + IRDFields *irdflds; + UWORD irow; +} padd_cdata; + +static RETCODE +pos_add_callback(RETCODE retcode, padd_cdata *s) +{ + RETCODE ret = retcode; + + if (s->updyes) + { + int brow_save; + + mylog("pos_add_callback in\n"); + brow_save = s->stmt->bind_row; + s->stmt->bind_row = s->irow; + ret = irow_insert(ret, s->stmt, s->qstmt, s->res->num_total_rows); + s->stmt->bind_row = brow_save; + } + s->updyes = FALSE; + PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP); + if (SQL_SUCCESS == ret && s->res->keyset) + { + int global_ridx = s->res->num_total_rows - 1; + ConnectionClass *conn = SC_get_conn(s->stmt); + + if (CC_is_in_trans(conn)) + { + + AddRollback(conn, s->res, global_ridx, NULL); + s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING); + } + else + s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED); + } +#if (ODBCVER >= 0x0300) + if (s->irdflds->rowStatusArray) + { + switch (ret) + { + case SQL_SUCCESS: + s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ADDED; + break; + default: + s->irdflds->rowStatusArray[s->irow] = ret; + } + } +#endif /* ODBCVER */ + + return ret; +} + RETCODE SC_pos_add(StatementClass *stmt, UWORD irow) @@ -2553,15 +2651,14 @@ SC_pos_add(StatementClass *stmt, add_cols, i; HSTMT hstmt; - StatementClass *qstmt; + + padd_cdata s; ConnectionClass *conn; ConnInfo *ci; - QResultClass *res; - ARDFields *opts = SC_get_ARD(stmt); - IRDFields *irdflds = SC_get_IRD(stmt); + ARDFields *opts = SC_get_ARDF(stmt); APDFields *apdopts; BindInfoClass *bindings = opts->bindings; - FIELD_INFO **fi = SC_get_IRD(stmt)->fi; + FIELD_INFO **fi = SC_get_IRDF(stmt)->fi; char addstr[4096]; RETCODE ret; UInt4 offset; @@ -2569,36 +2666,39 @@ SC_pos_add(StatementClass *stmt, Int4 fieldtype; mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti); - if (!(res = SC_get_Curres(stmt))) + s.stmt = stmt; + s.irow = irow; + if (!(s.res = SC_get_Curres(s.stmt))) { - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add."); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add."); return SQL_ERROR; } - if (!stmt->ti) - parse_statement(stmt); /* not preferable */ - if (!stmt->updatable) + if (!s.stmt->ti) + parse_statement(s.stmt); /* not preferable */ + if (!s.stmt->updatable) { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only"); + s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; + SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only"); return SQL_ERROR; } - num_cols = irdflds->nfields; - conn = SC_get_conn(stmt); - if (stmt->ti[0]->schema[0]) - sprintf(addstr, "insert into \"%s\".\"%s\" (", stmt->ti[0]->schema, stmt->ti[0]->name); + s.irdflds = SC_get_IRDF(s.stmt); + num_cols = s.irdflds->nfields; + conn = SC_get_conn(s.stmt); + if (s.stmt->ti[0]->schema[0]) + sprintf(addstr, "insert into \"%s\".\"%s\" (", s.stmt->ti[0]->schema, s.stmt->ti[0]->name); else - sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name); + sprintf(addstr, "insert into \"%s\" (", s.stmt->ti[0]->name); if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS) { - SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error"); + SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error"); return SQL_ERROR; } if (opts->row_offset_ptr) offset = *opts->row_offset_ptr; else offset = 0; - qstmt = (StatementClass *) hstmt; - apdopts = SC_get_APD(qstmt); + s.qstmt = (StatementClass *) hstmt; + apdopts = SC_get_APDF(s.qstmt); apdopts->param_bind_type = opts->bind_size; apdopts->param_offset_ptr = opts->row_offset_ptr; ci = &(conn->connInfo); @@ -2608,34 +2708,35 @@ SC_pos_add(StatementClass *stmt, { used += (offset >> 2); if (bind_size > 0) - used += (bind_size * irow / 4); + used += (bind_size * s.irow / 4); else - used += irow; + used += s.irow; mylog("%d used=%d\n", i, *used); if (*used != SQL_IGNORE && fi[i]->updatable) { - fieldtype = QR_get_field_type(res, i); + fieldtype = QR_get_field_type(s.res, i); if (add_cols) sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name); else sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name); - PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols, - SQL_PARAM_INPUT, bindings[i].returntype, - pgtype_to_concise_type(stmt, fieldtype), - fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes), - (SQLSMALLINT) fi[i]->decimal_digits, - bindings[i].buffer, - bindings[i].buflen, - bindings[i].used); + PGAPI_BindParameter(hstmt, + (SQLUSMALLINT) ++add_cols, + SQL_PARAM_INPUT, + bindings[i].returntype, + pgtype_to_concise_type(s.stmt, fieldtype), + fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes), + (SQLSMALLINT) fi[i]->decimal_digits, + bindings[i].buffer, + bindings[i].buflen, + bindings[i].used); } } else mylog("%d null bind\n", i); } + s.updyes = FALSE; if (add_cols > 0) { - int brow_save; - sprintf(addstr, "%s) values (", addstr); for (i = 0; i < add_cols; i++) { @@ -2646,54 +2747,29 @@ SC_pos_add(StatementClass *stmt, } strcat(addstr, ")"); mylog("addstr=%s\n", addstr); - qstmt->exec_start_row = qstmt->exec_end_row = irow; - ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr)); + s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow; + s.updyes = TRUE; + ret = PGAPI_ExecDirect(hstmt, addstr, SQL_NTS, 0); if (ret == SQL_ERROR) { - SC_error_copy(stmt, qstmt); + SC_error_copy(s.stmt, s.qstmt); } else if (ret == SQL_NEED_DATA) /* must be fixed */ { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "SetPos with data_at_exec not yet supported"); - ret = SQL_ERROR; + padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata)); + memcpy(cbdata, &s, sizeof(padd_cdata)); + s.stmt->execute_delegate = s.qstmt; + enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata); + return ret; } - brow_save = stmt->bind_row; - stmt->bind_row = irow; - ret = irow_insert(ret, stmt, qstmt, res->num_total_rows); - stmt->bind_row = brow_save; } else { ret = SQL_SUCCESS_WITH_INFO; - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null"); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null"); } - PGAPI_FreeStmt(hstmt, SQL_DROP); - if (SQL_SUCCESS == ret && res->keyset) - { - int global_ridx = res->num_total_rows - 1; - if (CC_is_in_trans(conn)) - { - AddRollback(conn, res, global_ridx, NULL); - res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING); - } - else - res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED); - } -#if (ODBCVER >= 0x0300) - if (irdflds->rowStatusArray) - { - switch (ret) - { - case SQL_SUCCESS: - irdflds->rowStatusArray[irow] = SQL_ROW_ADDED; - break; - default: - irdflds->rowStatusArray[irow] = ret; - } - } -#endif /* ODBCVER */ + ret = pos_add_callback(ret, &s); return ret; } @@ -2708,7 +2784,7 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx) { RETCODE ret; #if (ODBCVER >= 0x0300) - IRDFields *irdflds = SC_get_IRD(stmt); + IRDFields *irdflds = SC_get_IRDF(stmt); #endif /* ODBCVER */ /* save the last_fetch_count */ int last_fetch = stmt->last_fetch_count; @@ -2747,6 +2823,118 @@ SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx) return SQL_SUCCESS; } +/* SQL_NEED_DATA callback for PGAPI_SetPos */ +typedef struct +{ + BOOL need_data_callback, auto_commit_needed; + QResultClass *res; + StatementClass *stmt; + ARDFields *opts; + GetDataInfo *gdata; + int idx, start_row, end_row, processed, ridx; + UWORD fOption, irow, nrow; +} spos_cdata; +static +RETCODE spos_callback(RETCODE retcode, spos_cdata *s) +{ + RETCODE ret; + ConnectionClass *conn; + UDWORD global_ridx; + + ret = retcode; + if (s->need_data_callback) + { + mylog("spos_callback in\n"); + s->processed++; + if (SQL_ERROR != retcode) + { + s->nrow++; + s->idx++; + } + } + else + { + s->ridx = -1; + s->idx = s->nrow = s->processed = 0; + } + s->need_data_callback = FALSE; + for (; SQL_ERROR != ret && s->nrow <= s->end_row; s->idx++) + { + global_ridx = RowIdx2GIdx(s->idx, s->stmt); + if (SQL_ADD != s->fOption) + { + if ((int) global_ridx >= s->res->num_total_rows) + break; +#ifdef DRIVER_CURSOR_IMPLEMENT + if (s->res->keyset) /* the row may be deleted and not in the rowset */ + { + if (0 == (s->res->keyset[global_ridx].status & CURS_IN_ROWSET)) + continue; + } +#endif /* DRIVER_CURSOR_IMPLEMENT */ + } + if (s->nrow < s->start_row) + { + s->nrow++; + continue; + } + s->ridx = s->nrow; +#if (ODBCVER >= 0x0300) + if (0 != s->irow || !s->opts->row_operation_ptr || s->opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED) + { +#endif /* ODBCVER */ + switch (s->fOption) + { +#ifdef DRIVER_CURSOR_IMPLEMENT + case SQL_UPDATE: + ret = SC_pos_update(s->stmt, s->nrow, global_ridx); + break; + case SQL_DELETE: + ret = SC_pos_delete(s->stmt, s->nrow, global_ridx); + break; + case SQL_ADD: + ret = SC_pos_add(s->stmt, s->nrow); + break; +#endif /* DRIVER_CURSOR_IMPLEMENT */ + case SQL_REFRESH: + ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx); + break; + } + if (SQL_NEED_DATA == ret) + { + spos_cdata *cbdata = (spos_cdata *) malloc(sizeof(spos_cdata)); + + memcpy(cbdata, s, sizeof(spos_cdata)); + cbdata->need_data_callback = TRUE; + enqueueNeedDataCallback(s->stmt, spos_callback, cbdata); + return ret; + } + s->processed++; +#if (ODBCVER >= 0x0300) + } +#endif /* ODBCVER */ + if (SQL_ERROR != ret) + s->nrow++; + } + conn = SC_get_conn(s->stmt); + if (SQL_ERROR == ret) + CC_abort(conn); + if (s->auto_commit_needed) + PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if (s->irow > 0) + { + if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */ + { + s->stmt->currTuple = RowIdx2GIdx(s->ridx, s->stmt); + QR_set_position(s->res, s->ridx); + } + } + else if (SC_get_IRDF(s->stmt)->rowsFetched) + *(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed; + s->res->recent_processed_row_count = s->stmt->diag_row_count = s->processed; + return ret; +} + /* * This positions the cursor within a rowset, that was positioned using SQLExtendedFetch. * This will be useful (so far) only when using SQLGetData after SQLExtendedFetch. @@ -2760,88 +2948,92 @@ PGAPI_SetPos( { CSTR func = "PGAPI_SetPos"; RETCODE ret; - StatementClass *stmt = (StatementClass *) hstmt; - ConnectionClass *conn = SC_get_conn(stmt); - QResultClass *res; - int num_cols, i, start_row, end_row, processed, ridx; - UWORD nrow; - ARDFields *opts; - BindInfoClass *bindings; - UDWORD global_ridx, rowsetSize; - BOOL auto_commit_needed = FALSE; + ConnectionClass *conn; + int num_cols, i, rowsetSize; + GetDataClass *gdata = NULL; + spos_cdata s; - if (!stmt) + s.stmt = (StatementClass *) hstmt; + if (!s.stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } - opts = SC_get_ARD(stmt); - bindings = opts->bindings; + s.irow = irow; + s.fOption = fOption; + s.auto_commit_needed = FALSE; + s.opts = SC_get_ARDF(s.stmt); + gdata = SC_get_GDTI(s.stmt)->gdata; #ifdef DRIVER_CURSOR_IMPLEMENT - mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, fOption, irow, fLock, stmt->currTuple); - if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) + mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, s.fOption, s.irow, fLock, s.stmt->currTuple); + if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) ; else #endif /* DRIVER_CURSOR_IMPLEMENT */ - if (fOption != SQL_POSITION && fOption != SQL_REFRESH) + if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH) { - SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos"); - SC_log_error(func, "", stmt); + SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos"); + SC_log_error(func, "", s.stmt); return SQL_ERROR; } - if (!(res = SC_get_Curres(stmt))) + if (!(s.res = SC_get_Curres(s.stmt))) { - SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos."); - SC_log_error(func, "", stmt); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos."); + SC_log_error(func, "", s.stmt); return SQL_ERROR; } #if (ODBCVER >= 0x0300) - rowsetSize = (stmt->transition_status == 7 ? opts->size_of_rowset_odbc2 : opts->size_of_rowset); + rowsetSize = (s.stmt->transition_status == 7 ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset); #else - rowsetSize = opts->size_of_rowset_odbc2; + rowsetSize = s.opts->size_of_rowset_odbc2; #endif /* ODBCVER */ - if (irow == 0) /* bulk operation */ + if (s.irow == 0) /* bulk operation */ { - if (SQL_POSITION == fOption) + if (SQL_POSITION == s.fOption) { - SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed."); - SC_log_error(func, "", stmt); + SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed."); + SC_log_error(func, "", s.stmt); return SQL_ERROR; } - start_row = 0; - end_row = rowsetSize - 1; + s.start_row = 0; + s.end_row = rowsetSize - 1; } else { - if (SQL_ADD != fOption && irow > stmt->last_fetch_count) + if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count) { - SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range"); - SC_log_error(func, "", stmt); + SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range"); + SC_log_error(func, "", s.stmt); return SQL_ERROR; } - start_row = end_row = irow - 1; + s.start_row = s.end_row = s.irow - 1; } - num_cols = QR_NumResultCols(res); + num_cols = QR_NumResultCols(s.res); /* Reset for SQLGetData */ - if (bindings) + if (gdata) for (i = 0; i < num_cols; i++) - bindings[i].data_left = -1; + gdata[i].data_left = -1; ret = SQL_SUCCESS; #ifdef DRIVER_CURSOR_IMPLEMENT - switch (fOption) + conn = SC_get_conn(s.stmt); + switch (s.fOption) { case SQL_UPDATE: case SQL_DELETE: case SQL_ADD: - if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed) + if (s.auto_commit_needed = CC_is_in_autocommit(conn), s.auto_commit_needed) PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); break; } #endif /* DRIVER_CURSOR_IMPLEMENT */ + + s.need_data_callback = FALSE; + return spos_callback(SQL_SUCCESS, &s); +#ifdef NOT_USED ridx = -1; for (i = nrow = 0, processed = 0; nrow <= end_row; i++) { @@ -2885,6 +3077,8 @@ PGAPI_SetPos( ret = SC_pos_refresh(stmt, nrow, global_ridx); break; } + if (SQL_NEED_DATA == ret) + return ret; processed++; if (SQL_ERROR == ret) break; @@ -2905,10 +3099,11 @@ PGAPI_SetPos( QR_set_position(res, ridx); } } - else if (SC_get_IRD(stmt)->rowsFetched) - *(SC_get_IRD(stmt)->rowsFetched) = processed; + else if (SC_get_IRDF(stmt)->rowsFetched) + *(SC_get_IRDF(stmt)->rowsFetched) = processed; res->recent_processed_row_count = stmt->diag_row_count = processed; - return ret; + return ret; +#endif /* NOT_USED */ } diff --git a/statement.c b/statement.c index 3451dc3..522345e 100644 --- a/statement.c +++ b/statement.c @@ -84,6 +84,8 @@ PGAPI_AllocStmt(HDBC hdbc, CSTR func = "PGAPI_AllocStmt"; ConnectionClass *conn = (ConnectionClass *) hdbc; StatementClass *stmt; + ARDFields *ardopts; + BindInfoClass *bookmark; mylog("%s: entering...\n", func); @@ -118,10 +120,9 @@ PGAPI_AllocStmt(HDBC hdbc, /* Copy default statement options based from Connection options */ stmt->options = stmt->options_orig = conn->stmtOptions; - stmt->ardopts = conn->ardOptions; - stmt->ardopts.bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass)); - stmt->ardopts.bookmark->buffer = NULL; - stmt->ardopts.bookmark->used = NULL; + stmt->ardi.ardopts = conn->ardOptions; + ardopts = SC_get_ARDF(stmt); + bookmark = ARD_AllocBookmark(ardopts); stmt->stmt_size_limit = CC_get_max_query_len(conn); /* Save the handle for later */ @@ -224,31 +225,6 @@ InitializeStatementOptions(StatementOptions *opt) } -/* - * ARDFields initialize - */ -void -InitializeARDFields(ARDFields *opt) -{ - memset(opt, 0, sizeof(ARDFields)); -#if (ODBCVER >= 0x0300) - opt->size_of_rowset = 1; -#endif /* ODBCVER */ - opt->bind_size = 0; /* default is to bind by column */ - opt->size_of_rowset_odbc2 = 1; -} -/* - * APDFields initialize - */ -void -InitializeAPDFields(APDFields *opt) -{ - memset(opt, 0, sizeof(APDFields)); - opt->paramset_size = 1; - opt->param_bind_type = 0; /* default is to bind by column */ -} - - StatementClass * SC_Constructor(void) { @@ -303,10 +279,14 @@ SC_Constructor(void) /* Clear Statement Options -- defaults will be set in AllocStmt */ memset(&rv->options, 0, sizeof(StatementOptions)); - memset(&rv->ardopts, 0, sizeof(ARDFields)); - memset(&rv->apdopts, 0, sizeof(APDFields)); - memset(&rv->irdopts, 0, sizeof(IRDFields)); - memset(&rv->ipdopts, 0, sizeof(IPDFields)); + InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->ardi), + rv, SQL_ATTR_APP_ROW_DESC); + InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->apdi), + rv, SQL_ATTR_APP_PARAM_DESC); + InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->irdi), + rv, SQL_ATTR_IMP_ROW_DESC); + InitializeEmbeddedDescriptor((DescriptorClass *)&(rv->ipdi), + rv, SQL_ATTR_IMP_PARAM_DESC); rv->pre_executing = FALSE; rv->inaccurate_result = FALSE; @@ -315,60 +295,17 @@ SC_Constructor(void) rv->error_recsize = -1; rv->diag_row_count = 0; rv->stmt_time = 0; + rv->execute_delegate = NULL; + rv->allocated_callbacks = 0; + rv->num_callbacks = 0; + rv->callbacks = NULL; + GetDataInfoInitialize(SC_get_GDTI(rv)); + PutDataInfoInitialize(SC_get_PDTI(rv)); INIT_STMT_CS(rv); } return rv; } - -void ARDFields_free(ARDFields * self) -{ - if (self->bookmark) - { - free(self->bookmark); - self->bookmark = NULL; - } - /* - * the memory pointed to by the bindings is not deallocated by the - * driver but by the application that uses that driver, so we don't - * have to care - */ - ARD_unbind_cols(self, TRUE); -} - -void APDFields_free(APDFields * self) -{ - /* param bindings */ - APD_free_params(self, STMT_FREE_PARAMS_ALL); -} - -void IRDFields_free(IRDFields * self) -{ - /* Free the parsed field information */ - if (self->fi) - { - int i; - - for (i = 0; i < (int) self->nfields; i++) - { - if (self->fi[i]) - { - if (self->fi[i]->schema) - free(self->fi[i]->schema); - free(self->fi[i]); - } - } - free(self->fi); - self->fi = NULL; - } -} - -void IPDFields_free(IPDFields * self) -{ - /* param bindings */ - IPD_free_params(self, STMT_FREE_PARAMS_ALL); -} - char SC_Destructor(StatementClass *self) { @@ -407,13 +344,17 @@ SC_Destructor(StatementClass *self) } /* Free the parsed field information */ - ARDFields_free(&(self->ardopts)); - APDFields_free(&(self->apdopts)); - IRDFields_free(&(self->irdopts)); - IPDFields_free(&(self->ipdopts)); + DC_Destructor(SC_get_ARDi(self)); + DC_Destructor(SC_get_APDi(self)); + DC_Destructor(SC_get_IRDi(self)); + DC_Destructor(SC_get_IPDi(self)); if (self->__error_message) free(self->__error_message); + cancelNeedDataState(self); + if (self->callbacks) + free(self->callbacks); + DELETE_STMT_CS(self); free(self); @@ -430,8 +371,9 @@ SC_Destructor(StatementClass *self) void SC_free_params(StatementClass *self, char option) { - APD_free_params(SC_get_APD(self), option); - IPD_free_params(SC_get_IPD(self), option); + APD_free_params(SC_get_APDF(self), option); + IPD_free_params(SC_get_IPDF(self), option); + PDATA_free_params(SC_get_PDTI(self), option); self->data_at_exec = -1; self->current_exec_param = -1; self->put_data = FALSE; @@ -583,7 +525,7 @@ SC_recycle_statement(StatementClass *self) self->ntab = 0; } /* Free the parsed field information */ - IRDFields_free(SC_get_IRD(self)); + DC_Destructor(SC_get_IRD(self)); self->parse_status = STMT_PARSE_NONE; self->updatable = FALSE; @@ -621,6 +563,7 @@ SC_recycle_statement(StatementClass *self) */ SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY); SC_initialize_stmts(self, FALSE); + cancelNeedDataState(self); /* * reset the current attr setting to the original one. */ @@ -652,7 +595,7 @@ SC_pre_execute(StatementClass *self) self->pre_executing = TRUE; self->inaccurate_result = FALSE; - PGAPI_Execute(self); + PGAPI_Execute(self, 0); self->pre_executing = old_pre_executing; @@ -677,11 +620,17 @@ SC_pre_execute(StatementClass *self) char SC_unbind_cols(StatementClass *self) { - ARDFields *opts = SC_get_ARD(self); + ARDFields *opts = SC_get_ARDF(self); + GetDataInfo *gdata = SC_get_GDTI(self); + BindInfoClass *bookmark; ARD_unbind_cols(opts, FALSE); - opts->bookmark->buffer = NULL; - opts->bookmark->used = NULL; + GDATA_unbind_cols(gdata, FALSE); + if (bookmark = opts->bookmark, bookmark != NULL) + { + bookmark->buffer = NULL; + bookmark->used = NULL; + } return 1; } @@ -851,6 +800,7 @@ SC_fetch(StatementClass *self) CSTR func = "SC_fetch"; QResultClass *res = SC_get_Curres(self); ARDFields *opts; + GetDataInfo *gdata; int retval, result; @@ -859,6 +809,7 @@ SC_fetch(StatementClass *self) Oid type; char *value; ColumnInfoClass *coli; + BindInfoClass *bookmark; /* TupleField *tupleField; */ ConnInfo *ci = &(SC_get_conn(self)->connInfo); @@ -921,32 +872,35 @@ SC_fetch(StatementClass *self) self->last_fetch_count++; self->last_fetch_count_include_ommitted++; - opts = SC_get_ARD(self); + opts = SC_get_ARDF(self); /* * If the bookmark column was bound then return a bookmark. Since this * is used with SQLExtendedFetch, and the rowset size may be greater * than 1, and an application can use row or column wise binding, use * the code in copy_and_convert_field() to handle that. */ - if (opts->bookmark->buffer) + if ((bookmark = opts->bookmark) && bookmark->buffer) { char buf[32]; UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; sprintf(buf, "%ld", SC_get_bookmark(self)); result = copy_and_convert_field(self, 0, buf, - SQL_C_ULONG, opts->bookmark->buffer + offset, 0, - opts->bookmark->used ? opts->bookmark->used + (offset >> 2) : NULL); + SQL_C_ULONG, bookmark->buffer + offset, 0, + bookmark->used ? bookmark->used + (offset >> 2) : NULL); } if (self->options.retrieve_data == SQL_RD_OFF) /* data isn't required */ return SQL_SUCCESS; + gdata = SC_get_GDTI(self); + if (gdata->allocated != opts->allocated) + extend_getdata_info(gdata, opts->allocated, TRUE); for (lf = 0; lf < num_cols; lf++) { mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer); /* reset for SQLGetData */ - opts->bindings[lf].data_left = -1; + gdata->gdata[lf].data_left = -1; if (opts->bindings[lf].buffer != NULL) { @@ -1029,13 +983,8 @@ SC_execute(StatementClass *self) { CSTR func = "SC_execute"; ConnectionClass *conn; - APDFields *apdopts; - char was_ok, was_nonfatal, was_rows_affected = 1; - /* was_rows_affected is set to 0 iff an UPDATE or DELETE affects - * no rows. In this instance the driver should return - * SQL_NO_DATA_FOUND instead of SQL_SUCCESS. - */ - + IPDFields *ipdopts; + char was_ok, was_nonfatal; QResultClass *res = NULL; Int2 oldstatus, numcols; @@ -1166,13 +1115,6 @@ SC_execute(StatementClass *self) { was_ok = QR_command_successful(res); was_nonfatal = QR_command_nonfatal(res); - if (res->command && - (strncmp(res->command, "UPDATE", 6) == 0 || - strncmp(res->command, "DELETE", 6) == 0) && - strtoul(res->command + 7, NULL, 0) == 0) - { - was_rows_affected = 0; - } if (was_ok) SC_set_errornumber(self, STMT_OK); @@ -1202,7 +1144,7 @@ SC_execute(StatementClass *self) /* now allocate the array to hold the binding info */ if (numcols > 0) { - ARDFields *opts = SC_get_ARD(self); + ARDFields *opts = SC_get_ARDF(self); extend_column_bindings(opts, numcols); if (opts->bindings == NULL) { @@ -1248,13 +1190,12 @@ SC_execute(StatementClass *self) last->next = res; } - apdopts = SC_get_APD(self); + ipdopts = SC_get_IPDF(self); if (self->statement_type == STMT_TYPE_PROCCALL && (SC_get_errornumber(self) == STMT_OK || SC_get_errornumber(self) == STMT_INFO_ONLY) && - apdopts->parameters && - apdopts->parameters[0].buffer && - apdopts->parameters[0].paramType == SQL_PARAM_OUTPUT) + ipdopts->parameters && + ipdopts->parameters[0].paramType == SQL_PARAM_OUTPUT) { /* get the return value of the procedure * call */ RETCODE ret; @@ -1263,6 +1204,8 @@ SC_execute(StatementClass *self) ret = SC_fetch(hstmt); if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) { + APDFields *apdopts = SC_get_APDF(self); + ret = PGAPI_GetData(hstmt, 1, apdopts->parameters[0].CType, apdopts->parameters[0].buffer, apdopts->parameters[0].buflen, apdopts->parameters[0].used); if (ret != SQL_SUCCESS) { @@ -1275,10 +1218,7 @@ SC_execute(StatementClass *self) } } if (SC_get_errornumber(self) == STMT_OK) - if (was_rows_affected) - return SQL_SUCCESS; - else - return SQL_NO_DATA_FOUND; + return SQL_SUCCESS; else if (SC_get_errornumber(self) == STMT_INFO_ONLY) return SQL_SUCCESS_WITH_INFO; else @@ -1290,6 +1230,60 @@ SC_execute(StatementClass *self) } } +#define CALLBACK_ALLOC_ONCE 4 +int enqueueNeedDataCallback(StatementClass *stmt, NeedDataCallfunc func, void *data) +{ + if (stmt->num_callbacks >= stmt->allocated_callbacks) + { + stmt->callbacks = (NeedDataCallback *) realloc(stmt->callbacks, + sizeof(NeedDataCallback) * (stmt->allocated_callbacks + + CALLBACK_ALLOC_ONCE)); + stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE; + } + stmt->callbacks[stmt->num_callbacks].func = func; + stmt->callbacks[stmt->num_callbacks].data = data; + stmt->num_callbacks++; + +inolog("enqueueNeedDataCallack stmt=%x, func=%x, count=%d\n", stmt, func, stmt->num_callbacks); + return stmt->num_callbacks; +} + +RETCODE dequeueNeedDataCallback(RETCODE retcode, StatementClass *stmt) +{ + RETCODE ret; + NeedDataCallfunc func; + void *data; + int i, cnt; + + mylog("dequeueNeedDataCallback ret=%d count=%d\n", retcode, stmt->num_callbacks); + if (SQL_NEED_DATA == retcode) + return retcode; + if (stmt->num_callbacks <= 0) + return retcode; + func = stmt->callbacks[0].func; + data = stmt->callbacks[0].data; + for (i = 1; i < stmt->num_callbacks; i++) + stmt->callbacks[i - 1] = stmt->callbacks[i]; + cnt = --stmt->num_callbacks; + ret = (*func)(retcode, data); + free(data); + if (SQL_NEED_DATA != ret && cnt > 0) + ret = dequeueNeedDataCallback(ret, stmt); + return ret; +} + +void cancelNeedDataState(StatementClass *stmt) +{ + int cnt = stmt->num_callbacks, i; + + stmt->num_callbacks = 0; + for (i = 0; i < cnt; i++) + { + if (stmt->callbacks[i].data) + free(stmt->callbacks[i].data); + } + stmt->execute_delegate = NULL; +} void SC_log_error(const char *func, const char *desc, const StatementClass *self) @@ -1300,8 +1294,8 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self) if (self) { QResultClass *res = SC_get_Result(self); - const ARDFields *opts = SC_get_ARD(self); - const APDFields *apdopts = SC_get_APD(self); + const ARDFields *opts = SC_get_ARDF(self); + const APDFields *apdopts = SC_get_APDF(self); int rowsetSize; #if (ODBCVER >= 0x0300) @@ -1343,3 +1337,57 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self) } #undef PRN_NULLCHECK } + +/* Map sql commands to statement types */ +static struct +{ + int number; + const char * ver3str; + const char * ver2str; +} Descriptor_sqlstate[] = + +{ + { STMT_OK, "00000", "00000" }, /* OK */ + { STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */ + { STMT_STATUS_ERROR, "HY010", "S1010" }, + { STMT_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */ + { STMT_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */ + { STMT_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */ + { STMT_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */ + { STMT_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */ + { STMT_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */ + { STMT_STILL_EXECUTING, "HY010", "S1010" }, + { STMT_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not + * capable' */ + { STMT_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" }, + { STMT_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" }, + { STMT_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" }, + { STMT_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" }, + { STMT_INVALID_CURSOR_STATE_ERROR, "07005", "24000" }, + { STMT_OPTION_VALUE_CHANGED, "01S02", "01S02" }, + { STMT_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */ + { STMT_NO_CURSOR_NAME, "S1015", "S1015" }, + { STMT_INVALID_CURSOR_NAME, "34000", "34000" }, + { STMT_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */ + { STMT_ROW_OUT_OF_RANGE, "HY107", "S1107" }, + { STMT_OPERATION_CANCELLED, "HY008", "S1008" }, + { STMT_INVALID_CURSOR_POSITION, "HY109", "S1109" }, + { STMT_VALUE_OUT_OF_RANGE, "HY019", "22003" }, + { STMT_OPERATION_INVALID, "HY011", "S1011" }, + { STMT_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" }, + { STMT_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */ + { STMT_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" }, + { STMT_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" }, + { STMT_ERROR_IN_ROW, "01S01", "01S01" }, + { STMT_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" }, + { STMT_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" }, + { STMT_FETCH_OUT_OF_RANGE, "HY106", "S1106" }, + { STMT_COUNT_FIELD_INCORRECT, "07002", "07002" }, + + + { STMT_ROW_VERSION_CHANGED, "01001", "01001" }, /* data changed */ + { STMT_TRUNCATED, "01004", "01004" }, /* data truncated */ + { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */ + { STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" }, +}; + diff --git a/statement.h b/statement.h index 2e3feda..ae22bff 100644 --- a/statement.h +++ b/statement.h @@ -125,6 +125,12 @@ enum STMT_FETCH_EXTENDED }; +typedef RETCODE (*NeedDataCallfunc)(RETCODE, void *); +typedef struct +{ + NeedDataCallfunc func; + void *data; +} NeedDataCallback; /******** Statement Handle ***********/ struct StatementClass_ @@ -136,10 +142,16 @@ struct StatementClass_ HSTMT FAR *phstmt; StatementOptions options; StatementOptions options_orig; - ARDFields ardopts; - IRDFields irdopts; - APDFields apdopts; - IPDFields ipdopts; + /* attached descriptor handles */ + ARDClass *ard; + APDClass *apd; + IRDClass *ird; + IPDClass *ipd; + /* implicit descriptor handles */ + ARDClass ardi; + IRDClass irdi; + APDClass apdi; + IPDClass ipdi; STMT_Status status; char *__error_message; @@ -147,6 +159,7 @@ struct StatementClass_ Int4 currTuple; /* current absolute row number (GetData, * SetPos, SQLFetch) */ + GetDataInfo gdata_info; int save_rowset_size; /* saved rowset size in case of * change/FETCH_NEXT */ Int4 rowset_start; /* start of rowset (an absolute row @@ -171,6 +184,7 @@ struct StatementClass_ int data_at_exec; /* Number of params needing SQLPutData */ int current_exec_param; /* The current parameter for * SQLPutData */ + PutDataInfo pdata_info; char put_data; /* Has SQLPutData been called yet? */ @@ -182,6 +196,7 @@ struct StatementClass_ * prepared at the server ? */ char internal; /* Is this statement being called * internally? */ + char transition_status; /* Transition status */ char cursor_name[MAX_CURSOR_LEN + 1]; @@ -206,6 +221,11 @@ struct StatementClass_ Int4 where_pos; Int4 last_fetch_count_include_ommitted; time_t stmt_time; + /* SQL_NEED_DATA Callback list */ + StatementClass *execute_delegate; + UInt2 allocated_callbacks; + UInt2 num_callbacks; + NeedDataCallback *callbacks; #if defined(WIN_MULTITHREAD_SUPPORT) CRITICAL_SECTION cs; #elif defined(POSIX_MULTITHREAD_SUPPORT) @@ -219,16 +239,26 @@ struct StatementClass_ #define SC_get_Result(a) (a->result) #define SC_set_Curres(a, b) (a->curres = b) #define SC_get_Curres(a) (a->curres) -#define SC_get_ARD(a) (&(a->ardopts)) -#define SC_get_APD(a) (&(a->apdopts)) -#define SC_get_IRD(a) (&(a->irdopts)) -#define SC_get_IPD(a) (&(a->ipdopts)) +#define SC_get_ARD(a) (a->ard) +#define SC_get_APD(a) (a->apd) +#define SC_get_IRD(a) (a->ird) +#define SC_get_IPD(a) (a->ipd) +#define SC_get_ARDF(a) (&(SC_get_ARD(a)->ardopts)) +#define SC_get_APDF(a) (&(SC_get_APD(a)->apdopts)) +#define SC_get_IRDF(a) (&(SC_get_IRD(a)->irdopts)) +#define SC_get_IPDF(a) (&(SC_get_IPD(a)->ipdopts)) +#define SC_get_ARDi(a) (&(a->ardi)) +#define SC_get_APDi(a) (&(a->apdi)) +#define SC_get_IRDi(a) (&(a->irdi)) +#define SC_get_IPDi(a) (&(a->ipdi)) +#define SC_get_GDTI(a) (&(a->gdata_info)) +#define SC_get_PDTI(a) (&(a->pdata_info)) #define SC_get_errornumber(a) (a->__error_number) #define SC_set_errornumber(a, n) (a->__error_number = n) #define SC_get_errormsg(a) (a->__error_message) #if (ODBCVER >= 0x0300) -#define SC_is_lower_case(a, b) (a->options.metadata_id || b->connInfo.lower_case_identifier) +#define SC_is_lower_case(a, b) (a->options.metadata_id, b->connInfo.lower_case_identifier) #else #define SC_is_lower_case(a, b) (b->connInfo.lower_case_identifier) #endif /* ODBCVER */ @@ -295,6 +325,12 @@ RETCODE SC_pos_delete(StatementClass *self, UWORD irow, UDWORD index); RETCODE SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index); RETCODE SC_pos_add(StatementClass *self, UWORD irow); +DescriptorClass *SC_set_ARD(StatementClass *stmt, DescriptorClass *desc); +DescriptorClass *SC_set_APD(StatementClass *stmt, DescriptorClass *desc); +int enqueueNeedDataCallback(StatementClass *self, NeedDataCallfunc, void *); +RETCODE dequeueNeedDataCallback(RETCODE, StatementClass *self); +void cancelNeedDataState(StatementClass *self); + /* * Macros to convert global index <-> relative index in resultset/rowset */ diff --git a/version.h b/version.h index bc38b19..18a7155 100644 --- a/version.h +++ b/version.h @@ -9,8 +9,8 @@ #ifndef __VERSION_H__ #define __VERSION_H__ -#define POSTGRESDRIVERVERSION "07.03.0200" -#define POSTGRES_RESOURCE_VERSION "07.03.0200\0" -#define PG_DRVFILE_VERSION 7,3,2,0 +#define POSTGRESDRIVERVERSION "07.03.0201" +#define POSTGRES_RESOURCE_VERSION "07.03.0201\0" +#define PG_DRVFILE_VERSION 7,3,2,01 #endif diff --git a/win32.mak b/win32.mak index 4baca75..dcfb5f4 100644 --- a/win32.mak +++ b/win32.mak @@ -89,6 +89,7 @@ CLEAN : -@erase "$(INTDIR)\odbcapi.obj" -@erase "$(INTDIR)\odbcapi30.obj" -@erase "$(INTDIR)\pgapi30.obj" + -@erase "$(INTDIR)\descriptor.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(OUTDIR)\psqlodbc.dll" -@erase "$(OUTDIR)\psqlodbc.exp" @@ -178,6 +179,7 @@ LINK32_OBJS= \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\odbcapi30.obj" \ "$(INTDIR)\pgapi30.obj" \ + "$(INTDIR)\descriptor.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIRBIN)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -231,6 +233,7 @@ CLEAN : -@erase "$(INTDIR)\odbcapi.obj" -@erase "$(INTDIR)\odbcapi30.obj" -@erase "$(INTDIR)\pgapi30.obj" + -@erase "$(INTDIR)\descriptor.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\vc60.pdb" -@erase "$(OUTDIR)\psqlodbc.dll" @@ -323,6 +326,7 @@ LINK32_OBJS= \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\odbcapi30.obj" \ "$(INTDIR)\pgapi30.obj" \ + "$(INTDIR)\descriptor.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -533,5 +537,10 @@ SOURCE=pgapi30.c "$(INTDIR)\pgapi30.obj" : $(SOURCE) "$(INTDIR)" $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=descriptor.c + +"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + !ENDIF diff --git a/win32_25.mak b/win32_25.mak index 3fd187a..2cebc4a 100644 --- a/win32_25.mak +++ b/win32_25.mak @@ -86,6 +86,7 @@ CLEAN : -@erase "$(INTDIR)\tuple.obj" -@erase "$(INTDIR)\tuplelist.obj" -@erase "$(INTDIR)\odbcapi.obj" + -@erase "$(INTDIR)\descriptor.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(OUTDIR)\psqlodbc25.dll" -@erase "$(OUTDIR)\psqlodbc.exp" @@ -172,6 +173,7 @@ LINK32_OBJS= \ "$(INTDIR)\tuple.obj" \ "$(INTDIR)\tuplelist.obj" \ "$(INTDIR)\odbcapi.obj" \ + "$(INTDIR)\descriptor.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIRBIN)\psqlodbc25.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -222,6 +224,7 @@ CLEAN : -@erase "$(INTDIR)\tuple.obj" -@erase "$(INTDIR)\tuplelist.obj" -@erase "$(INTDIR)\odbcapi.obj" + -@erase "$(INTDIR)\descriptor.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\vc60.pdb" -@erase "$(OUTDIR)\psqlodbc25.dll" @@ -311,6 +314,7 @@ LINK32_OBJS= \ "$(INTDIR)\tuple.obj" \ "$(INTDIR)\tuplelist.obj" \ "$(INTDIR)\odbcapi.obj" \ + "$(INTDIR)\descriptor.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIR)\psqlodbc25.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -504,6 +508,11 @@ SOURCE=odbcapi.c "$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)" $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=descriptor.c + +"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + diff --git a/win32_30w.mak b/win32_30w.mak index c837d45..0a5a29b 100644 --- a/win32_30w.mak +++ b/win32_30w.mak @@ -82,6 +82,7 @@ CLEAN : -@erase "$(INTDIR)\tuplelist.obj" -@erase "$(INTDIR)\odbcapi.obj" -@erase "$(INTDIR)\odbcapi30.obj" + -@erase "$(INTDIR)\descriptor.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(OUTDIR)\psqlodbc30w.dll" -@erase "$(OUTDIR)\psqlodbc.exp" @@ -168,6 +169,7 @@ LINK32_OBJS= \ "$(INTDIR)\tuplelist.obj" \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\odbcapi30.obj" \ + "$(INTDIR)\descriptor.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIRBIN)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -214,6 +216,7 @@ CLEAN : -@erase "$(INTDIR)\tuplelist.obj" -@erase "$(INTDIR)\odbcapi.obj" -@erase "$(INTDIR)\odbcapi30.obj" + -@erase "$(INTDIR)\descriptor.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\vc60.pdb" -@erase "$(OUTDIR)\psqlodbc30w.dll" @@ -303,6 +306,7 @@ LINK32_OBJS= \ "$(INTDIR)\tuplelist.obj" \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\odbcapi30.obj" \ + "$(INTDIR)\descriptor.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIR)\psqlodbc30w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -514,7 +518,10 @@ SOURCE=odbcapi30.c "$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)" $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=descriptor.c +"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) !ENDIF -- 2.39.5