Example #1
0
RETCODE SQL_API PG_SQLFreeStmt(HSTMT     hstmt,
			    UWORD     fOption)
{
static char* const func="SQLFreeStmt";
StatementClass *stmt = (StatementClass *) hstmt;

	mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption);

	if ( ! stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	if (fOption == SQL_DROP) {
		ConnectionClass *conn = stmt->hdbc;

		/* Remove the statement from the connection's statement list */
		if ( conn) {
			if ( ! CC_remove_statement(conn, stmt)) {
				SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
				SC_log_error(func, "", stmt);
				return SQL_ERROR;  /* stmt may be executing a transaction */
			}

			/*	Free any cursors and discard any result info */
			if (stmt->result) {
				QR_Destructor(stmt->result);
				stmt->result = NULL;
			}
		}

		/* Destroy the statement and free any results, cursors, etc. */
		SC_Destructor(stmt);

    } else if (fOption == SQL_UNBIND) {
		SC_unbind_cols(stmt);

    } else if (fOption == SQL_CLOSE) {
		/* this should discard all the results, but leave the statement */
		/* itself in place (it can be executed again) */
	if (!SC_recycle_statement(stmt)) {
		/*	errormsg passed in above */
			SC_log_error(func, "", stmt);
	    return SQL_ERROR;
		}

    } else if(fOption == SQL_RESET_PARAMS) {
		SC_free_params(stmt, STMT_FREE_PARAMS_ALL);

    } else {
	SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to SQLFreeStmt.");
	SC_log_error(func, "", stmt);
	return SQL_ERROR;
    }

    return SQL_SUCCESS;
}
Example #2
0
/*	If the statement does not have parameters, it should just return 0. */
RETCODE SQL_API SQLNumParams(
        HSTMT      hstmt,
        SWORD  FAR *pcpar)
{
StatementClass *stmt = (StatementClass *) hstmt;
char in_quote = FALSE;
unsigned int i;
static char* const func = "SQLNumParams";

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

	if(!stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	if (pcpar)
		*pcpar = 0;
	else {
		SC_log_error(func, "pcpar was null", stmt);
		return SQL_ERROR;
	}


	if(!stmt->statement) {
		/* no statement has been allocated */
		SC_set_error(stmt, STMT_SEQUENCE_ERROR, "SQLNumParams called with no statement ready.");
		SC_log_error(func, "", stmt);
		return SQL_ERROR;
	} else {
		size_t stlen=strlen(stmt->statement);

		for(i=0; i < stlen; i++) {

			if(stmt->statement[i] == '?' && !in_quote)
				(*pcpar)++;
			else {
				if (stmt->statement[i] == '\'')
					in_quote = (in_quote ? FALSE : TRUE);
			}
		}

		return SQL_SUCCESS;
	}
}
Example #3
0
RETCODE SQL_API SQLDescribeParam(
        HSTMT      hstmt,
        UWORD      ipar,
        SWORD  FAR *pfSqlType,
        SQLULEN    *pcbColDef,
        SWORD  FAR *pibScale,
        SWORD  FAR *pfNullable)
{
StatementClass *stmt = (StatementClass *) hstmt;
static char* const func = "SQLDescribeParam";

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

	if( ! stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	if( (ipar < 1) || (ipar > stmt->parameters_allocated) ) {
		SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for SQLDescribeParam.");
		SC_log_error(func, "", stmt);
		return SQL_ERROR;
	}

	ipar--;

	/*	This implementation is not very good, since it is supposed to describe */
	/*	parameter markers, not bound parameters.  */
	if(pfSqlType)
		*pfSqlType = stmt->parameters[ipar].SQLType;

	if(pcbColDef)
		*pcbColDef = stmt->parameters[ipar].precision;

	if(pibScale)
		*pibScale = stmt->parameters[ipar].scale;

	if(pfNullable)
		*pfNullable = pgtype_nullable(stmt, stmt->parameters[ipar].paramType);

	return SQL_SUCCESS;
}
Example #4
0
RETCODE SQL_API SQLParamOptions(
        HSTMT      hstmt,
        SQLULEN     crow,
        SQLULEN FAR *pirow)
{
static char* const func = "SQLParamOptions";

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

	SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
	return SQL_ERROR;
}
Example #5
0
/*
 *	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_API
PGAPI_NumParams(
				HSTMT hstmt,
				SQLSMALLINT FAR * pcpar)
{
	StatementClass *stmt = (StatementClass *) hstmt;
	CSTR func = "PGAPI_NumParams";

	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
	{
		po_ind_t 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;
}
Example #6
0
RETCODE SQL_API SQLSetStmtOption(
        HSTMT   hstmt,
        UWORD   fOption,
        SQLULEN  vParam)
{
static char *func="SQLSetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
char changed = FALSE;

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

    /*// thought we could fake Access out by just returning SQL_SUCCESS */
    /*// all the time, but it tries to set a huge value for SQL_MAX_LENGTH */
    /*// and expects the driver to reduce it to the real value */

	if( ! stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	return set_statement_option(NULL, stmt, fOption, vParam);
}
Example #7
0
RETCODE		SQL_API
PGAPI_Cancel(
			 HSTMT hstmt)		/* Statement to cancel. */
{
	CSTR func = "PGAPI_Cancel";
	StatementClass *stmt = (StatementClass *) hstmt, *estmt;
	ConnectionClass *conn;
	RETCODE		ret = SQL_SUCCESS;
	BOOL	entered_cs = FALSE;

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

	/* Check if this can handle canceling in the middle of a SQLPutData? */
	if (!stmt)
	{
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}
	conn = SC_get_conn(stmt);

#define	return	DONT_CALL_RETURN_FROM_HERE???
	/* StartRollbackState(stmt); */

	if (stmt->execute_delegate)
		estmt = stmt->execute_delegate;
	else
		estmt = stmt;
	/*
	 * Not in the middle of SQLParamData/SQLPutData so cancel like a
	 * close.
	 */
	if (estmt->data_at_exec < 0)
	{
		/*
		 * Tell the Backend that we're cancelling this request
		 */
		if (estmt->status == STMT_EXECUTING)
		{
			if (!CC_send_cancel_request(conn))
			{
				ret = SQL_ERROR;
			}
			goto cleanup;
		}
		/*
		 * MAJOR HACK for Windows to reset the driver manager's cursor
		 * state: Because of what seems like a bug in the Odbc driver
		 * manager, SQLCancel does not act like a SQLFreeStmt(CLOSE), as
		 * many applications depend on this behavior.  So, this brute
		 * force method calls the driver manager's function on behalf of
		 * the application.
		 */

		if (conn->driver_version < 0x0350)
		{
#ifdef WIN32
		ConnInfo   *ci = &(conn->connInfo);

		if (ci->drivers.cancel_as_freestmt)
		{
	typedef SQLRETURN (SQL_API *SQLAPIPROC)();
			HMODULE		hmodule;
			SQLAPIPROC	addr;

			hmodule = GetModuleHandle("ODBC32");
			addr = (SQLAPIPROC) GetProcAddress(hmodule, "SQLFreeStmt");
			ret = addr((char *) (stmt->phstmt) - 96, SQL_CLOSE);
		}
		else
#endif /* WIN32 */
		{
			ENTER_STMT_CS(stmt);
			entered_cs = TRUE;
			SC_clear_error(hstmt);
			ret = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
		}

		mylog("PGAPI_Cancel:  PGAPI_FreeStmt returned %d\n", ret);
		}
		goto cleanup;
	}

	/* In the middle of SQLParamData/SQLPutData, so cancel that. */
	/*
	 * Note, any previous data-at-exec buffers will be freed in the
	 * recycle
	 */
	/* if they call SQLExecDirect or SQLExecute again. */

	ENTER_STMT_CS(stmt);
	entered_cs = TRUE;
	SC_clear_error(stmt);
	estmt->data_at_exec = -1;
	estmt->current_exec_param = -1;
	estmt->put_data = FALSE;
	cancelNeedDataState(estmt);

cleanup:
#undef	return
	if (entered_cs)
	{
		if (stmt->internal)
			ret = DiscardStatementSvp(stmt, ret, FALSE);
		LEAVE_STMT_CS(stmt);
	}
	return ret;
}
Example #8
0
/*		Bind parameters on a statement handle */
RETCODE		SQL_API
PGAPI_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 (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;
		case SQL_C_INTERVAL_DAY_TO_SECOND:
		case SQL_C_INTERVAL_HOUR_TO_SECOND:
		case SQL_C_INTERVAL_MINUTE_TO_SECOND:
		case SQL_C_INTERVAL_SECOND:
				ipdopts->parameters[ipar].precision = 6;
			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(%d), pcbValue=%p\n", rgbValue, cbValueMax, pcbValue);

	return SQL_SUCCESS;
}
Example #9
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;
}
Example #10
0
/*	Associate a user-supplied buffer with a database column. */
RETCODE		SQL_API
PGAPI_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;
		opts->bindings[icol].precision = 0;
#if (ODBCVER >= 0x0300)
		switch (fCType)
		{
			case SQL_C_NUMERIC:
				opts->bindings[icol].precision = 32;
				break;
			case SQL_C_TIMESTAMP:
			case SQL_C_INTERVAL_DAY_TO_SECOND:
			case SQL_C_INTERVAL_HOUR_TO_SECOND:
			case SQL_C_INTERVAL_MINUTE_TO_SECOND:
			case SQL_C_INTERVAL_SECOND:
				opts->bindings[icol].precision = 6;
				break;
		}
#endif /* ODBCVER */
		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;
}
Example #11
0
/*		Perform a Prepare on the SQL statement */
RETCODE		SQL_API
PGAPI_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	return
inolog("SQLPrepare return=%d\n", retval);
	if (self->internal)
		retval = DiscardStatementSvp(self, retval, FALSE);
	return retval;
}
Example #12
0
RETCODE SC_execute(StatementClass *self)
{
static char* const func="SC_execute";
ConnectionClass *conn;
QResultClass *res;
char ok, was_ok, was_nonfatal;
Int2 oldstatus, numcols;
QueryInfo qi;


	conn = SC_get_conn(self);

	/*	Begin a transaction if one is not already in progress */
	/*
	 * Basically we don't have to begin a transaction in autocommit mode
	 * because Postgres backend runs in autocomit mode. We issue "BEGIN"
	 * in the following cases. 1) we use declare/fetch and the statement
	 * is SELECT (because declare/fetch must be called in a transaction).
	 * 2) we are in autocommit off state and the statement isn't of type
	 * OTHER.
	 */
	if (!self->internal && !CC_is_in_trans(conn) &&
		((globals.use_declarefetch && self->statement_type == STMT_TYPE_SELECT) || (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER)))
	{
		mylog("   about to begin a transaction on statement = %u\n", self);
		res = CC_send_query(conn, "BEGIN", NULL);
		if (QR_aborted(res)) {
			SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction");
			SC_log_error(func, "", self);
			return SQL_ERROR;
		}

		ok = QR_command_successful(res);

		mylog("SQLExecute: ok = %d, status = %d\n", ok, QR_get_status(res));

		QR_Destructor(res);

		if (!ok) {
			SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction");
			SC_log_error(func, "", self);
			return SQL_ERROR;
		}
		else
			CC_set_in_trans(conn);
	}



	oldstatus = conn->status;
	conn->status = CONN_EXECUTING;
	self->status = STMT_EXECUTING;


	/*	If it's a SELECT statement, use a cursor. */
	/*	Note that the declare cursor has already been prepended to the statement */
	/*	in copy_statement... */
	if (self->statement_type == STMT_TYPE_SELECT) {

		char fetch[128];

		mylog("       Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);


		/*	send the declare/select */
		self->result = CC_send_query(conn, self->stmt_with_params, NULL);

		if (globals.use_declarefetch && self->result != NULL &&
			QR_command_successful(self->result)) {

			QR_Destructor(self->result);

			/*	That worked, so now send the fetch to start getting data back */
			qi.result_in = NULL;
			qi.cursor = self->cursor_name;
			qi.row_size = globals.fetch_max;

			/*	Most likely the rowset size will not be set by the application until
				after the statement	is executed, so might as well use the cache size.
				The qr_next_tuple() function will correct for any discrepancies in
				sizes and adjust the cache accordingly.
			*/

			sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);

			self->result = CC_send_query( conn, fetch, &qi);
		}

		mylog("     done sending the query:\n");



	}
	else  { /* not a SELECT statement so don't use a cursor */
		mylog("      it's NOT a select statement: stmt=%u\n", self);
		self->result = CC_send_query(conn, self->stmt_with_params, NULL);

		/*	We shouldn't send COMMIT. Postgres backend does the
			autocommit if neccessary. (Zoltan, 04/26/2000)
		*/
		/*	Above seems wrong.
			Even in case of autocommit, started transactions
			must be committed. (Hiroshi, 02/11/2001)
		 */ 
		if ( ! self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
		 {                   
			res = CC_send_query(conn, "COMMIT", NULL); 
			QR_Destructor(res);
			CC_set_no_trans(conn);
		} 
	
	}

	conn->status = oldstatus;
	self->status = STMT_FINISHED;

	/*	Check the status of the result */
	if (self->result) {

		was_ok = QR_command_successful(self->result);
		was_nonfatal = QR_command_nonfatal(self->result);

		if ( was_ok)
			SC_set_errornumber(self, STMT_OK);
		else
			SC_set_errornumber(self, was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND);

		self->currTuple = -1; /* set cursor before the first tuple in the list */
		self->current_col = -1;
		self->rowset_start = -1;

		/* see if the query did return any result columns */
		numcols = QR_NumResultCols(self->result);

		/* now allocate the array to hold the binding info */
		if (numcols > 0) {
			extend_bindings(self, numcols);
			if (self->bindings == NULL) {
				SC_set_error(self, STMT_NO_MEMORY_ERROR, "Could not get enough free memory to store the binding information");
				SC_log_error(func, "", self);
				return SQL_ERROR;
			}
		}
		/* issue "ABORT" when query aborted */ 
		if (QR_get_aborted(self->result) && ! self->internal )                   
			CC_abort(conn);
	} else {		/* Bad Error -- The error message will be in the Connection */

		if (self->statement_type == STMT_TYPE_CREATE) {
			SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table");
			/*	This would allow the table to already exists, thus appending
				rows to it.  BUT, if the table didn't have the same attributes,
				it would fail.
				return SQL_SUCCESS_WITH_INFO;
			*/
		}
		else {
			SC_set_error(self, STMT_EXEC_ERROR, "Error while executing the query");
		}

		if ( ! self->internal)
			CC_abort(conn);
	}

	if (SC_get_errornumber(self) == STMT_OK)
		return SQL_SUCCESS;

	else {
		/* Modified, 2000-04-29, Zoltan */
		if (SC_get_errornumber(self) == STMT_INFO_ONLY)
		    SC_set_errormsg(self, "Error while executing the query (non-fatal)");
		else
		    SC_set_errormsg(self, "Unknown error");
		SC_log_error(func, "", self);
		return SQL_ERROR;
	}
}
Example #13
0
RETCODE
SC_fetch(StatementClass *self)
{
static char* const func = "SC_fetch";
QResultClass *res = self->result;
int retval, result;
Int2 num_cols, lf;
Oid type;
char *value;
ColumnInfoClass *ci;
/* TupleField *tupleField; */

	self->last_fetch_count = 0;
	ci = QR_get_fields(res);		/* the column info */

	mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, globals.use_declarefetch);

	if ( self->manual_result || ! globals.use_declarefetch) {

		if (self->currTuple >= QR_get_num_tuples(res) -1 ||
			(self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1)) {

			/*	if at the end of the tuples, return "no data found"
				and set the cursor past the end of the result set
			*/
			self->currTuple = QR_get_num_tuples(res);
			return SQL_NO_DATA_FOUND;
		}

		mylog("**** SQLFetch: manual_result\n");
		(self->currTuple)++;
	}
	else {

		/* read from the cache or the physical next tuple */
		retval = QR_next_tuple(res);
		if (retval < 0) {
			mylog("**** SQLFetch: end_tuples\n");
			return SQL_NO_DATA_FOUND;
		}
		else if (retval > 0)
			(self->currTuple)++;		/* all is well */

		else {
			mylog("SQLFetch: error\n");
			SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row");
			SC_log_error(func, "", self);
			return SQL_ERROR;
		}
	}

	num_cols = QR_NumResultCols(res);

	result = SQL_SUCCESS;
	self->last_fetch_count = 1;

	/*	If the bookmark column was bound then return a bookmark.
		Since this is used with SQLExtendedFetch, and the rowset size
		may be greater than 1, and an application can use row or column wise
		binding, use the code in copy_and_convert_field() to handle that.
	*/
	if (self->bookmark.buffer) {
		char buf[32];

		sprintf(buf, "%ld", SC_get_bookmark(self));
		result = copy_and_convert_field(self, 0, buf,
								SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
	}

	for (lf=0; lf < num_cols; lf++) {

		mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer);

		/*	reset for SQLGetData */
		self->bindings[lf].data_left = -1;

		if (self->bindings[lf].buffer != NULL) {
			/* this column has a binding */

			/* type = QR_get_field_type(res, lf); */
			type = CI_get_oid(ci, lf);		/* speed things up */

			mylog("type = %d\n", type);

			if (self->manual_result) {
				value = QR_get_value_manual(res, self->currTuple, lf);
				mylog("manual_result\n");
			}
			else if (globals.use_declarefetch)
				value = QR_get_value_backend(res, lf);
			else {
				value = QR_get_value_backend_row(res, self->currTuple, lf);
			}

			mylog("value = '%s'\n",  (value==NULL)?"<NULL>":value);

			retval = copy_and_convert_field_bindinfo(self, type, value, lf);

			mylog("copy_and_convert: retval = %d\n", retval);

			switch(retval) {
			case COPY_OK:
				break;	/*	OK, do next bound column */

			case COPY_UNSUPPORTED_TYPE:
				SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
				SC_log_error(func, "", self);
				result = SQL_ERROR;
				break;

			case COPY_UNSUPPORTED_CONVERSION:
				SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
				SC_log_error(func, "", self);
				result = SQL_ERROR;
				break;

			case COPY_RESULT_TRUNCATED:
				SC_set_error(self, STMT_TRUNCATED, "The buffer was too small for the result.");
				result = SQL_SUCCESS_WITH_INFO;
				break;

			case COPY_GENERAL_ERROR:	/* error msg already filled in */
				SC_log_error(func, "", self);
				result = SQL_ERROR;
				break;

			/*  This would not be meaningful in SQLFetch. */
			case COPY_NO_DATA_FOUND:
				break;

			default:
				SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
				SC_log_error(func, "", self);
				result = SQL_ERROR;
				break;
			}
		}
	}

	return result;
}
Example #14
0
SQLRETURN  SQLBindParameter(
    SQLHSTMT           hstmt,
    SQLUSMALLINT       ipar,
    SQLSMALLINT        fParamType,
    SQLSMALLINT        fCType,
    SQLSMALLINT        fSqlType,
    SQLULEN            cbColDef,
    SQLSMALLINT        ibScale,
    SQLPOINTER         rgbValue,
    SQLLEN             cbValueMax,
    SQLLEN 		      *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
static char* const func="SQLBindParameter";

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

	if( ! stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	if(stmt->parameters_allocated < ipar) {
		ParameterInfoClass *old_parameters;
		int i, old_parameters_allocated;

		old_parameters = stmt->parameters;
		old_parameters_allocated = stmt->parameters_allocated;

		stmt->parameters = (ParameterInfoClass *) malloc(sizeof(ParameterInfoClass)*(ipar));
		if ( ! stmt->parameters) {
			SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for statement parameters");
			SC_log_error(func, "", stmt);
			return SQL_ERROR;
		}

		stmt->parameters_allocated = ipar;

		/* copy the old parameters over */
		for(i = 0; i < old_parameters_allocated; i++) {
			/* a structure copy should work */
			stmt->parameters[i] = old_parameters[i];
		}

		/* get rid of the old parameters, if there were any */
		if(old_parameters)
			free(old_parameters);

		/* zero out the newly allocated parameters (in case they skipped some, */
		/* so we don't accidentally try to use them later) */
		for(; i < stmt->parameters_allocated; i++) {
			stmt->parameters[i].buflen = 0;
			stmt->parameters[i].buffer = 0;
			stmt->parameters[i].used = 0;
			stmt->parameters[i].paramType = 0;
			stmt->parameters[i].CType = 0;
			stmt->parameters[i].SQLType = 0;
			stmt->parameters[i].precision = 0;
			stmt->parameters[i].scale = 0;
			stmt->parameters[i].data_at_exec = FALSE;
			stmt->parameters[i].lobj_oid = 0;
			stmt->parameters[i].EXEC_used = NULL;
			stmt->parameters[i].EXEC_buffer = NULL;
		}
	}

	ipar--;		/* use zero based column numbers for the below part */

	/* store the given info */
	stmt->parameters[ipar].buflen = cbValueMax;
	stmt->parameters[ipar].buffer = rgbValue;
	stmt->parameters[ipar].used = pcbValue;
	stmt->parameters[ipar].paramType = fParamType;
	stmt->parameters[ipar].CType = fCType;
	stmt->parameters[ipar].SQLType = fSqlType;
	stmt->parameters[ipar].precision = cbColDef;
	stmt->parameters[ipar].scale = ibScale;

	/*	If rebinding a parameter that had data-at-exec stuff in it,
		then free that stuff
	*/
	if (stmt->parameters[ipar].EXEC_used) {
		free(stmt->parameters[ipar].EXEC_used);
		stmt->parameters[ipar].EXEC_used = NULL;
	}

	if (stmt->parameters[ipar].EXEC_buffer) {
		if (stmt->parameters[ipar].SQLType != SQL_LONGVARBINARY)
			free(stmt->parameters[ipar].EXEC_buffer);
		stmt->parameters[ipar].EXEC_buffer = NULL;
	}

	/*	Data at exec macro only valid for C char/binary data */
	if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && pcbValue && (*pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET || *pcbValue == SQL_DATA_AT_EXEC ))
		stmt->parameters[ipar].data_at_exec = TRUE;
	else
		stmt->parameters[ipar].data_at_exec = FALSE;

	mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue: -777, stmt->parameters[ipar].data_at_exec);

	return SQL_SUCCESS;
}
Example #15
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;
}
Example #16
0
RETCODE SQL_API SQLGetStmtOption(
        HSTMT   hstmt,
        UWORD   fOption,
        PTR     pvParam)
{
static char *func="SQLGetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;

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

    /*// thought we could fake Access out by just returning SQL_SUCCESS */
    /*// all the time, but it tries to set a huge value for SQL_MAX_LENGTH */
    /*// and expects the driver to reduce it to the real value */

	if( ! stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	switch(fOption) {
	case SQL_GET_BOOKMARK:
	case SQL_ROW_NUMBER:

		res = stmt->result;

		if ( stmt->manual_result || ! globals.use_declarefetch) {
			/*// make sure we're positioned on a valid row */
			if((stmt->currTuple < 0) ||
			   (stmt->currTuple >= QR_get_num_tuples(res))) {
				stmt->errormsg = "Not positioned on a valid row.";
				stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
			}
		}
		else {
			if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
				stmt->errormsg = "Not positioned on a valid row.";
				stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
			}
		}

		if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF) {
			stmt->errormsg = "Operation invalid because use bookmarks not enabled.";
			stmt->errornumber = STMT_OPERATION_INVALID;
			SC_log_error(func, "", stmt);
			return SQL_ERROR;
		}

		*((UDWORD *) pvParam) = SC_get_bookmark(stmt);
		
		break;

	case SQL_ASYNC_ENABLE:	/* NOT SUPPORTED */
		*((SDWORD *) pvParam) = SQL_ASYNC_ENABLE_OFF;
		break;

	case SQL_BIND_TYPE:
		*((SDWORD *) pvParam) = stmt->options.bind_size;
		break;

	case SQL_CONCURRENCY: /* NOT REALLY SUPPORTED */
		mylog("GetStmtOption(): SQL_CONCURRENCY\n");
		*((SDWORD *)pvParam) = stmt->options.scroll_concurrency;
		break;

	case SQL_CURSOR_TYPE: /* PARTIAL SUPPORT */
		mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
		*((SDWORD *)pvParam) = stmt->options.cursor_type;
		break;

	case SQL_KEYSET_SIZE: /* NOT SUPPORTED, but saved */
		mylog("GetStmtOption(): SQL_KEYSET_SIZE\n");
		*((SDWORD *)pvParam) = stmt->options.keyset_size;
		break;

	case SQL_MAX_LENGTH: /* NOT SUPPORTED, but saved */
		*((SDWORD *)pvParam) = stmt->options.maxLength;
		break;

	case SQL_MAX_ROWS: /* NOT SUPPORTED, but saved */
		*((SDWORD *)pvParam) = stmt->options.maxRows;
		mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->options.maxRows);
		break;

	case SQL_NOSCAN:/* NOT SUPPORTED */
		*((SDWORD *) pvParam) = SQL_NOSCAN_ON;
		break;

	case SQL_QUERY_TIMEOUT: /* NOT SUPPORTED */
		*((SDWORD *) pvParam) = 0;
		break;

	case SQL_RETRIEVE_DATA: /* NOT SUPPORTED, but saved */
		*((SDWORD *) pvParam) = stmt->options.retrieve_data;
		break;

	case SQL_ROWSET_SIZE:
		*((SDWORD *) pvParam) = stmt->options.rowset_size;
		break;

	case SQL_SIMULATE_CURSOR:/* NOT SUPPORTED */
		*((SDWORD *) pvParam) = SQL_SC_NON_UNIQUE;
		break;

	case SQL_USE_BOOKMARKS:
		*((SDWORD *) pvParam) = stmt->options.use_bookmarks;
		break;

    /*
     * added to be nice to StarOffice and OpenOffice
     */

    case /*SQL_ATTR_CURSOR_SENSITIVITY*/ 65534:
		*((SDWORD *) pvParam) = /*SQL_UNSPECIFIED*/ 0;
        break;

	default:
		{
		char option[64];
		stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
		stmt->errormsg = "Unknown statement option (Get)";
		sprintf(option, "fOption=%d", fOption);
		SC_log_error(func, option, stmt);
		return SQL_ERROR;
		}
	}

	return SQL_SUCCESS;
}
Example #17
0
/*
 *	Supplies parameter data at execution time.
 *	Used in conjunction with SQLParamData.
 */
