execute.c

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

C
1,696
字号
	{		BOOL	need_savep = FALSE;		if (stmt->internal)		{			if (PG_VERSION_GE(conn, 8.0))				SC_start_rb_stmt(stmt);			else				SC_start_tc_stmt(stmt);		}		if (SC_is_rb_stmt(stmt))		{			if (CC_is_in_trans(conn))			{				need_savep = TRUE;			}		}		if (need_savep)		{			sprintf(esavepoint, "_EXEC_SVP_%p", stmt);			snprintf(cmd, sizeof(cmd), "SAVEPOINT %s", esavepoint);			res = CC_send_query(conn, cmd, NULL, 0, NULL);			if (QR_command_maybe_successful(res))			{				SC_set_accessed_db(stmt);				SC_start_rbpoint(stmt);				ret = SQL_SUCCESS;			}			else			{				SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal SAVEPOINT failed", func);				ret = SQL_ERROR;			}			QR_Destructor(res);		}		else			SC_set_accessed_db(stmt);	}inolog("%s:%p->accessed=%d\n", func, stmt, SC_accessed_db(stmt));	return ret;}RETCODEDiscardStatementSvp(StatementClass *stmt, RETCODE ret, BOOL errorOnly){	CSTR	func = "DiscardStatementSvp";	char	esavepoint[32], cmd[64];	ConnectionClass	*conn = SC_get_conn(stmt);	QResultClass *res;	BOOL	cmd_success, start_stmt = FALSE;	inolog("%s:%p->accessed=%d is_in=%d is_rb=%d is_tc=%d\n", func, stmt, SC_accessed_db(stmt),CC_is_in_trans(conn), SC_is_rb_stmt(stmt), SC_is_tc_stmt(stmt));	switch (ret)	{		case SQL_NEED_DATA:			break;		case SQL_ERROR:			start_stmt = TRUE;			break;		default:			if (!errorOnly)				start_stmt = TRUE;			break;	}	if (!SC_accessed_db(stmt) || !CC_is_in_trans(conn))		goto cleanup;	if (!SC_is_rb_stmt(stmt) && !SC_is_tc_stmt(stmt))		goto cleanup;	sprintf(esavepoint, "_EXEC_SVP_%p", stmt);	if (SQL_ERROR == ret)	{		if (SC_started_rbpoint(stmt))		{			snprintf(cmd, sizeof(cmd), "ROLLBACK to %s", esavepoint);			res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL);			cmd_success = QR_command_maybe_successful(res);			QR_Destructor(res);			if (!cmd_success)			{				SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal ROLLBACK failed", func);				CC_abort(conn);				goto cleanup;			}		}		else		{			CC_abort(conn);			goto cleanup;		}	}	else if (errorOnly)		return ret;inolog("ret=%d\n", ret);	if (SQL_NEED_DATA != ret && SC_started_rbpoint(stmt))	{		snprintf(cmd, sizeof(cmd), "RELEASE %s", esavepoint);		res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL);		cmd_success = QR_command_maybe_successful(res);		QR_Destructor(res);		if (!cmd_success)		{			SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal RELEASE failed", func);			CC_abort(conn);			ret = SQL_ERROR;		}	}cleanup:	if (SQL_NEED_DATA != ret)		SC_forget_unnamed(stmt); /* unnamed plan is no longer reliable */	if (!SC_is_prepare_statement(stmt) && ONCE_DESCRIBED == stmt->prepared)		SC_set_prepared(stmt, NOT_YET_PREPARED);	if (start_stmt || SQL_ERROR == ret)	{		if (stmt->lock_CC_for_rb > 0)		{			LEAVE_CONN_CS(conn);			stmt->lock_CC_for_rb--;		}		SC_start_stmt(stmt);	}	return ret;}voidSC_setInsertedTable(StatementClass *stmt, RETCODE retval){	const char *cmd = stmt->statement, *ptr;	ConnectionClass	*conn;	size_t	len;	if (STMT_TYPE_INSERT != stmt->statement_type)		return;	if (SQL_NEED_DATA == retval)		return;	conn = SC_get_conn(stmt);#ifdef	NOT_USED /* give up the use of lastval() */		if (PG_VERSION_GE(conn, 8.1)) /* lastval() is available */		return;#endif /* NOT_USED */	/*if (!CC_fake_mss(conn))		return;*/	while (isspace((UCHAR) *cmd)) cmd++;	if (!*cmd)        	return;	len = 6;	if (strnicmp(cmd, "insert", len))        	return;	cmd += len;	while (isspace((UCHAR) *(++cmd)));	if (!*cmd)        	return;	len = 4;	if (strnicmp(cmd, "into", len))        	return;	cmd += len;	while (isspace((UCHAR) *(++cmd)));	if (!*cmd)        	return;	NULL_THE_NAME(conn->schemaIns);	NULL_THE_NAME(conn->tableIns);	if (!SQL_SUCCEEDED(retval))		return;	ptr = NULL;	if (IDENTIFIER_QUOTE == *cmd)	{		if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)			return;		if ('.' == ptr[1])		{			len = ptr - cmd - 1;			STRN_TO_NAME(conn->schemaIns, cmd + 1, len);			cmd = ptr + 2;			ptr = NULL;		}	}	else	{		if (ptr = strchr(cmd + 1, '.'), NULL != ptr)		{			len = ptr - cmd;			STRN_TO_NAME(conn->schemaIns, cmd, len);			cmd = ptr + 1;			ptr = NULL; 		}	}	if (IDENTIFIER_QUOTE == *cmd && NULL == ptr)	{		if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)			return;	}	if (IDENTIFIER_QUOTE == *cmd)	{		len = ptr - cmd - 1;		STRN_TO_NAME(conn->tableIns, cmd + 1, len);	}	else	{		ptr = cmd;		while (*ptr && !isspace((UCHAR) *ptr)) ptr++;		len = ptr - cmd;		STRN_TO_NAME(conn->tableIns, cmd, len);	}}/*	Execute a prepared SQL statement */RETCODE		SQL_APIPGAPI_Execute(HSTMT hstmt, UWORD flag){	CSTR func = "PGAPI_Execute";	StatementClass *stmt = (StatementClass *) hstmt;	RETCODE		retval = SQL_SUCCESS;	ConnectionClass	*conn;	APDFields	*apdopts;	IPDFields	*ipdopts;	SQLLEN		i, start_row, end_row;	BOOL	exec_end, recycled = FALSE, recycle = TRUE;	SQLSMALLINT	num_params;	mylog("%s: entering...%x\n", func, flag);	if (!stmt)	{		SC_log_error(func, "", NULL);		mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func);		return SQL_INVALID_HANDLE;	}	conn = SC_get_conn(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	 * success.	 */	if (stmt->prepare && stmt->status == STMT_PREMATURE)	{		if (stmt->inaccurate_result)		{			stmt->exec_current_row = -1;			SC_recycle_statement(stmt);		}		else		{			stmt->status = STMT_FINISHED;			if (NULL == SC_get_errormsg(stmt))			{				mylog("%s: premature statement but return SQL_SUCCESS\n", func);				retval = SQL_SUCCESS;				goto cleanup;			}			else			{				SC_set_error(stmt,STMT_INTERNAL_ERROR, "premature statement so return SQL_ERROR", func);				retval = SQL_ERROR;				goto cleanup;			}		}	}	mylog("%s: clear errors...\n", func);	SC_clear_error(stmt);	if (!stmt->statement)	{		SC_set_error(stmt, STMT_NO_STMTSTRING, "This handle does not have a SQL statement stored in it", func);		mylog("%s: problem with handle\n", func);		return SQL_ERROR;	}#define	return	DONT_CALL_RETURN_FROM_HERE???	if (stmt->exec_current_row > 0)	{		/*		 * executing an array of parameters.		 * Don't recycle the statement.		 */		recycle = FALSE;	}	else if (PREPARED_PERMANENTLY == stmt->prepared ||		 PREPARED_TEMPORARILY == stmt->prepared)	{		QResultClass	*res;		/*		 * re-executing an prepared statement.		 * Don't recycle the statement but		 * discard the old result.		 */		recycle = FALSE;		if (res = SC_get_Result(stmt), res)        		QR_close_result(res, FALSE);	}	/*	 * If SQLExecute is being called again, recycle the statement. Note	 * this should have been done by the application in a call to	 * SQLFreeStmt(SQL_CLOSE) or SQLCancel.	 */	else if (stmt->status == STMT_FINISHED)	{		mylog("%s: recycling statement (should have been done by app)...\n", func);/******** Is this really NEEDED ? ******/		SC_recycle_statement(stmt);		recycled = TRUE;	}	/* Check if the statement is in the correct state */	else if ((stmt->prepare && stmt->status != STMT_READY) ||		(stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY))	{		SC_set_error(stmt, STMT_STATUS_ERROR, "The handle does not point to a statement that is ready to be executed", func);		mylog("%s: problem with statement\n", func);		retval = SQL_ERROR;		goto cleanup;	}	if (start_row = stmt->exec_start_row, start_row < 0)		start_row = 0; 	if (end_row = stmt->exec_end_row, end_row < 0)		end_row = (SQLINTEGER) apdopts->paramset_size - 1; 	if (stmt->exec_current_row < 0)		stmt->exec_current_row = start_row;	ipdopts = SC_get_IPDF(stmt);	num_params = stmt->num_params;	if (num_params < 0)		PGAPI_NumParams(stmt, &num_params);	if (stmt->exec_current_row == start_row)	{		/*		   We sometimes need to know about the PG type of binding		   parameters even in case of non-prepared statements.		 */		BOOL	bCallPrepare = FALSE;		ConnInfo *ci = &(conn->connInfo);		if (NOT_YET_PREPARED == stmt->prepared &&		    PROTOCOL_74(ci) &&		    ci->use_server_side_prepare &&		   (ci->bytea_as_longvarbinary || /* both lo and bytea are LO */		    ci->cvt_null_date_string))		{			SQLSMALLINT	num_params = stmt->num_params;			if (num_params < 0)				PGAPI_NumParams(stmt, &num_params);			if (num_params > 0)			{				int	param_number = -1;				ParameterInfoClass *apara;				ParameterImplClass *ipara;				BOOL	reqOK = FALSE;				switch (decideHowToPrepare(stmt, TRUE))				{					case NAMED_PARSE_REQUEST:					case PARSE_TO_EXEC_ONCE:					case PARSE_REQ_FOR_INFO:						reqOK = TRUE;				}				while (reqOK)				{					SC_param_next(stmt, &param_number, &apara, &ipara);					if (!ipara || !apara)						break;					if (SQL_LONGVARBINARY == ipara->SQLType)					{						if (ci->bytea_as_longvarbinary)						{							bCallPrepare = TRUE;							break;						}					}					else if (SQL_CHAR == ipara->SQLType)					{						if (SQL_C_CHAR == apara->CType &&						    ci->cvt_null_date_string)						{							bCallPrepare = TRUE;							break;						}					}				}			}		}		if (bCallPrepare)		{			if (retval = prepareParameters(stmt), SQL_ERROR == retval)				goto cleanup;		}mylog("prepareParameters %d end\n", stmt->prepare);		if (ipdopts->param_processed_ptr)			*ipdopts->param_processed_ptr = 0;#if (ODBCVER >= 0x0300)		/*	 	 *	Initialize the param_status_ptr 	 	 */		if (ipdopts->param_status_ptr)		{			for (i = 0; i <= end_row; i++)				ipdopts->param_status_ptr[i] = SQL_PARAM_UNUSED;		}#endif /* ODBCVER */		if (recycle && !recycled)			SC_recycle_statement(stmt);	}next_param_row:#if (ODBCVER >= 0x0300)	if (apdopts->param_operation_ptr)	{		while (apdopts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)		{			if (stmt->exec_current_row >= end_row)			{				stmt->exec_current_row = -1;				retval = SQL_SUCCESS;				goto cleanup;			}			++stmt->exec_current_row;		}	}	/*	 *	Initialize the current row status 	 */	if (ipdopts->param_status_ptr)		ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;#endif /* ODBCVER */	/*	 * Check if statement has any data-at-execute parameters when it is	 * not in SC_pre_execute.	 */	if (!stmt->pre_executing)	{		/*		 * The bound parameters could have possibly changed since the last		 * execute of this statement?  Therefore check for params and		 * re-copy.		 */		SQLULEN	offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;		SQLINTEGER	bind_size = apdopts->param_bind_type;		SQLLEN		current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;		Int4	num_p = num_params < apdopts->allocated ? num_params : apdopts->allocated;		/*		 *	Increment the  number of currently processed rows 		 */		if (ipdopts->param_processed_ptr)			(*ipdopts->param_processed_ptr)++;		stmt->data_at_exec = -1;		for (i = 0; i < num_p; i++)		{			SQLLEN	   *pcVal = apdopts->parameters[i].used;			apdopts->parameters[i].data_at_exec = FALSE;			if (pcVal)			{				if (bind_size > 0)					pcVal = (SQLLEN *)((char *)pcVal + offset + bind_size * current_row);				else					pcVal = (SQLLEN *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);				if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)					apdopts->parameters[i].data_at_exec = TRUE;			}			/* Check for data at execution parameters */			if (apdopts->parameters[i].data_at_exec)			{				if (stmt->data_at_exec < 0)					stmt->data_at_exec = 1;				else					stmt->data_at_exec++;			}		}		/*		 * If there are some data at execution parameters, return need		 * data		 */		/*		 * SQLParamData and SQLPutData will be used to send params and		 * execute the statement.		 */		if (stmt->data_at_exec > 0)		{			retval = SQL_NEED_DATA;			goto cleanup;		}	}	if (0 != (flag & PODBC_WITH_HOLD))		SC_set_with_hold(stmt);	retval = Exec_with_parameters_resolved(stmt, &exec_end);	if (!exec_end)		goto next_param_row;cleanup:mylog("retval=%d\n", retval);	SC_setInsertedTable(stmt, retval);#undef	return	if (stmt->internal)		retval = DiscardStatementSvp(stmt, retval, FALSE);	return retval;}RETCODE		SQL_APIPGAPI_Transact(			   HENV henv,			   HDBC hdbc,			   SQLUSMALLINT fType){	CSTR func = "PGAPI_Transact";	ConnectionClass *conn;	QResultClass *res;	char		ok,			   *stmt_string;	int			lf;	mylog("entering %s: hdbc=%p, henv=%p\n", func, hdbc, henv);	if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV)	{		CC_log_error(func, "", NULL);		return SQL_INVALID_HANDLE;	}	/*	 * If hdbc is null and henv is valid, it means transact all	 * connections on that henv.	 */	if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV)	{		ConnectionClass * const *conns = getConnList();		const int	conn_count = getConnCount();		for (lf = 0; lf < conn_count; lf++)		{			conn = conns[lf];			if (conn && conn->henv == henv)				if (PGAPI_Transact(henv, (HDBC) conn, fType) != SQL_SUCCESS)					return SQL_ERROR;		}		return SQL_SUCCESS;	}	conn = (ConnectionClass *) hdbc;	if (fType == SQL_COMMIT)		stmt_string = "COMMIT";	else if (fType == SQL_ROLLBACK)		stmt_string = "ROLLBACK";	else	{		CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter", func);		return SQL_ERROR;	}	/* If manual commit and in transaction, then proceed. */	if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))	{		mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string);		res = CC_send_query(conn, stmt_string, NULL, 0, NULL);		ok = QR_command_maybe_successful(res);		QR_Destructor(res);		if (!ok)		{

⌨️ 快捷键说明

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