execute.c

来自「postgresql-odbc,跨平台应用」· C语言 代码 · 共 1,696 行 · 第 1/3 页

C
1,696
字号
/*------- * Module:			execute.c * * Description:		This module contains routines related to *					preparing and executing an SQL statement. * * Classes:			n/a * * API functions:	SQLPrepare, SQLExecute, SQLExecDirect, SQLTransact, *					SQLCancel, SQLNativeSql, SQLParamData, SQLPutData * * Comments:		See "notice.txt" for copyright and license information. *------- */#include "psqlodbc.h"#include "misc.h"#include <stdio.h>#include <string.h>#ifndef	WIN32#include <ctype.h>#endif /* WIN32 */#include "environ.h"#include "connection.h"#include "statement.h"#include "qresult.h"#include "convert.h"#include "bind.h"#include "pgtypes.h"#include "lobj.h"#include "pgapifunc.h"/*extern GLOBAL_VALUES globals;*//*		Perform a Prepare on the SQL statement */RETCODE		SQL_APIPGAPI_Prepare(HSTMT hstmt,			  const SQLCHAR FAR * szSqlStr,			  SQLINTEGER cbSqlStr){	CSTR func = "PGAPI_Prepare";	StatementClass *self = (StatementClass *) hstmt;	RETCODE	retval = SQL_SUCCESS;	mylog("%s: entering...\n", func);#define	return	DONT_CALL_RETURN_FROM_HERE???	/* StartRollbackState(self); */	if (!self)	{		SC_log_error(func, "", NULL);		retval = SQL_INVALID_HANDLE;		goto cleanup;	}	/*	 * According to the ODBC specs it is valid to call SQLPrepare multiple	 * times. In that case, the bound SQL statement is replaced by the new	 * one	 */	SC_set_prepared(self, NOT_YET_PREPARED);	switch (self->status)	{		case STMT_PREMATURE:			mylog("**** PGAPI_Prepare: STMT_PREMATURE, recycle\n");			SC_recycle_statement(self); /* recycle the statement, but do										 * not remove parameter bindings */			break;		case STMT_FINISHED:			mylog("**** PGAPI_Prepare: STMT_FINISHED, recycle\n");			SC_recycle_statement(self); /* recycle the statement, but do										 * not remove parameter bindings */			break;		case STMT_ALLOCATED:			mylog("**** PGAPI_Prepare: STMT_ALLOCATED, copy\n");			self->status = STMT_READY;			break;		case STMT_READY:			mylog("**** PGAPI_Prepare: STMT_READY, change SQL\n");			break;		case STMT_EXECUTING:			mylog("**** PGAPI_Prepare: STMT_EXECUTING, error!\n");			SC_set_error(self, STMT_SEQUENCE_ERROR, "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed", func);			retval = SQL_ERROR;			goto cleanup;		default:			SC_set_error(self, STMT_INTERNAL_ERROR, "An Internal Error has occured -- Unknown statement status.", func);			retval = SQL_ERROR;			goto cleanup;	}	SC_initialize_stmts(self, TRUE);	if (!szSqlStr)	{		SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL", func);		retval = SQL_ERROR;		goto cleanup;	}	if (!szSqlStr[0])		self->statement = strdup("");	else		self->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);	if (!self->statement)	{		SC_set_error(self, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func);		retval = SQL_ERROR;		goto cleanup;	}	self->prepare = PREPARE_STATEMENT;	self->statement_type = statement_type(self->statement);	/* Check if connection is onlyread (only selects are allowed) */	if (CC_is_onlyread(SC_get_conn(self)) && STMT_UPDATE(self))	{		SC_set_error(self, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func);		retval = SQL_ERROR;		goto cleanup;	}cleanup:#undef	returninolog("SQLPrepare return=%d\n", retval);	if (self->internal)		retval = DiscardStatementSvp(self, retval, FALSE);	return retval;}/*		Performs the equivalent of SQLPrepare, followed by SQLExecute. */RETCODE		SQL_APIPGAPI_ExecDirect(				 HSTMT hstmt,				 const SQLCHAR FAR * szSqlStr,				 SQLINTEGER cbSqlStr,				 UWORD flag){	StatementClass *stmt = (StatementClass *) hstmt;	RETCODE		result;	CSTR func = "PGAPI_ExecDirect";	const ConnectionClass	*conn = SC_get_conn(stmt);	mylog("%s: entering...%x\n", func, flag);	if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)		return result;	/*	 * keep a copy of the un-parametrized statement, in case they try to	 * execute this statement again	 */	stmt->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);inolog("a2\n");	if (!stmt->statement)	{		SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func);		return SQL_ERROR;	}	mylog("**** %s: hstmt=%p, statement='%s'\n", func, hstmt, stmt->statement);	if (0 != (flag & PODBC_WITH_HOLD))		SC_set_with_hold(stmt);	/*	 * If an SQLPrepare was performed prior to this, but was left in the	 * premature state because an error occurred prior to SQLExecute then	 * set the statement to finished so it can be recycled.	 */	if (stmt->status == STMT_PREMATURE)		stmt->status = STMT_FINISHED;	stmt->statement_type = statement_type(stmt->statement);	/* Check if connection is onlyread (only selects are allowed) */	if (CC_is_onlyread(conn) && STMT_UPDATE(stmt))	{		SC_set_error(stmt, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func);		return SQL_ERROR;	}	mylog("%s: calling PGAPI_Execute...\n", func);	flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0;	result = PGAPI_Execute(hstmt, flag);	mylog("%s: returned %hd from PGAPI_Execute\n", func, result);	return result;}static intinquireHowToPrepare(const StatementClass *stmt){	ConnectionClass	*conn;	ConnInfo	*ci;	int		ret = 0;	conn = SC_get_conn(stmt);	ci = &(conn->connInfo);	if (!ci->use_server_side_prepare ||		PG_VERSION_LT(conn, 7.3))	{		/* Do prepare operations by the driver itself */		return PREPARE_BY_THE_DRIVER;	}	if (NOT_YET_PREPARED == stmt->prepared)	{		SQLSMALLINT	num_params;		if (STMT_TYPE_DECLARE == stmt->statement_type &&		    PG_VERSION_LT(conn, 8.0))		{			return PREPARE_BY_THE_DRIVER;		}		if (stmt->multi_statement < 0)			PGAPI_NumParams((StatementClass *) stmt, &num_params);		if (stmt->multi_statement > 0) /* would divide the query into multiple commands and apply V3 parse requests for each of them */			ret = PARSE_REQ_FOR_INFO;		else if (PROTOCOL_74(ci))		{			if (STMT_TYPE_SELECT == stmt->statement_type)			{				if (ci->drivers.use_declarefetch)					return PARSE_REQ_FOR_INFO;				else if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)					ret = PARSE_REQ_FOR_INFO;				else					ret = PARSE_TO_EXEC_ONCE;			}			else				ret = PARSE_TO_EXEC_ONCE;		}		else		{			if (STMT_TYPE_SELECT == stmt->statement_type &&			    (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type ||			    ci->drivers.use_declarefetch))				ret = PREPARE_BY_THE_DRIVER;			else				ret = USING_PREPARE_COMMAND;		}	}	if (SC_is_prepare_statement(stmt) && (PARSE_TO_EXEC_ONCE == ret))		ret = NAMED_PARSE_REQUEST;	return ret;}intdecideHowToPrepare(StatementClass *stmt, BOOL force){	int	method = SC_get_prepare_method(stmt);	if (0 != method) /* a method was already determined */		return method;	if (stmt->inaccurate_result)		return method;	switch (stmt->prepare)	{		case NON_PREPARE_STATEMENT: /* not a prepare statement */			if (!force)				return method;			break;	}	method = inquireHowToPrepare(stmt);	stmt->prepare |= method;	if (PREPARE_BY_THE_DRIVER == method)		stmt->discard_output_params = 1;	return method;}/* *	The execution after all parameters were resolved. */staticRETCODE	Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end){	CSTR func = "Exec_with_parameters_resolved";	RETCODE		retval;	SQLLEN		end_row;	SQLINTEGER	cursor_type, scroll_concurrency;	ConnectionClass	*conn;	QResultClass	*res;	APDFields	*apdopts;	IPDFields	*ipdopts;	BOOL		prepare_before_exec = FALSE;	*exec_end = FALSE;	conn = SC_get_conn(stmt);	mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement);	/* save the cursor's info before the execution */	cursor_type = stmt->options.cursor_type;	scroll_concurrency = stmt->options.scroll_concurrency;	/* Prepare the statement if possible at backend side */	if (!stmt->inaccurate_result)	{		switch (decideHowToPrepare(stmt, FALSE))		{			case USING_PREPARE_COMMAND:			case NAMED_PARSE_REQUEST:#ifndef	BYPASS_ONESHOT_PLAN_EXECUTION			case PARSE_TO_EXEC_ONCE:#endif/* BYPASS_ONESHOT_PLAN_EXECUTION */				prepare_before_exec = TRUE;		}	}inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare);	/* Create the statement with parameters substituted. */	retval = copy_statement_with_parameters(stmt, prepare_before_exec);	stmt->current_exec_param = -1;	if (retval != SQL_SUCCESS)	{		stmt->exec_current_row = -1;		*exec_end = TRUE;		return retval; /* error msg is passed from the above */	}	mylog("   stmt_with_params = '%s'\n", stmt->stmt_with_params);	/*	 *	Dummy exection to get the column info.	 */ 	if (stmt->inaccurate_result && SC_is_parse_tricky(stmt))	{		BOOL		in_trans = CC_is_in_trans(conn);		BOOL		issued_begin = FALSE,					begin_included = FALSE;		QResultClass *curres;		stmt->exec_current_row = -1;		*exec_end = TRUE;		if (!SC_is_pre_executable(stmt))			return SQL_SUCCESS;		if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)			begin_included = TRUE;		else if (!in_trans)		{			if (issued_begin = CC_begin(conn), !issued_begin)			{				SC_set_error(stmt, STMT_EXEC_ERROR,  "Handle prepare error", func);				return SQL_ERROR;			}		}		/* we are now in a transaction */		res = CC_send_query(conn, stmt->stmt_with_params, NULL, 0, SC_get_ancestor(stmt));		if (!QR_command_maybe_successful(res))		{#ifndef	_LEGACY_MODE_			if (PG_VERSION_LT(conn, 8.0))				CC_abort(conn);#endif /* LEGACY_MODE_ */			SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func);			QR_Destructor(res);			return SQL_ERROR;		}		SC_set_Result(stmt, res);		for (curres = res; !curres->num_fields; curres = curres->next)			;		SC_set_Curres(stmt, curres);		if (CC_is_in_autocommit(conn))		{			if (issued_begin)				CC_commit(conn);		}		stmt->status = STMT_FINISHED;		return SQL_SUCCESS;	}	/*	 *	The real execution.	 */mylog("about to begin SC_execute\n");	retval = SC_execute(stmt);	if (retval == SQL_ERROR)	{		stmt->exec_current_row = -1;		*exec_end = TRUE;		return retval;	}	res = SC_get_Result(stmt);	/* special handling of result for keyset driven cursors */	if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&	    SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)	{		QResultClass	*kres;		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;			res->next = NULL;			SC_set_Result(stmt, kres);			res = kres;		}	}#ifdef	NOT_USED	else if (SC_is_concat_prepare_exec(stmt))	{		if (res && QR_command_maybe_successful(res))		{			QResultClass	*kres;					kres = res->next;inolog("res->next=%p\n", kres);			res->next = NULL;			SC_set_Result(stmt, kres);			res = kres;			SC_set_prepared(stmt, PREPARED_PERMANENTLY);		}		else		{			retval = SQL_ERROR;			if (stmt->execute_statement)				free(stmt->execute_statement);			stmt->execute_statement = NULL;		}	}#endif /* NOT_USED */#if (ODBCVER >= 0x0300)	ipdopts = SC_get_IPDF(stmt);	if (ipdopts->param_status_ptr)	{		switch (retval)		{			case SQL_SUCCESS: 				ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;				break;			case SQL_SUCCESS_WITH_INFO: 				ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;				break;			default: 				ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;				break;		}	}#endif /* ODBCVER */	if (end_row = stmt->exec_end_row, end_row < 0)	{		apdopts = SC_get_APDF(stmt);		end_row = (SQLINTEGER) apdopts->paramset_size - 1;	}	if (stmt->inaccurate_result ||	    stmt->exec_current_row >= end_row)	{		*exec_end = TRUE;		stmt->exec_current_row = -1;	}	else		stmt->exec_current_row++;	if (res)	{#if (ODBCVER >= 0x0300)		EnvironmentClass *env = (EnvironmentClass *) (conn->henv);		const char *cmd = QR_get_command(res);		if (retval == SQL_SUCCESS && cmd && env && EN_is_odbc3(env))		{			int     count;			if (sscanf(cmd , "UPDATE %d", &count) == 1)				;			else if (sscanf(cmd , "DELETE %d", &count) == 1)				;			else				count = -1;			if (0 == count)				retval = SQL_NO_DATA;		}#endif /* ODBCVER */		stmt->diag_row_count = res->recent_processed_row_count;	}	/*	 *	The cursor's info was changed ?	 */	if (retval == SQL_SUCCESS &&	    (stmt->options.cursor_type != cursor_type ||	     stmt->options.scroll_concurrency != scroll_concurrency))	{		SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed", func);		retval = SQL_SUCCESS_WITH_INFO;	}	return retval;}intStartRollbackState(StatementClass *stmt){	CSTR	func = "StartRollbackState";	int	ret;	ConnectionClass	*conn;	ConnInfo	*ci = NULL;	inolog("%s:%p->internal=%d\n", func, stmt, stmt->internal);	conn = SC_get_conn(stmt);	if (conn)		ci = &conn->connInfo;	ret = 0;	if (!ci || ci->rollback_on_error < 0) /* default */	{		if (conn && PG_VERSION_GE(conn, 8.0))			ret = 2; /* statement rollback */		else			ret = 1; /* transaction rollback */	}	else	{		ret = ci->rollback_on_error;		if (2 == ret && PG_VERSION_LT(conn, 8.0))			ret = 1;	}	switch (ret)	{		case 1:			SC_start_tc_stmt(stmt);			break;		case 2:			SC_start_rb_stmt(stmt);			break;	}	return	ret;}/* *	Must be in a transaction or the subsequent execution *	invokes a transaction. */RETCODESetStatementSvp(StatementClass *stmt){	CSTR	func = "SetStatementSvp";	char	esavepoint[32], cmd[64];	ConnectionClass	*conn = SC_get_conn(stmt);	QResultClass *res;	RETCODE	ret = SQL_SUCCESS_WITH_INFO;	if (CC_is_in_error_trans(conn))		return ret;	if (0 == stmt->lock_CC_for_rb)	{		ENTER_CONN_CS(conn);		stmt->lock_CC_for_rb++;	}	switch (stmt->statement_type)	{		case STMT_TYPE_SPECIAL:		case STMT_TYPE_TRANSACTION:			return ret;	}	if (!SC_accessed_db(stmt))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?