Пример #1
0
static int
inquireHowToPrepare(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 = PROTOCOL_74(ci) ? PARSE_REQ_FOR_INFO : PREPARE_BY_THE_DRIVER;
		else if (PROTOCOL_74(ci))
		{
			if (SC_may_use_cursor(stmt))
			{
				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 (SC_may_use_cursor(stmt) &&
			    (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type ||
			    ci->drivers.use_declarefetch))
				ret = PREPARE_BY_THE_DRIVER;
			else if (SC_is_prepare_statement(stmt))
				ret = USING_PREPARE_COMMAND;
			else
				ret = PREPARE_BY_THE_DRIVER;
		}
	}
	if (SC_is_prepare_statement(stmt) && (PARSE_TO_EXEC_ONCE == ret))
		ret = NAMED_PARSE_REQUEST;

	return ret;
}
Пример #2
0
RETCODE		SQL_API
SQLNumParams(HSTMT hstmt,
			 SQLSMALLINT *pcpar)
{
	RETCODE	ret;
	StatementClass *stmt = (StatementClass *) hstmt;

	mylog("[SQLNumParams]");
	ENTER_STMT_CS(stmt);
	SC_clear_error(stmt);
	StartRollbackState(stmt);
	ret = PGAPI_NumParams(hstmt, pcpar);
	ret = DiscardStatementSvp(stmt, ret, FALSE);
	LEAVE_STMT_CS(stmt);
	return ret;
}
Пример #3
0
/*	Execute a prepared SQL statement */
RETCODE		SQL_API
PGAPI_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.
		 */
		int	nCallParse = doNothing;

		if (NOT_YET_PREPARED == stmt->prepared)
		{
			switch (nCallParse = HowToPrepareBeforeExec(stmt, TRUE))
			{
				case shouldParse:
					if (retval = prepareParameters(stmt, TRUE), SQL_ERROR == retval)
						goto cleanup;
					break;
			}
		}
