Esempio n. 1
0
Int4
getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
{
	CSTR	func = "getCharColumnSize";
	int		p = -1, attlen = -1, adtsize = -1, maxsize;
	QResultClass	*result;
	ConnectionClass	*conn = SC_get_conn(stmt);
	ConnInfo	*ci = &(conn->connInfo);

	mylog("%s: type=%d, col=%d, unknown = %d\n", func, type, col, handle_unknown_size_as);

	/* Assign Maximum size based on parameters */
	switch (type)
	{
		case PG_TYPE_TEXT:
			if (ci->drivers.text_as_longvarchar)
				maxsize = ci->drivers.max_longvarchar_size;
			else
				maxsize = ci->drivers.max_varchar_size;
			break;

		case PG_TYPE_VARCHAR:
		case PG_TYPE_BPCHAR:
			maxsize = ci->drivers.max_varchar_size;
			break;

		default:
			if (ci->drivers.unknowns_as_longvarchar)
				maxsize = ci->drivers.max_longvarchar_size;
			else
				maxsize = ci->drivers.max_varchar_size;
			break;
	}
#ifdef	UNICODE_SUPPORT
	if (CC_is_in_unicode_driver(conn) &&
	    isSqlServr() &&
	    maxsize > 4000)
		maxsize = 4000;
#endif /* UNICODE_SUPPORT */

	if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
	{
		if (PG_VERSION_GE(SC_get_conn(stmt), 7.1))
			maxsize = 0;
		else
			maxsize = TEXT_FIELD_SIZE;
	}
	/*
	 * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This
	 * has nothing to do with a result set.
	 */
	if (col < 0)
		return maxsize;

	if (result = SC_get_Curres(stmt), NULL == result)
		return maxsize;

	/*
	 * Catalog Result Sets -- use assigned column width (i.e., from
	 * set_tuplefield_string)
	 */
	adtsize = QR_get_fieldsize(result, col);
	if (stmt->catalog_result)
	{
		if (adtsize > 0)
			return adtsize;
		return maxsize;
	}

	p = QR_get_display_size(result, col); /* longest */
	attlen = QR_get_atttypmod(result, col);
	/* Size is unknown -- handle according to parameter */
	if (attlen > 0)	/* maybe the length is known */
	{
		if (attlen >= p)
			return attlen;
		switch (type)
		{
			case PG_TYPE_VARCHAR:
			case PG_TYPE_BPCHAR:
#if (ODBCVER >= 0x0300)
				return attlen;
#else
				if (CC_is_in_unicode_driver(conn) || conn->ms_jet)
					return attlen;
				return p;
#endif /* ODBCVER */
		}
	}

	/* The type is really unknown */
	switch (handle_unknown_size_as)
	{
		case UNKNOWNS_AS_DONTKNOW:
			return -1;
		case UNKNOWNS_AS_LONGEST:
			mylog("%s: LONGEST: p = %d\n", func, p);
			if (p > 0)
				return p;
			break;
		case UNKNOWNS_AS_MAX:
			break;
		default:
			return -1;
	}
	if (maxsize <= 0)
		return maxsize;
	switch (type)
	{
		case PG_TYPE_BPCHAR:
		case PG_TYPE_VARCHAR:
		case PG_TYPE_TEXT:
			return maxsize;
	}

	if (p > maxsize)
		maxsize = p;
	return maxsize;
}
Esempio n. 2
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;
}
Esempio n. 3
0
static Int4
getCharColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
{
	int		p = -1, maxsize;
	const ConnInfo	*ci = &(conn->connInfo);

	mylog("%s: type=%d, atttypmod=%d, adtsize_or=%d, unknown = %d\n", __FUNCTION__, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);

	/* Assign Maximum size based on parameters */
	switch (type)
	{
		case PG_TYPE_TEXT:
			if (ci->drivers.text_as_longvarchar)
				maxsize = ci->drivers.max_longvarchar_size;
			else
				maxsize = ci->drivers.max_varchar_size;
			break;

		case PG_TYPE_VARCHAR:
		case PG_TYPE_BPCHAR:
			maxsize = ci->drivers.max_varchar_size;
			break;

		default:
			if (ci->drivers.unknowns_as_longvarchar)
				maxsize = ci->drivers.max_longvarchar_size;
			else
				maxsize = ci->drivers.max_varchar_size;
			break;
	}
#ifdef	UNICODE_SUPPORT
	if (CC_is_in_unicode_driver(conn) &&
	    isSqlServr() &&
	    maxsize > 4000)
		maxsize = 4000;
#endif /* UNICODE_SUPPORT */

	if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
		maxsize = 0;

	/*
	 * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This
	 * has nothing to do with a result set.
	 */
inolog("!!! atttypmod  < 0 ?\n");
	if (atttypmod < 0 && adtsize_or_longestlen < 0)
		return maxsize;

inolog("!!! adtsize_or_logngest=%d\n", adtsize_or_longestlen);
	p = adtsize_or_longestlen; /* longest */
	/*
	 * Catalog Result Sets -- use assigned column width (i.e., from
	 * set_tuplefield_string)
	 */
inolog("!!! catalog_result=%d\n", handle_unknown_size_as);
	if (UNKNOWNS_AS_LONGEST == handle_unknown_size_as)
	{
		mylog("%s: LONGEST: p = %d\n", __FUNCTION__, p);
		if (p > 0 &&
		    (atttypmod < 0 || atttypmod > p))
			return p;
	}
	if (TYPE_MAY_BE_ARRAY(type))
	{
		if (p > 0)
			return p;
		return maxsize;
	}

	/* Size is unknown -- handle according to parameter */
	if (atttypmod > 0)	/* maybe the length is known */
	{
		return atttypmod;
	}

	/* The type is really unknown */
	switch (handle_unknown_size_as)
	{
		case UNKNOWNS_AS_DONTKNOW:
			return -1;
		case UNKNOWNS_AS_LONGEST:
		case UNKNOWNS_AS_MAX:
			break;
		default:
			return -1;
	}
	if (maxsize <= 0)
		return maxsize;
	switch (type)
	{
		case PG_TYPE_BPCHAR:
		case PG_TYPE_VARCHAR:
		case PG_TYPE_TEXT:
			return maxsize;
	}

	if (p > maxsize)
		maxsize = p;
	return maxsize;
}