⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bind.c

📁 postgresql-odbc,跨平台应用
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------- * 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 + -