RETCODE		SQL_API
PGAPI_PutData(
			  HSTMT hstmt,
			  PTR rgbValue,
			  SQLLEN cbValue)
{
	CSTR func = "PGAPI_PutData";
	StatementClass *stmt = (StatementClass *) hstmt, *estmt;
	ConnectionClass *conn;
	RETCODE		retval = SQL_SUCCESS;
	APDFields	*apdopts;
	IPDFields	*ipdopts;
	PutDataInfo	*pdata;
	SQLLEN		old_pos;
	ParameterInfoClass *current_param;
	ParameterImplClass *current_iparam;
	PutDataClass	*current_pdata;
	char	   *buffer, *putbuf, *allocbuf = NULL;
	Int2		ctype;
	SQLLEN		putlen;
	BOOL		lenset = FALSE, handling_lo = FALSE;

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

#define	return	DONT_CALL_RETURN_FROM_HERE???
	if (!stmt)
	{
		SC_log_error(func, "", NULL);
		retval = SQL_INVALID_HANDLE;
		goto cleanup;
	}
	if (SC_AcceptedCancelRequest(stmt))
	{
		SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry.", func);
		retval = SQL_ERROR;
		goto cleanup;
	}

	estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt;
	apdopts = SC_get_APDF(estmt);
	if (estmt->current_exec_param < 0)
	{
		SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData", func);
		retval = SQL_ERROR;
		goto cleanup;
	}

	current_param = &(apdopts->parameters[estmt->current_exec_param]);
	ipdopts = SC_get_IPDF(estmt);
	current_iparam = &(ipdopts->parameters[estmt->current_exec_param]);
	pdata = SC_get_PDTI(estmt);
	current_pdata = &(pdata->pdata[estmt->current_exec_param]);
	ctype = current_param->CType;

	conn = SC_get_conn(estmt);
	if (ctype == SQL_C_DEFAULT)
	{
		ctype = sqltype_to_default_ctype(conn, current_iparam->SQLType);
		if (SQL_C_WCHAR == ctype &&
		    CC_default_is_c(conn))
			ctype = SQL_C_CHAR;
	}
	if (SQL_NTS == cbValue)
	{
#ifdef	UNICODE_SUPPORT
		if (SQL_C_WCHAR == ctype)
		{
			putlen = WCLEN * ucs2strlen((SQLWCHAR *) rgbValue);
			lenset = TRUE;
		}
		else
#endif /* UNICODE_SUPPORT */
		if (SQL_C_CHAR == ctype)
		{
			putlen = strlen(rgbValue);
			lenset = TRUE;
		}
	}
	if (!lenset)
	{
		if (cbValue < 0)
			putlen = cbValue;
		else
#ifdef	UNICODE_SUPPORT
		if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY || ctype == SQL_C_WCHAR)
#else
		if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
#endif /* UNICODE_SUPPORT */
			putlen = cbValue;
		else
			putlen = ctype_length(ctype);
	}
	putbuf = rgbValue;
	handling_lo = (PIC_dsp_pgtype(conn, *current_iparam) == conn->lobj_type);
	if (handling_lo && SQL_C_CHAR == ctype)
	{
		allocbuf = malloc(putlen / 2 + 1);
		if (allocbuf)
		{
			pg_hex2bin(rgbValue, allocbuf, putlen);
			putbuf = allocbuf;
			putlen /= 2;
		}
	}

	if (!estmt->put_data)
	{							/* first call */
		mylog("PGAPI_PutData: (1) cbValue = %d\n", cbValue);

		estmt->put_data = TRUE;

		current_pdata->EXEC_used = (SQLLEN *) malloc(sizeof(SQLLEN));
		if (!current_pdata->EXEC_used)
		{
			SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)", func);
			retval = SQL_ERROR;
			goto cleanup;
		}

		*current_pdata->EXEC_used = putlen;

		if (cbValue == SQL_NULL_DATA)
		{
			retval = SQL_SUCCESS;
			goto cleanup;
		}

		/* Handle Long Var Binary with Large Objects */
		/* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
		if (handling_lo)
		{
			/* begin transaction if needed */
			if (!CC_is_in_trans(conn))
			{
				if (!CC_begin(conn))
				{
					SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction", func);
					retval = SQL_ERROR;
					goto cleanup;
				}
			}

			/* store the oid */
			current_pdata->lobj_oid = odbc_lo_creat(conn, INV_READ | INV_WRITE);
			if (current_pdata->lobj_oid == 0)
			{
				SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object.", func);
				retval = SQL_ERROR;
				goto cleanup;
			}

			/*
			 * major hack -- to allow convert to see somethings there have
			 * to modify convert to handle this better
			 */
			/***current_param->EXEC_buffer = (char *) &current_param->lobj_oid;***/

			/* store the fd */
			estmt->lobj_fd = odbc_lo_open(conn, current_pdata->lobj_oid, INV_WRITE);
			if (estmt->lobj_fd < 0)
			{
				SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing.", func);
				retval = SQL_ERROR;
				goto cleanup;
			}

			retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, (Int4) putlen);
			mylog("lo_write: cbValue=%d, wrote %d bytes\n", putlen, retval);
		}
		else
		{
			current_pdata->EXEC_buffer = malloc(putlen + 1);
			if (!current_pdata->EXEC_buffer)
			{
				SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)", func);
				retval = SQL_ERROR;
				goto cleanup;
			}
			memcpy(current_pdata->EXEC_buffer, putbuf, putlen);
			current_pdata->EXEC_buffer[putlen] = '\0';
		}
	}
	else
	{
		/* calling SQLPutData more than once */
		mylog("PGAPI_PutData: (>1) cbValue = %d\n", cbValue);

		/* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
		if (handling_lo)
		{
			/* the large object fd is in EXEC_buffer */
			retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, (Int4) putlen);
			mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", putlen, retval);

			*current_pdata->EXEC_used += putlen;
		}
		else
		{
			buffer = current_pdata->EXEC_buffer;
			old_pos = *current_pdata->EXEC_used;
			if (putlen > 0)
			{
				SQLLEN	used = *current_pdata->EXEC_used + putlen, allocsize;
				for (allocsize = (1 << 4); allocsize <= used; allocsize <<= 1) ;
				mylog("        cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, used);

				/* dont lose the old pointer in case out of memory */
				buffer = realloc(current_pdata->EXEC_buffer, allocsize);
				if (!buffer)
				{
					SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)", func);
					retval = SQL_ERROR;
					goto cleanup;
				}

				memcpy(&buffer[old_pos], putbuf, putlen);
				buffer[used] = '\0';

				/* reassign buffer incase realloc moved it */
				*current_pdata->EXEC_used = used;
				current_pdata->EXEC_buffer = buffer;
			}
			else
			{
				SC_set_error(stmt, STMT_INTERNAL_ERROR, "bad cbValue", func);
				retval = SQL_ERROR;
				goto cleanup;
			}
		}
	}

	retval = SQL_SUCCESS;