mylog("prepareParameters was %s called, prepare state:%d\n", shouldParse == nCallParse ? "" : "not", 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);
		if (isSqlServr() &&
		    !stmt->internal &&
		    0 != stmt->prepare &&
		    PG_VERSION_LT(conn, 8.4) &&
		    SC_can_parse_statement(stmt))
			parse_sqlsvr(stmt);
	}

	/*
	 * Clear any old result sets before executing. The prepare stage might've
	 * created one.
	 */
	SC_set_Result(stmt, NULL);

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 = LENADDR_SHIFT(pcVal, offset + bind_size * current_row);
				else
					pcVal = LENADDR_SHIFT(pcVal, offset) + 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)
			{
				mylog("The %dth parameter of %d-row is data at exec(%d)\n", i, current_row, *pcVal);
				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)
	{
		stmt->curr_param_result = 0;
		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;
}
Пример #4
0
static
int HowToPrepareBeforeExec(StatementClass *stmt, BOOL checkOnly)
{
	SQLSMALLINT	num_params = stmt->num_params;
	ConnectionClass	*conn = SC_get_conn(stmt);
	ConnInfo *ci = &(conn->connInfo);
	int		nCallParse = doNothing, how_to_prepare = 0;
	BOOL		bNeedsTrans = FALSE;

	if (num_params < 0)
		PGAPI_NumParams(stmt, &num_params);
	how_to_prepare = decideHowToPrepare(stmt, checkOnly);
	if (checkOnly)
	{
		if (num_params <= 0)
			return doNothing;
	}
	else
	{
		switch (how_to_prepare)
		{
			case USING_PREPARE_COMMAND:
				return checkOnly ? doNothing : usingCommand;
			case NAMED_PARSE_REQUEST:
				return shouldParse;
			case PARSE_TO_EXEC_ONCE:
				switch (stmt->prepared)
				{
					case PREPARED_TEMPORARILY:
						nCallParse = preferParse;
						break;
					default:
						if (num_params <= 0)
							nCallParse = NOPARAM_ONESHOT_CALL_PARSE;
						else
							nCallParse = ONESHOT_CALL_PARSE;
				}
				break;
			default:
				return doNothing;
		}
	}
	if (PG_VERSION_LE(conn, 7.3) ||
	    !PROTOCOL_74(ci))
		return nCallParse;

	if (num_params > 0)
	{
		int	param_number = -1;
		ParameterInfoClass *apara;
		ParameterImplClass *ipara;
		OID	pgtype;

		while (TRUE)
		{
			SC_param_next(stmt, &param_number, &apara, &ipara);
			if (!ipara || !apara)
				break;
			pgtype = PIC_get_pgtype(*ipara);
			if (checkOnly)
			{
				switch (ipara->SQLType)
				{
					case SQL_LONGVARBINARY:
						if (0 == pgtype)
						{
							if (ci->bytea_as_longvarbinary &&
							    0 != conn->lobj_type)
								nCallParse = shouldParse;
						}
						break;
					case SQL_CHAR:
						if (ci->cvt_null_date_string)
							nCallParse = shouldParse;
						break;
					case SQL_VARCHAR:
						if (ci->drivers.bools_as_char &&
						    PG_WIDTH_OF_BOOLS_AS_CHAR == ipara->column_size)
							nCallParse = shouldParse;
						break;
				}
			}
			else
			{
				BOOL	bBytea = FALSE;

				switch (ipara->SQLType)
				{
					case SQL_LONGVARBINARY:
						if (conn->lobj_type == pgtype ||
					    	    PG_TYPE_OID == pgtype)
							bNeedsTrans = TRUE;
						else if (PG_TYPE_BYTEA == pgtype)
							bBytea = TRUE;
						else if (0 == pgtype)
						{
							if (ci->bytea_as_longvarbinary)
								bBytea = TRUE;
							else
								bNeedsTrans = TRUE;
						}
						if (bBytea)
							if (nCallParse < preferParse)
								nCallParse = preferParse;
						break;
				}
			}
		}
	}
	if (bNeedsTrans &&
	    PARSE_TO_EXEC_ONCE == how_to_prepare)
	{
		if (!CC_is_in_trans(conn) && CC_does_autocommit(conn))
			nCallParse = doNothing;
	}
	return nCallParse;
}
Пример #5
0
/*
 *	Supplies parameter data at execution time.
 *	Used in conjuction with SQLPutData.
 */
RETCODE		SQL_API
PGAPI_ParamData(
				HSTMT hstmt,
				PTR FAR * prgbValue)
{
	CSTR func = "PGAPI_ParamData";
	StatementClass *stmt = (StatementClass *) hstmt, *estmt;
	APDFields	*apdopts;
	IPDFields	*ipdopts;
	RETCODE		retval;
	int		i;
	Int2		num_p;
	ConnectionClass	*conn = NULL;

	mylog("%s: entering...\n", func);

	if (!stmt)
	{
		SC_log_error(func, "", NULL);
		retval = SQL_INVALID_HANDLE;
		goto cleanup;
	}
	conn = SC_get_conn(stmt);

	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);

#define	return	DONT_CALL_RETURN_FROM_HERE???
	if (SC_AcceptedCancelRequest(stmt))
	{
		SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry", func);
		retval = SQL_ERROR;
		goto cleanup;
	}
	if (estmt->data_at_exec < 0)
	{
		SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement", func);
		retval = SQL_ERROR;
		goto cleanup;
	}

	if (estmt->data_at_exec > apdopts->allocated)
	{
		SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present", func);
		retval = SQL_ERROR;
		goto cleanup;
	}

	/* close the large object */
	if (estmt->lobj_fd >= 0)
	{
		odbc_lo_close(conn, estmt->lobj_fd);

		/* commit transaction if needed */
		if (!CC_cursor_count(conn) && CC_does_autocommit(conn))
		{
			if (!CC_commit(conn))
			{
				SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
				retval = SQL_ERROR;
				goto cleanup;
			}
		}
		estmt->lobj_fd = -1;
	}

	/* Done, now copy the params and then execute the statement */
	ipdopts = SC_get_IPDF(estmt);
inolog("ipdopts=%p\n", ipdopts);
	if (estmt->data_at_exec == 0)
	{
		BOOL	exec_end;
		UWORD	flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0;

		retval = Exec_with_parameters_resolved(estmt, &exec_end);
		if (exec_end)
		{
			/**SC_reset_delegate(retval, stmt);**/
			retval = dequeueNeedDataCallback(retval, stmt);
			goto cleanup;
		}
		if (retval = PGAPI_Execute(estmt, flag), SQL_NEED_DATA != retval)
		{
			goto cleanup;
		}
	}

	/*
	 * Set beginning param;  if first time SQLParamData is called , start
	 * at 0. Otherwise, start at the last parameter + 1.
	 */
	i = estmt->current_exec_param >= 0 ? estmt->current_exec_param + 1 : 0;

	num_p = estmt->num_params;
	if (num_p < 0)
		PGAPI_NumParams(estmt, &num_p);
inolog("i=%d allocated=%d num_p=%d\n", i, apdopts->allocated, num_p);
	if (num_p > apdopts->allocated)
		num_p = apdopts->allocated;
	/* At least 1 data at execution parameter, so Fill in the token value */
	for (; i < num_p; i++)
	{
inolog("i=%d", i);
		if (apdopts->parameters[i].data_at_exec)
		{
inolog(" at exec buffer=%p", apdopts->parameters[i].buffer);
			estmt->data_at_exec--;
			estmt->current_exec_param = i;
			estmt->put_data = FALSE;
			if (prgbValue)
			{
				/* returns token here */
				if (stmt->execute_delegate)
				{
					SQLULEN	offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
					SQLLEN	perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen; 

inolog(" offset=%d perrow=%d", offset, perrow);
					*prgbValue = apdopts->parameters[i].buffer + offset + estmt->exec_current_row * perrow;
				}
				else
					*prgbValue = apdopts->parameters[i].buffer;
			}
			break;
		}
inolog("\n");
	}

	retval = SQL_NEED_DATA;
inolog("return SQL_NEED_DATA\n");
cleanup:
#undef	return
	SC_setInsertedTable(stmt, retval);
	if (stmt->internal)
		retval = DiscardStatementSvp(stmt, retval, FALSE);
	mylog("%s: returning %d\n", func, retval);
	return retval;
}
Пример #6
0
/*
 *	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_API
PGAPI_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";
	IPDFields	*ipdopts;
	RETCODE		ret = SQL_SUCCESS;
	int		num_params;
	OID		pgtype;

	mylog("%s: entering...%d\n", func, ipar);

	if (!stmt)
	{
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}
	SC_clear_error(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--;
	pgtype = PIC_get_pgtype(ipdopts->parameters[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, pgtype);
		if (ipdopts->parameters[ipar].SQLType)
			*pfSqlType = ipdopts->parameters[ipar].SQLType;
		else if (pgtype)
			*pfSqlType = pgtype_to_concise_type(stmt, 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 && pgtype)
			*pcbParamDef = pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC);
	}

	if (pibScale)
	{
		*pibScale = 0;
		if (ipdopts->parameters[ipar].SQLType)
			*pibScale = ipdopts->parameters[ipar].decimal_digits;
		else if (pgtype)
			*pibScale = pgtype_scale(stmt, pgtype, -1);
	}

	if (pfNullable)
		*pfNullable = pgtype_nullable(SC_get_conn(stmt), ipdopts->parameters[ipar].paramType);
cleanup:
#undef	return
	if (stmt->internal)
		ret = DiscardStatementSvp(stmt, ret, FALSE);
	return ret;
}