Пример #1
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;
	}
}
Пример #2
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:
				case SQL_C_VARBOOKMARK:
					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;
		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;
		}
		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;
}
Пример #3
0
/*	Called from SQLPrepare if STMT_PREMATURE, or
	from SQLExecute if STMT_FINISHED, or
	from SQLFreeStmt(SQL_CLOSE)
 */
char
SC_recycle_statement(StatementClass *self)
{
ConnectionClass *conn;

mylog("recycle statement: self= %u\n", self);

	/*	This would not happen */
	if (self->status == STMT_EXECUTING) {
		SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
		return FALSE;
	}

	SC_set_errormsg(self, NULL);
	SC_clear_error(self);

	switch (self->status) {
	case STMT_ALLOCATED:
		/* this statement does not need to be recycled */
		return TRUE;

	case STMT_READY:
		break;

	case STMT_PREMATURE:
		/*	Premature execution of the statement might have caused the start of a transaction.
			If so, we have to rollback that transaction.
		*/
		conn = SC_get_conn(self);
		if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {

			CC_send_query(conn, "ABORT", NULL);
			CC_set_no_trans(conn);
		}
		break;

	case STMT_FINISHED:
		break;

	default:
		SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements");
		return FALSE;
	}

	/*	Free the parsed table information */
	if (self->ti) {
		int i;
		for (i = 0; i < self->ntab; i++) {
			free(self->ti[i]);
		}

		free(self->ti);
		self->ti = NULL;
		self->ntab = 0;
	}

	/*	Free the parsed field information */
	if (self->fi) {
		int i;
		for (i = 0; i < self->nfld; i++) {
			free(self->fi[i]);
		}
		free(self->fi);
		self->fi = NULL;
		self->nfld = 0;
	}
	self->parse_status = STMT_PARSE_NONE;

	/*	Free any cursors */
	if (self->result) {
		QR_Destructor(self->result);
		self->result = NULL;
	}

	/****************************************************************/
	/*	Reset only parameters that have anything to do with results */
	/****************************************************************/

	self->status = STMT_READY;
	self->manual_result = FALSE;	/* very important */

	self->currTuple = -1;
	self->rowset_start = -1;
	self->current_col = -1;
	self->bind_row = 0;
	self->last_fetch_count = 0;

	SC_set_errormsg(self, NULL);
	SC_clear_error(self);

	self->lobj_fd = -1;

	/*	Free any data at exec params before the statement is executed */
	/*	again.  If not, then there will be a memory leak when */
	/*	the next SQLParamData/SQLPutData is called. */
	SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);

	return TRUE;
}
Пример #4
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;
}
Пример #5
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";
    APDFields	*apdopts;
    IPDFields	*ipdopts;
    RETCODE		ret = SQL_SUCCESS;
    int		num_params;

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

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

    apdopts = SC_get_APDF(stmt);
    ipdopts = SC_get_IPDF(stmt);
    /*if ((ipar < 1) || (ipar > ipdopts->allocated))*/
    num_params = stmt->num_params;
    if (num_params < 0)
    {
        SQLSMALLINT	num_p;

        PGAPI_NumParams(stmt, &num_p);
        num_params = num_p;
    }
    if ((ipar < 1) || (ipar > num_params))
    {
        inolog("num_params=%d\n", stmt->num_params);
        SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.", func);
        return SQL_ERROR;
    }
    extend_iparameter_bindings(ipdopts, stmt->num_params);

#define	return	DONT_CALL_RETURN_FROM_HERE???
    /* StartRollbackState(stmt); */
    if (NOT_YET_PREPARED == stmt->prepared)
    {
        decideHowToPrepare(stmt, FALSE);
        inolog("howTo=%d\n", SC_get_prepare_method(stmt));
        switch (SC_get_prepare_method(stmt))
        {
        case NAMED_PARSE_REQUEST:
        case PARSE_TO_EXEC_ONCE:
        case PARSE_REQ_FOR_INFO:
            if (ret = prepareParameters(stmt), SQL_ERROR == ret)
                goto cleanup;
        }
    }

    ipar--;
    /*
     * This implementation is not very good, since it is supposed to
     * describe
     */
    /* parameter markers, not bound parameters.  */
    if (pfSqlType)
    {
        inolog("[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType,
               ipdopts->parameters[ipar].PGType);
        if (ipdopts->parameters[ipar].SQLType)
            *pfSqlType = ipdopts->parameters[ipar].SQLType;
        else if (ipdopts->parameters[ipar].PGType)
            *pfSqlType = pgtype_to_concise_type(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC);
        else
        {
            ret = SQL_ERROR;
            SC_set_error(stmt, STMT_EXEC_ERROR, "Unfortunatley couldn't get this paramater's info", func);
            goto cleanup;
        }
    }

    if (pcbParamDef)
    {
        *pcbParamDef = 0;
        if (ipdopts->parameters[ipar].SQLType)
            *pcbParamDef = ipdopts->parameters[ipar].column_size;
        if (0 == *pcbParamDef && ipdopts->parameters[ipar].PGType)
            *pcbParamDef = pgtype_column_size(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC, PG_STATIC);
    }

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

    if (pfNullable)
        *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);
cleanup:
#undef	return
    if (stmt->internal)
        ret = DiscardStatementSvp(stmt, ret, FALSE);
    return ret;
}
Пример #6
0
SQLRETURN SQL_API SQLColAttributeW(
    SQLHSTMT    hstmt,
    SQLUSMALLINT    iCol,
    SQLUSMALLINT    iField,
    SQLPOINTER  pCharAttr,
    SQLSMALLINT cbCharAttrMax,  
    SQLSMALLINT *pcbCharAttr,
#if defined(WITH_UNIXODBC) || (defined(WIN32) && ! defined(_WIN64))
    SQLPOINTER  pNumAttr
#else
    SQLLEN      *pNumAttr
#endif
    )
{
    CSTR func = "SQLColAttributeW";
    RETCODE ret;
    StatementClass  *stmt = (StatementClass *) hstmt;
    SQLSMALLINT *rgbL, blen = 0, bMax;
        char    *rgbD = NULL;

    mylog("[%s]", func);
    ENTER_STMT_CS(stmt);
    SC_clear_error(stmt);
    StartRollbackState(stmt);
    switch (iField)
    { 
        case SQL_DESC_BASE_COLUMN_NAME:
        case SQL_DESC_BASE_TABLE_NAME:
        case SQL_DESC_CATALOG_NAME:
        case SQL_DESC_LABEL:
        case SQL_DESC_LITERAL_PREFIX:
        case SQL_DESC_LITERAL_SUFFIX:
        case SQL_DESC_LOCAL_TYPE_NAME:
        case SQL_DESC_NAME:
        case SQL_DESC_SCHEMA_NAME:
        case SQL_DESC_TABLE_NAME:
        case SQL_DESC_TYPE_NAME:
        case SQL_COLUMN_NAME:
            bMax = cbCharAttrMax * 3 / WCLEN;
            rgbD = malloc(bMax);
            rgbL = &blen;
            for (;; bMax = blen + 1, rgbD = realloc(rgbD, bMax))
            {
                ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
                    bMax, rgbL, pNumAttr);
                if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
                    break;
            }
            if (SQL_SUCCEEDED(ret))
            {
                blen = (SQLSMALLINT) utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) pCharAttr, cbCharAttrMax / WCLEN);
                if (SQL_SUCCESS == ret && blen * WCLEN >= cbCharAttrMax)
                {
                    ret = SQL_SUCCESS_WITH_INFO;
                    SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the pCharAttr.", func);
                }
                if (pcbCharAttr)
                    *pcbCharAttr = blen * WCLEN;
            }
            if (rgbD)
                free(rgbD);
            break;
        default:
            rgbD = pCharAttr;
            bMax = cbCharAttrMax;
            rgbL = pcbCharAttr;
            ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
                    bMax, rgbL, pNumAttr);
            break;
    }
    ret = DiscardStatementSvp(stmt, ret, FALSE);
    LEAVE_STMT_CS(stmt);

    return ret;
}
Пример #7
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;
}
Пример #8
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;
}
Пример #9
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;
	BOOL	prepared;

	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
	 */

	prepared = self->prepared;
	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");
			if (NOT_YET_PREPARED != prepared)
				SC_recycle_statement(self); /* recycle the statement */
			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;
}