cleanup:
#undef	return
	if (allocbuf)
		free(allocbuf);
	if (stmt->internal)
		retval = DiscardStatementSvp(stmt, retval, TRUE);

	return retval;
}
Example #18
0
RETCODE set_statement_option(ConnectionClass *conn,
							 StatementClass *stmt,
							 UWORD   fOption,
							 UDWORD  vParam)
{
static char *func="set_statement_option";
char changed = FALSE;


	switch(fOption) {
	case SQL_ASYNC_ENABLE:/* ignored */
		break;

	case SQL_BIND_TYPE:		
		/* now support multi-column and multi-row binding */
		if (conn) conn->stmtOptions.bind_size = vParam;
		if (stmt) stmt->options.bind_size = vParam;
		break;

	case SQL_CONCURRENCY:
		/*	positioned update isn't supported so cursor concurrency is read-only */

		if (conn) conn->stmtOptions.scroll_concurrency = vParam;
		if (stmt) stmt->options.scroll_concurrency = vParam;
		break;

		/*
		if (globals.lie) {
			if (conn) conn->stmtOptions.scroll_concurrency = vParam;
			if (stmt) stmt->options.scroll_concurrency = vParam;
		}
		else {

			if (conn) conn->stmtOptions.scroll_concurrency = SQL_CONCUR_READ_ONLY;
			if (stmt) stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;

			if (vParam != SQL_CONCUR_READ_ONLY)
				changed = TRUE;
		}
		break;
		*/
		
	case SQL_CURSOR_TYPE:
		/*	if declare/fetch, then type can only be forward.
			otherwise, it can only be forward or static.
		*/
		mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam);

		if (globals.lie) {

			if (conn) conn->stmtOptions.cursor_type = vParam;
			if (stmt) stmt->options.cursor_type = vParam;

		}
		else {
			if (globals.use_declarefetch) {

				if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_FORWARD_ONLY;
				if (stmt) stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;

				if (vParam != SQL_CURSOR_FORWARD_ONLY)
					changed = TRUE;
			}
			else {
				if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC) {

					if (conn) conn->stmtOptions.cursor_type = vParam;		/*// valid type */
					if (stmt) stmt->options.cursor_type = vParam;		/*// valid type */
				}
				else {

					if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_STATIC;
					if (stmt) stmt->options.cursor_type = SQL_CURSOR_STATIC;

					changed = TRUE;
				}
			}
		}
		break;

	case SQL_KEYSET_SIZE: /* ignored, but saved and returned  */
		mylog("SetStmtOption(): SQL_KEYSET_SIZE, vParam = %d\n", vParam);

		if (conn) conn->stmtOptions.keyset_size = vParam;
		if (stmt) stmt->options.keyset_size = vParam;

		break;

		/*
		if (globals.lie)
			stmt->keyset_size = vParam;
		else {
			stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
			stmt->errormsg = "Driver does not support keyset size option";
			SC_log_error(func, "", stmt);
			return SQL_ERROR;
		}
		*/

	case SQL_MAX_LENGTH:/* ignored, but saved */
		mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam);
		if (conn) conn->stmtOptions.maxLength = vParam;
		if (stmt) stmt->options.maxLength = vParam;
		break;

	case SQL_MAX_ROWS: /* ignored, but saved */
		mylog("SetStmtOption(): SQL_MAX_ROWS, vParam = %d\n", vParam);
		if (conn) conn->stmtOptions.maxRows = vParam;
		if (stmt) stmt->options.maxRows = vParam;
		break;

	case SQL_NOSCAN: /* ignored */
		mylog("SetStmtOption: SQL_NOSCAN, vParam = %d\n", vParam);
		break;

	case SQL_QUERY_TIMEOUT: /* ignored */
		mylog("SetStmtOption: SQL_QUERY_TIMEOUT, vParam = %d\n", vParam);
		/*//	"0" returned in SQLGetStmtOption */
		break;

	case SQL_RETRIEVE_DATA: /* ignored, but saved */
		mylog("SetStmtOption(): SQL_RETRIEVE_DATA, vParam = %d\n", vParam);
		if (conn) conn->stmtOptions.retrieve_data = vParam;
		if (stmt) stmt->options.retrieve_data = vParam;
		break;

	case SQL_ROWSET_SIZE:
		mylog("SetStmtOption(): SQL_ROWSET_SIZE, vParam = %d\n", vParam);


		/*	Save old rowset size for SQLExtendedFetch purposes
			If the rowset_size is being changed since the last call
			to fetch rows.
		*/

		if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0 )
			stmt->save_rowset_size = stmt->options.rowset_size;

		if (vParam < 1) {
			vParam = 1;
			changed = TRUE;
		}

		if (conn) conn->stmtOptions.rowset_size = vParam;
		if (stmt) stmt->options.rowset_size = vParam;

		break;

	case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
		if (stmt) {
			stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
			stmt->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
			SC_log_error(func, "", stmt);
		}
		if (conn) {
			conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
			conn->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
			CC_log_error(func, "", conn);
		}
		return SQL_ERROR;

	case SQL_USE_BOOKMARKS:

		if (stmt) stmt->options.use_bookmarks = vParam;
		if (conn) conn->stmtOptions.use_bookmarks = vParam;
		break;

    /*
     * added to be nice to OpenOffice
     */

    case /*SQL_ATTR_CURSOR_SENSITIVITY*/ 65534:
        break;

    default:
		{
		char option[64];

		if (stmt) {
			stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
			stmt->errormsg = "Unknown statement option (Set)";
			sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
			SC_log_error(func, option, stmt);
		}
		if (conn) {
			conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
			conn->errormsg = "Unknown statement option (Set)";
			sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
			CC_log_error(func, option, conn);
		}

        return SQL_ERROR;
		}
    }

	if (changed) {
		if (stmt) {
			stmt->errormsg = "Requested value changed.";
			stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
		}
		if (conn) {
			conn->errormsg = "Requested value changed.";
			conn->errornumber = STMT_OPTION_VALUE_CHANGED;
		}
		return SQL_SUCCESS_WITH_INFO;
	}
	else
		return SQL_SUCCESS;
}
Example #19
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;
}
Example #20
0
/*      Associate a user-supplied buffer with a database column. */
RETCODE SQL_API PG_SQLBindCol(
        HSTMT      hstmt,
        UWORD      icol,
        SWORD      fCType,
        PTR        rgbValue,
        SQLLEN     cbValueMax,
        SQLLEN    *pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
static char* const func="SQLBindCol";

	mylog( "%s: entering...\n", func);
    
mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);

	if ( ! stmt) {
		SC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}


	SC_clear_error(stmt);
    
	if( stmt->status == STMT_EXECUTING) {
		SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.");
		SC_log_error(func, "", stmt);
		return SQL_ERROR;
	}

	/*	If the bookmark column is being bound, then just save it */
	if (icol == 0) {

		if (rgbValue == NULL) {
			stmt->bookmark.buffer = NULL;
			stmt->bookmark.used = NULL;
		}
		else {
			/*	Make sure it is the bookmark data type */
			if ( fCType != SQL_C_BOOKMARK && fCType != SQL_C_BINARY ) {
				SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK");
				SC_log_error(func, "", stmt);
				return SQL_ERROR;
			}

			stmt->bookmark.buffer = rgbValue;
			stmt->bookmark.used = pcbValue;
		}
		return SQL_SUCCESS;
	}

	/*	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 > stmt->bindings_allocated)
		extend_bindings(stmt, icol);

	/*	check to see if the bindings were allocated */
	if ( ! stmt->bindings) {
		SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.");
		SC_log_error(func, "", stmt);
		return SQL_ERROR;
	}

	icol--;		/* use zero based col numbers from here out */

	/*	Reset for SQLGetData */
	stmt->bindings[icol].data_left = -1;

	if (rgbValue == NULL) {
		/* we have to unbind the column */
		stmt->bindings[icol].buflen = 0;
		stmt->bindings[icol].buffer = NULL;
		stmt->bindings[icol].used =   NULL;
		stmt->bindings[icol].returntype = SQL_C_CHAR;
	} else {
		/* ok, bind that column */
		stmt->bindings[icol].buflen     = cbValueMax;
		stmt->bindings[icol].buffer     = rgbValue;
		stmt->bindings[icol].used       = pcbValue;
		stmt->bindings[icol].returntype = fCType;

		mylog("       bound buffer[%d] = %u\n", icol, stmt->bindings[icol].buffer);
	}

	return SQL_SUCCESS;
}