📄 bind.c
字号:
/*------- * Module: bind.c * * Description: This module contains routines related to binding * columns and parameters. * * Classes: BindInfoClass, ParameterInfoClass * * API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams, * SQLParamOptions * * Comments: See "notice.txt" for copyright and license information. *------- *//* #include <stdlib.h> */#include <string.h>#include <ctype.h>#include "bind.h"#include "misc.h"#include "environ.h"#include "statement.h"#include "descriptor.h"#include "qresult.h"#include "pgtypes.h"#include "multibyte.h"#include "pgapifunc.h"/* Bind parameters on a statement handle */RETCODE SQL_APIPGAPI_BindParameter( HSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale, PTR rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue){ StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_BindParameter"; APDFields *apdopts; IPDFields *ipdopts; PutDataInfo *pdata_info; mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } SC_clear_error(stmt); apdopts = SC_get_APDF(stmt); if (apdopts->allocated < ipar) extend_parameter_bindings(apdopts, ipar); 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--; /* store the given info */ apdopts->parameters[ipar].buflen = cbValueMax; apdopts->parameters[ipar].buffer = rgbValue; apdopts->parameters[ipar].used = apdopts->parameters[ipar].indicator = pcbValue; apdopts->parameters[ipar].CType = fCType; ipdopts->parameters[ipar].SQLType = fSqlType; ipdopts->parameters[ipar].paramType = fParamType; ipdopts->parameters[ipar].column_size = cbColDef; ipdopts->parameters[ipar].decimal_digits = ibScale; ipdopts->parameters[ipar].precision = 0; ipdopts->parameters[ipar].scale = 0; if (0 == ipdopts->parameters[ipar].PGType) ipdopts->parameters[ipar].PGType = sqltype_to_pgtype(stmt, fSqlType);#if (ODBCVER >= 0x0300) switch (fCType) { case SQL_C_NUMERIC: if (cbColDef > 0) ipdopts->parameters[ipar].precision = (UInt2) cbColDef; if (ibScale > 0) ipdopts->parameters[ipar].scale = ibScale; break; case SQL_C_TYPE_TIMESTAMP: if (ibScale > 0) ipdopts->parameters[ipar].precision = ibScale; break; } apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision; apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;#endif /* ODBCVER */ /* * If rebinding a parameter that had data-at-exec stuff in it, then * free that stuff */ 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; } if (pcbValue && apdopts->param_offset_ptr) pcbValue = LENADDR_SHIFT(pcbValue, *apdopts->param_offset_ptr);#ifdef NOT_USED /* evaluation of pcbValue here is dangerous */ /* Data at exec macro only valid for C char/binary data */ if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC || *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)) apdopts->parameters[ipar].data_at_exec = TRUE; else apdopts->parameters[ipar].data_at_exec = FALSE;#endif /* NOT_USED */ /* Clear premature result */ if (stmt->status == STMT_PREMATURE) SC_recycle_statement(stmt); mylog("%s: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d,", func, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale); /*** mylog("rgbValue=%p, pcbValue = %p(%d), data_at_exec = %d\n", rgbValue, pcbValue, pcbValue ? *pcbValue : -777, apdopts->parameters[ipar].data_at_exec); ***/ mylog("rgbValue=%p, pcbValue = %p, data_at_exec = %d\n", rgbValue, pcbValue, apdopts->parameters[ipar].data_at_exec); return SQL_SUCCESS;}/* Associate a user-supplied buffer with a database column. */RETCODE SQL_APIPGAPI_BindCol( HSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, PTR rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue){ StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_BindCol"; ARDFields *opts; GetDataInfo *gdata_info; BindInfoClass *bookmark; RETCODE ret = SQL_SUCCESS; mylog("%s: entering...\n", func); mylog("**** PGAPI_BindCol: stmt = %p, icol = %d\n", stmt, icol); mylog("**** : fCType=%d rgb=%p valusMax=%d pcb=%p\n", fCType, rgbValue, cbValueMax, pcbValue); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } 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.", func); return SQL_ERROR; }#define return DONT_CALL_RETURN_FROM_HERE ??? SC_clear_error(stmt); /* If the bookmark column is being bound, then just save it */ if (icol == 0) { bookmark = opts->bookmark; if (rgbValue == NULL) { if (bookmark) { bookmark->buffer = NULL; bookmark->used = bookmark->indicator = NULL; } } else { /* Make sure it is the bookmark data type */ switch (fCType) { case SQL_C_BOOKMARK:#if (ODBCVER >= 0x0300) case SQL_C_VARBOOKMARK:#endif /* ODBCVER */ break; default: SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK", func);inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType); ret = SQL_ERROR; goto cleanup; } bookmark = ARD_AllocBookmark(opts); bookmark->buffer = rgbValue; bookmark->used = bookmark->indicator = pcbValue; bookmark->buflen = cbValueMax; bookmark->returntype = fCType; } goto cleanup; } /* * Allocate enough bindings if not already done. Most likely, * execution of a statement would have setup the necessary bindings. * But some apps call BindCol before any statement is executed. */ 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) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.", func); ret = SQL_ERROR; goto cleanup; } /* use zero based col numbers from here out */ icol--; /* Reset for SQLGetData */ gdata_info->gdata[icol].data_left = -1; if (rgbValue == NULL) { /* we have to unbind the column */ opts->bindings[icol].buflen = 0; opts->bindings[icol].buffer = NULL; opts->bindings[icol].used = opts->bindings[icol].indicator = NULL; opts->bindings[icol].returntype = SQL_C_CHAR; 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 { /* ok, bind that column */ opts->bindings[icol].buflen = cbValueMax; opts->bindings[icol].buffer = rgbValue; opts->bindings[icol].used = opts->bindings[icol].indicator = pcbValue; opts->bindings[icol].returntype = fCType;#if (ODBCVER >= 0x0300) if (SQL_C_NUMERIC == fCType) opts->bindings[icol].precision = 32; else#endif /* ODBCVER */ opts->bindings[icol].precision = 0; opts->bindings[icol].scale = 0; mylog(" bound buffer[%d] = %p\n", icol, opts->bindings[icol].buffer); }cleanup:#undef return if (stmt->internal) ret = DiscardStatementSvp(stmt, ret, FALSE); return ret;}/* * Returns the description of a parameter marker. * This function is listed as not being supported by SQLGetFunctions() because it is * used to describe "parameter markers" (not bound parameters), in which case, * the dbms should return info on the markers. Since Postgres doesn't support that, * it is best to say this function is not supported and let the application assume a * data type (most likely varchar). */RETCODE SQL_APIPGAPI_DescribeParam( HSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR * pfSqlType, SQLULEN FAR * pcbParamDef, SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable){ StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_DescribeParam"; APDFields *apdopts; IPDFields *ipdopts; RETCODE ret = SQL_SUCCESS; int num_params; mylog("%s: entering...%d\n", func, ipar); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } SC_clear_error(stmt); apdopts = SC_get_APDF(stmt); ipdopts = SC_get_IPDF(stmt); /*if ((ipar < 1) || (ipar > ipdopts->allocated))*/ num_params = stmt->num_params; if (num_params < 0) { SQLSMALLINT num_p; PGAPI_NumParams(stmt, &num_p); num_params = num_p; } if ((ipar < 1) || (ipar > num_params)) {inolog("num_params=%d\n", stmt->num_params); SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.", func); return SQL_ERROR; } extend_iparameter_bindings(ipdopts, stmt->num_params);#define return DONT_CALL_RETURN_FROM_HERE??? /* StartRollbackState(stmt); */ if (NOT_YET_PREPARED == stmt->prepared) { decideHowToPrepare(stmt, FALSE);inolog("howTo=%d\n", SC_get_prepare_method(stmt)); switch (SC_get_prepare_method(stmt)) { case NAMED_PARSE_REQUEST: case PARSE_TO_EXEC_ONCE: case PARSE_REQ_FOR_INFO: if (ret = prepareParameters(stmt), SQL_ERROR == ret) goto cleanup; } } ipar--; /* * This implementation is not very good, since it is supposed to * describe */ /* parameter markers, not bound parameters. */ if (pfSqlType) {inolog("[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType,ipdopts->parameters[ipar].PGType); if (ipdopts->parameters[ipar].SQLType) *pfSqlType = ipdopts->parameters[ipar].SQLType; else if (ipdopts->parameters[ipar].PGType) *pfSqlType = pgtype_to_concise_type(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC); else { ret = SQL_ERROR; SC_set_error(stmt, STMT_EXEC_ERROR, "Unfortunatley couldn't get this paramater's info", func); goto cleanup; } } if (pcbParamDef) { *pcbParamDef = 0; if (ipdopts->parameters[ipar].SQLType) *pcbParamDef = ipdopts->parameters[ipar].column_size; if (0 == *pcbParamDef && ipdopts->parameters[ipar].PGType) *pcbParamDef = pgtype_column_size(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC, PG_STATIC); } if (pibScale) { *pibScale = 0; if (ipdopts->parameters[ipar].SQLType) *pibScale = ipdopts->parameters[ipar].decimal_digits; else if (ipdopts->parameters[ipar].PGType) *pibScale = pgtype_scale(stmt, ipdopts->parameters[ipar].PGType, -1); } if (pfNullable) *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);cleanup:#undef return if (stmt->internal) ret = DiscardStatementSvp(stmt, ret, FALSE); return ret;}#if (ODBCVER < 0x0300)/* Sets multiple values (arrays) for the set of parameter markers. */RETCODE SQL_APIPGAPI_ParamOptions( HSTMT hstmt, SQLULEN crow, SQLULEN FAR * pirow){ CSTR func = "PGAPI_ParamOptions"; StatementClass *stmt = (StatementClass *) hstmt; APDFields *apdopts; IPDFields *ipdopts; mylog("%s: entering... %d %p\n", func, crow, pirow); apdopts = SC_get_APDF(stmt); apdopts->paramset_size = crow; ipdopts = SC_get_IPDF(stmt); ipdopts->param_processed_ptr = pirow; return SQL_SUCCESS;}#endif /* ODBCVER *//* * This function should really talk to the dbms to determine the number of * "parameter markers" (not bound parameters) in the statement. But, since * Postgres doesn't support that, the driver should just count the number of markers * and return that. The reason the driver just can't say this function is unsupported * like it does for SQLDescribeParam is that some applications don't care and try * to call it anyway. * If the statement does not have parameters, it should just return 0. */RETCODE SQL_APIPGAPI_NumParams( HSTMT hstmt, SQLSMALLINT FAR * pcpar){ StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_NumParams"; char literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, dollar_quote = DOLLAR_QUOTE; mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } if (pcpar) *pcpar = 0; else { SC_set_error(stmt, STMT_EXEC_ERROR, "parameter count address is null", func); return SQL_ERROR; }inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return); if (stmt->num_params >= 0) *pcpar = stmt->num_params; else if (!stmt->statement) { /* no statement has been allocated */ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.", func); return SQL_ERROR; } else { char multi = FALSE, proc_return = 0; stmt->proc_return = 0; SC_scanQueryAndCountParams(stmt->statement, SC_get_conn(stmt), NULL, pcpar, &multi, &proc_return); stmt->num_params = *pcpar; stmt->proc_return = proc_return; stmt->multi_statement = multi; if (multi) SC_no_parse_tricky(stmt); }inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return); return SQL_SUCCESS;}/* * Bindings Implementation */static BindInfoClass *create_empty_bindings(int num_columns){ BindInfoClass *new_bindings; int i; new_bindings = (BindInfoClass *) malloc(num_columns * sizeof(BindInfoClass)); if (!new_bindings) return NULL; for (i = 0; i < num_columns; i++) { new_bindings[i].buflen = 0; new_bindings[i].buffer = NULL; new_bindings[i].used = new_bindings[i].indicator = NULL; } return new_bindings;}voidextend_parameter_bindings(APDFields *self, int num_params){ CSTR func = "extend_parameter_bindings"; ParameterInfoClass *new_bindings; mylog("%s: entering ... self=%p, parameters_allocated=%d, num_params=%d,%p\n", func, self, self->allocated, num_params, self->parameters); /* * if we have too few, allocate room for more, and copy the old * entries into the new structure */ if (self->allocated < num_params) { new_bindings = (ParameterInfoClass *) realloc(self->parameters, sizeof(ParameterInfoClass) * num_params); if (!new_bindings) { mylog("%s: unable to create %d new bindings from %d old bindings\n", func, num_params, self->allocated); self->parameters = NULL; self->allocated = 0; return; } memset(&new_bindings[self->allocated], 0, sizeof(ParameterInfoClass) * (num_params - self->allocated));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -