Esempio n. 1
0
/*
 *	The execution after all parameters were resolved.
 */
static
RETCODE	Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end)
{
	CSTR func = "Exec_with_parameters_resolved";
	RETCODE		retval;
	SQLLEN		end_row;
	SQLINTEGER	cursor_type, scroll_concurrency;
	ConnectionClass	*conn;
	QResultClass	*res;
	APDFields	*apdopts;
	IPDFields	*ipdopts;
	BOOL		prepare_before_exec = FALSE;

	*exec_end = FALSE;
	conn = SC_get_conn(stmt);
	mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement);

	/* save the cursor's info before the execution */
	cursor_type = stmt->options.cursor_type;
	scroll_concurrency = stmt->options.scroll_concurrency;
	/* Prepare the statement if possible at backend side */
	if (!stmt->inaccurate_result)
	{
		if (HowToPrepareBeforeExec(stmt, FALSE) >= allowParse)
			prepare_before_exec = TRUE;
	}
inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare);
	/* Create the statement with parameters substituted. */
	retval = copy_statement_with_parameters(stmt, prepare_before_exec);
	stmt->current_exec_param = -1;
	if (retval != SQL_SUCCESS)
	{
		stmt->exec_current_row = -1;
		*exec_end = TRUE;
		return retval; /* error msg is passed from the above */
	}

	mylog("   stmt_with_params = '%s'\n", stmt->stmt_with_params);

	/*
	 *	Dummy exection to get the column info.
	 */ 
	if (stmt->inaccurate_result && SC_is_parse_tricky(stmt))
	{
		BOOL		in_trans = CC_is_in_trans(conn);
		BOOL		issued_begin = FALSE;
		QResultClass *curres;

		stmt->exec_current_row = -1;
		*exec_end = TRUE;
		if (!SC_is_pre_executable(stmt))
			return SQL_SUCCESS;
		if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0)
		{
			/* do nothing */
		}
		else if (!in_trans)
		{
			if (issued_begin = CC_begin(conn), !issued_begin)
			{
				SC_set_error(stmt, STMT_EXEC_ERROR,  "Handle prepare error", func);
				return SQL_ERROR;
			}
		}
		/* we are now in a transaction */
		res = CC_send_query(conn, stmt->stmt_with_params, NULL, 0, SC_get_ancestor(stmt));
		if (!QR_command_maybe_successful(res))
		{
#ifndef	_LEGACY_MODE_
			if (PG_VERSION_LT(conn, 8.0))
				CC_abort(conn);
#endif /* LEGACY_MODE_ */
			SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func);
			QR_Destructor(res);
			return SQL_ERROR;
		}
		SC_set_Result(stmt, res);
		for (curres = res; !curres->num_fields; curres = curres->next)
			;
		SC_set_Curres(stmt, curres);
		if (CC_does_autocommit(conn))
		{
			if (issued_begin)
				CC_commit(conn);
		}
		stmt->status = STMT_FINISHED;
		return SQL_SUCCESS;
	}
	/*
	 *	The real execution.
	 */
mylog("about to begin SC_execute\n");
	retval = SC_execute(stmt);
	if (retval == SQL_ERROR)
	{
		stmt->exec_current_row = -1;
		*exec_end = TRUE;
		return retval;
	}
	res = SC_get_Result(stmt);
	/* special handling of result for keyset driven cursors */
	if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
	    SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency)
	{
		QResultClass	*kres;

		if (kres = res->next, kres)
		{
			if (kres->fields)
				CI_Destructor(kres->fields);
			kres->fields = res->fields;
			res->fields = NULL;
			kres->num_fields = res->num_fields;
			res->next = NULL;
			SC_set_Result(stmt, kres);
			res = kres;
		}
	}
#ifdef	NOT_USED
	else if (SC_is_concat_prepare_exec(stmt))
	{
		if (res && QR_command_maybe_successful(res))
		{
			QResultClass	*kres;
		
			kres = res->next;
inolog("res->next=%p\n", kres);
			res->next = NULL;
			SC_set_Result(stmt, kres);
			res = kres;
			SC_set_prepared(stmt, PREPARED_PERMANENTLY);
		}
		else
		{
			retval = SQL_ERROR;
			if (stmt->execute_statement)
				free(stmt->execute_statement);
			stmt->execute_statement = NULL;
		}
	}
#endif /* NOT_USED */
#if (ODBCVER >= 0x0300)
	ipdopts = SC_get_IPDF(stmt);
	if (ipdopts->param_status_ptr)
	{
		switch (retval)
		{
			case SQL_SUCCESS: 
				ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
				break;
			case SQL_SUCCESS_WITH_INFO: 
				ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
				break;
			default: 
				ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
				break;
		}
	}
#endif /* ODBCVER */
	if (end_row = stmt->exec_end_row, end_row < 0)
	{
		apdopts = SC_get_APDF(stmt);
		end_row = (SQLINTEGER) apdopts->paramset_size - 1;
	}
	if (stmt->inaccurate_result ||
	    stmt->exec_current_row >= end_row)
	{
		*exec_end = TRUE;
		stmt->exec_current_row = -1;
	}
	else
		stmt->exec_current_row++;
	if (res)
	{
#if (ODBCVER >= 0x0300)
		EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
		const char *cmd = QR_get_command(res);
		SQLLEN	start_row;
		if (start_row = stmt->exec_start_row, start_row < 0)
			start_row = 0;

		if (retval == SQL_SUCCESS &&
		    NULL != cmd &&
		    start_row >= end_row &&
		    NULL != env &&
		    EN_is_odbc3(env))
		{
			int     count;

			if (sscanf(cmd , "UPDATE %d", &count) == 1)
				;
			else if (sscanf(cmd , "DELETE %d", &count) == 1)
				;
			else
				count = -1;
			if (0 == count)
				retval = SQL_NO_DATA;
		}
#endif /* ODBCVER */
		stmt->diag_row_count = res->recent_processed_row_count;
	}
	/*
	 *	The cursor's info was changed ?
	 */
	if (retval == SQL_SUCCESS &&
	    (stmt->options.cursor_type != cursor_type ||
	     stmt->options.scroll_concurrency != scroll_concurrency))
	{
		SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed", func);
		retval = SQL_SUCCESS_WITH_INFO;
	}
	return retval;
}
Esempio n. 2
0
RETCODE		SQL_API
PGAPI_Transact(
			   HENV henv,
			   HDBC hdbc,
			   SQLUSMALLINT fType)
{
	CSTR func = "PGAPI_Transact";
	ConnectionClass *conn;
	char		ok;
	int			lf;

	mylog("entering %s: hdbc=%p, henv=%p\n", func, hdbc, henv);

	if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV)
	{
		CC_log_error(func, "", NULL);
		return SQL_INVALID_HANDLE;
	}

	/*
	 * If hdbc is null and henv is valid, it means transact all
	 * connections on that henv.
	 */
	if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV)
	{
		ConnectionClass * const *conns = getConnList();
		const int	conn_count = getConnCount();
		for (lf = 0; lf < conn_count; lf++)
		{
			conn = conns[lf];

			if (conn && CC_get_env(conn) == henv)
				if (PGAPI_Transact(henv, (HDBC) conn, fType) != SQL_SUCCESS)
					return SQL_ERROR;
		}
		return SQL_SUCCESS;
	}

	conn = (ConnectionClass *) hdbc;

	if (fType != SQL_COMMIT &&
	    fType != SQL_ROLLBACK)
	{
		CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter", func);
		return SQL_ERROR;
	}

	/* If manual commit and in transaction, then proceed. */
	if (CC_loves_visible_trans(conn) && CC_is_in_trans(conn))
	{
		mylog("PGAPI_Transact: sending on conn %p '%d'\n", conn, fType);

		ok = (SQL_COMMIT == fType) ? CC_commit(conn) : CC_abort(conn);
		if (!ok)
		{
			/* error msg will be in the connection */
			CC_on_abort(conn, NO_TRANS);
			CC_log_error(func, "", conn);
			return SQL_ERROR;
		}
	}
	return SQL_SUCCESS;
}
Esempio n. 3
0
SQLSMALLINT
pgtype_to_ctype(StatementClass *stmt, OID type)
{
	ConnectionClass	*conn = SC_get_conn(stmt);
	ConnInfo	*ci = &(conn->connInfo);
#if (ODBCVER >= 0x0300)
	EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
#endif /* ODBCVER */

	switch (type)
	{
		case PG_TYPE_INT8:
#if (ODBCVER >= 0x0300)
			if (!conn->ms_jet)
				return ALLOWED_C_BIGINT;
#endif /* ODBCVER */
			return SQL_C_CHAR;
		case PG_TYPE_NUMERIC:
			return SQL_C_CHAR;
		case PG_TYPE_INT2:
			return SQL_C_SSHORT;
		case PG_TYPE_OID:
		case PG_TYPE_XID:
			return SQL_C_ULONG;
		case PG_TYPE_INT4:
			return SQL_C_SLONG;
		case PG_TYPE_FLOAT4:
			return SQL_C_FLOAT;
		case PG_TYPE_FLOAT8:
			return SQL_C_DOUBLE;
		case PG_TYPE_DATE:
#if (ODBCVER >= 0x0300)
			if (EN_is_odbc3(env))
				return SQL_C_TYPE_DATE;
#endif /* ODBCVER */
			return SQL_C_DATE;
		case PG_TYPE_TIME:
#if (ODBCVER >= 0x0300)
			if (EN_is_odbc3(env))
				return SQL_C_TYPE_TIME;
#endif /* ODBCVER */
			return SQL_C_TIME;
		case PG_TYPE_ABSTIME:
		case PG_TYPE_DATETIME:
		case PG_TYPE_TIMESTAMP_NO_TMZONE:
		case PG_TYPE_TIMESTAMP:
#if (ODBCVER >= 0x0300)
			if (EN_is_odbc3(env))
				return SQL_C_TYPE_TIMESTAMP;
#endif /* ODBCVER */
			return SQL_C_TIMESTAMP;
		case PG_TYPE_MONEY:
			return SQL_C_FLOAT;
		case PG_TYPE_BOOL:
			return ci->drivers.bools_as_char ? SQL_C_CHAR : SQL_C_BIT;

		case PG_TYPE_BYTEA:
			return SQL_C_BINARY;
		case PG_TYPE_LO_UNDEFINED:
			return SQL_C_BINARY;
#ifdef	UNICODE_SUPPORT
		case PG_TYPE_BPCHAR:
		case PG_TYPE_VARCHAR:
		case PG_TYPE_TEXT:
			if (CC_is_in_unicode_driver(conn)
#ifdef	NOT_USED
			    && ! stmt->catalog_result
#endif /* NOT USED */
				)
				return SQL_C_WCHAR;
			return SQL_C_CHAR;
#endif /* UNICODE_SUPPORT */
		case PG_TYPE_UUID:
#if (ODBCVER >= 0x0350)
			if (!conn->ms_jet)
				return SQL_C_GUID;
#endif /* ODBCVER */
			return SQL_C_CHAR;

		default:
			/* hack until permanent type is available */
			if (type == stmt->hdbc->lobj_type)
				return SQL_C_BINARY;

			/* Experimental, Does this work ? */
#ifdef	EXPERIMENTAL_CURRENTLY
			if (ALLOW_WCHAR(conn))
				return SQL_C_WCHAR;
#endif	/* EXPERIMENTAL_CURRENTLY */
			return SQL_C_CHAR;
	}
}
Esempio n. 4
0
/*
 *	There are two ways of calling this function:
 *
 *	1.	When going through the supported PG types (SQLGetTypeInfo)
 *
 *	2.	When taking any type id (SQLColumns, SQLGetData)
 *
 *	The first type will always work because all the types defined are returned here.
 *	The second type will return a default based on global parameter when it does not
 *	know.	This allows for supporting
 *	types that are unknown.  All other pg routines in here return a suitable default.
 */
SQLSMALLINT
pgtype_to_concise_type(StatementClass *stmt, OID type, int col)
{
	ConnectionClass	*conn = SC_get_conn(stmt);
	ConnInfo	*ci = &(conn->connInfo);
#if (ODBCVER >= 0x0300)
	EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
#endif /* ODBCVER */

	switch (type)
	{
		case PG_TYPE_CHAR:
		case PG_TYPE_CHAR2:
		case PG_TYPE_CHAR4:
		case PG_TYPE_CHAR8:
			return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
		case PG_TYPE_NAME:
			return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;

#ifdef	UNICODE_SUPPORT
		case PG_TYPE_BPCHAR:
			if (col >= 0 &&
			    getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
				return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
			return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;

		case PG_TYPE_VARCHAR:
			if (col >= 0 &&
			    getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
				return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
			return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;

		case PG_TYPE_TEXT:
			return ci->drivers.text_as_longvarchar ? 
				(ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
				(ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);

#else
		case PG_TYPE_BPCHAR:
			if (col >= 0 &&
			    getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
				return SQL_LONGVARCHAR;
			return SQL_CHAR;

		case PG_TYPE_VARCHAR:
			if (col >= 0 &&
			    getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
				return SQL_LONGVARCHAR;
			return SQL_VARCHAR;

		case PG_TYPE_TEXT:
			return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
#endif /* UNICODE_SUPPORT */

		case PG_TYPE_BYTEA:
			if (ci->bytea_as_longvarbinary)
				return SQL_LONGVARBINARY;
			else
				return SQL_VARBINARY;
		case PG_TYPE_LO_UNDEFINED:
			return SQL_LONGVARBINARY;

		case PG_TYPE_INT2:
			return SQL_SMALLINT;

		case PG_TYPE_OID:
		case PG_TYPE_XID:
		case PG_TYPE_INT4:
			return SQL_INTEGER;

			/* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
		case PG_TYPE_INT8:
			if (ci->int8_as != 0) 
				return ci->int8_as;
			if (conn->ms_jet) 
				return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
#if (ODBCVER >= 0x0300)
			return SQL_BIGINT;
#else
			return SQL_VARCHAR;
#endif /* ODBCVER */

		case PG_TYPE_NUMERIC:
			return SQL_NUMERIC;

		case PG_TYPE_FLOAT4:
			return SQL_REAL;
		case PG_TYPE_FLOAT8:
			return SQL_FLOAT;
		case PG_TYPE_DATE:
#if (ODBCVER >= 0x0300)
			if (EN_is_odbc3(env))
				return SQL_TYPE_DATE;
#endif /* ODBCVER */
			return SQL_DATE;
		case PG_TYPE_TIME:
#if (ODBCVER >= 0x0300)
			if (EN_is_odbc3(env))
				return SQL_TYPE_TIME;
#endif /* ODBCVER */
			return SQL_TIME;
		case PG_TYPE_ABSTIME:
		case PG_TYPE_DATETIME:
		case PG_TYPE_TIMESTAMP_NO_TMZONE:
		case PG_TYPE_TIMESTAMP:
#if (ODBCVER >= 0x0300)
			if (EN_is_odbc3(env))
				return SQL_TYPE_TIMESTAMP;
#endif /* ODBCVER */
			return SQL_TIMESTAMP;
		case PG_TYPE_MONEY:
			return SQL_FLOAT;
		case PG_TYPE_BOOL:
			return ci->drivers.bools_as_char ? SQL_CHAR : SQL_BIT;
		case PG_TYPE_XML:
			return CC_is_in_unicode_driver(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
		case PG_TYPE_INET:
		case PG_TYPE_CIDR:
		case PG_TYPE_MACADDR:
			return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
		case PG_TYPE_UUID:
#if (ODBCVER >= 0x0350)
			return SQL_GUID;
#endif /* ODBCVER */
			return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
		default:

			/*
			 * first, check to see if 'type' is in list.  If not, look up
			 * with query. Add oid, name to list.  If it's already in
			 * list, just return.
			 */
			/* hack until permanent type is available */
			if (type == stmt->hdbc->lobj_type)
				return SQL_LONGVARBINARY;

#ifdef	EXPERIMENTAL_CURRENTLY
			if (ALLOW_WCHAR(conn))
				return ci->drivers.unknowns_as_longvarchar ? SQL_WLONGVARCHAR : SQL_WVARCHAR;
#endif	/* EXPERIMENTAL_CURRENTLY */
			return ci->drivers.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
	}
}
Esempio n. 5
0
SQLSMALLINT
pgtype_attr_to_ctype(const ConnectionClass *conn, OID type, int atttypmod)
{
	const ConnInfo	*ci = &(conn->connInfo);
	EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
#ifdef	PG_INTERVAL_AS_SQL_INTERVAL
	SQLSMALLINT	ctype;
#endif /* PG_INTERVAL_A_SQL_INTERVAL */

	switch (type)
	{
		case PG_TYPE_INT8:
			if (!conn->ms_jet)
				return ALLOWED_C_BIGINT;
			return SQL_C_CHAR;
		case PG_TYPE_NUMERIC:
			return SQL_C_CHAR;
		case PG_TYPE_INT2:
			return SQL_C_SSHORT;
		case PG_TYPE_OID:
		case PG_TYPE_XID:
			return SQL_C_ULONG;
		case PG_TYPE_INT4:
			return SQL_C_SLONG;
		case PG_TYPE_FLOAT4:
			return SQL_C_FLOAT;
		case PG_TYPE_FLOAT8:
			return SQL_C_DOUBLE;
		case PG_TYPE_DATE:
			if (EN_is_odbc3(env))
				return SQL_C_TYPE_DATE;
			return SQL_C_DATE;
		case PG_TYPE_TIME:
			if (EN_is_odbc3(env))
				return SQL_C_TYPE_TIME;
			return SQL_C_TIME;
		case PG_TYPE_ABSTIME:
		case PG_TYPE_DATETIME:
		case PG_TYPE_TIMESTAMP_NO_TMZONE:
		case PG_TYPE_TIMESTAMP:
			if (EN_is_odbc3(env))
				return SQL_C_TYPE_TIMESTAMP;
			return SQL_C_TIMESTAMP;
		case PG_TYPE_MONEY:
			return SQL_C_FLOAT;
		case PG_TYPE_BOOL:
			return ci->drivers.bools_as_char ? SQL_C_CHAR : SQL_C_BIT;

		case PG_TYPE_BYTEA:
			return SQL_C_BINARY;
		case PG_TYPE_LO_UNDEFINED:
			return SQL_C_BINARY;
		case PG_TYPE_BPCHAR:
		case PG_TYPE_VARCHAR:
		case PG_TYPE_TEXT:
			return ansi_to_wtype(conn, SQL_C_CHAR);
		case PG_TYPE_UUID:
			if (!conn->ms_jet)
				return SQL_C_GUID;
			return ansi_to_wtype(conn, SQL_C_CHAR);

		case PG_TYPE_INTERVAL:
#ifdef	PG_INTERVAL_AS_SQL_INTERVAL
			if (ctype = get_interval_type(atttypmod, NULL), 0 != ctype)
				return ctype;
#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
			return ansi_to_wtype(conn, SQL_CHAR);

		default:
			/* hack until permanent type is available */
			if (type == conn->lobj_type)
				return SQL_C_BINARY;

			/* Experimental, Does this work ? */
#ifdef	EXPERIMENTAL_CURRENTLY
			return ansi_to_wtype(conn, SQL_C_CHAR);
#endif	/* EXPERIMENTAL_CURRENTLY */
			return SQL_C_CHAR;
	}
}
Esempio n. 6
0
SQLSMALLINT
pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
{
	const ConnInfo	*ci = &(conn->connInfo);
	EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
#ifdef	PG_INTERVAL_AS_SQL_INTERVAL
	SQLSMALLINT	sqltype;
#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
	BOOL	bLongVarchar, bFixed = FALSE;

	switch (type)
	{
		case PG_TYPE_CHAR:
			return ansi_to_wtype(conn, SQL_CHAR);
		case PG_TYPE_NAME:
		case PG_TYPE_REFCURSOR:
			return ansi_to_wtype(conn, SQL_VARCHAR);

		case PG_TYPE_BPCHAR:
			bFixed = TRUE;
		case PG_TYPE_VARCHAR:
			if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as) > ci->drivers.max_varchar_size)
				bLongVarchar = TRUE;
			else
				bLongVarchar = FALSE;
			return ansi_to_wtype(conn, bLongVarchar ? SQL_LONGVARCHAR : (bFixed ? SQL_CHAR : SQL_VARCHAR));
		case PG_TYPE_TEXT:
			bLongVarchar = ci->drivers.text_as_longvarchar;
			if (bLongVarchar)
			{
				int column_size = getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
				if (column_size > 0 &&
				    column_size <= ci->drivers.max_varchar_size)
					bLongVarchar = FALSE;
			}
			return ansi_to_wtype(conn, bLongVarchar ? SQL_LONGVARCHAR : SQL_VARCHAR);

		case PG_TYPE_BYTEA:
			if (ci->bytea_as_longvarbinary)
				return SQL_LONGVARBINARY;
			else
				return SQL_VARBINARY;
		case PG_TYPE_LO_UNDEFINED:
			return SQL_LONGVARBINARY;

		case PG_TYPE_INT2:
			return SQL_SMALLINT;

		case PG_TYPE_OID:
		case PG_TYPE_XID:
		case PG_TYPE_INT4:
			return SQL_INTEGER;

			/* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */
		case PG_TYPE_INT8:
			if (ci->int8_as != 0)
				return ci->int8_as;
			if (conn->ms_jet)
				return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
			return SQL_BIGINT;

		case PG_TYPE_NUMERIC:
			return SQL_NUMERIC;

		case PG_TYPE_FLOAT4:
			return SQL_REAL;
		case PG_TYPE_FLOAT8:
			return SQL_FLOAT;
		case PG_TYPE_DATE:
			if (EN_is_odbc3(env))
				return SQL_TYPE_DATE;
			return SQL_DATE;
		case PG_TYPE_TIME:
			if (EN_is_odbc3(env))
				return SQL_TYPE_TIME;
			return SQL_TIME;
		case PG_TYPE_ABSTIME:
		case PG_TYPE_DATETIME:
		case PG_TYPE_TIMESTAMP_NO_TMZONE:
		case PG_TYPE_TIMESTAMP:
			if (EN_is_odbc3(env))
				return SQL_TYPE_TIMESTAMP;
			return SQL_TIMESTAMP;
		case PG_TYPE_MONEY:
			return SQL_FLOAT;
		case PG_TYPE_BOOL:
			return ci->drivers.bools_as_char ? SQL_VARCHAR : SQL_BIT;
		case PG_TYPE_XML:
			return ansi_to_wtype(conn, SQL_LONGVARCHAR);
		case PG_TYPE_INET:
		case PG_TYPE_CIDR:
		case PG_TYPE_MACADDR:
			return ansi_to_wtype(conn, SQL_VARCHAR);
		case PG_TYPE_UUID:
			return SQL_GUID;

		case PG_TYPE_INTERVAL:
#ifdef	PG_INTERVAL_AS_SQL_INTERVAL
			if (sqltype = get_interval_type(atttypmod, NULL), 0 != sqltype)
				return sqltype;
#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
			return ansi_to_wtype(conn, SQL_VARCHAR);

		default:

			/*
			 * first, check to see if 'type' is in list.  If not, look up
			 * with query. Add oid, name to list.  If it's already in
			 * list, just return.
			 */
			/* hack until permanent type is available */
			if (type == conn->lobj_type)
				return SQL_LONGVARBINARY;

			bLongVarchar = ci->drivers.unknowns_as_longvarchar;
			if (bLongVarchar)
			{
				int column_size = getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
				if (column_size > 0 &&
				    column_size <= ci->drivers.max_varchar_size)
					bLongVarchar = FALSE;
			}
#ifdef	EXPERIMENTAL_CURRENTLY
			return ansi_to_wtype(conn, bLongVarchar ? SQL_LONGVARCHAR : SQL_VARCHAR);
#endif	/* EXPERIMENTAL_CURRENTLY */
			return bLongVarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
	}
}