I'm using Visual Studio 2010 C++ Express and connecting via ODBC to MS SQL Server 2008 R2 Express.

My question is: Is there any way I can pass some type of pointer into SqlGetData instead of an actual data type, then stuff that reference into a void pointer for the calling function to typecast/dereference?

I'd like to have a single function to handle all of my select queries, but I'm currently stumped when calling SqlGetData and supplying an appropriate SQLPOINTER in the 4th parameter.

I surrounded my trouble code (the last few parameters to pass into SqlGetData) with *****. I was able to retrieve results using a simple SELECT query that returned 11 rows of 1 column of type VARCHAR.

When looking at the DatabaseODBC::Query(...) method, the first chunk of code simply retrieves the actual query from an alias list I stored so I wouldn't have to recompile every time I modified a query. So, assume for the rest of the function that the query is SELECT Name FROM Race and that there are 11 rows in the database.

static struct _DBRow_Race
{
    SQLCHAR			Name[51];
	SQLINTEGER		NameLength;
    SQLCHAR			Visible;
	SQLINTEGER		VisibleLength;
} DBRow_Race;
static struct ColumnInfo
{
public:
	SQLCHAR			ColumnName[32];
	SQLSMALLINT		ColumnNameLength;
	SQLSMALLINT		ColumnType;
	SQLUINTEGER		ColumnSize;
	SQLSMALLINT		DecimalDigits;
	SQLSMALLINT		Nullable;
	SQLPOINTER		TargetValue;
} _ColumnInfo;
int DatabaseODBC::Query(std::string QueryName)
{
	// Check that the database connection is established
	if (SQLHandleDatabaseConnection == SQL_NULL_HDBC)
		return -1;

	SqlReturnCode = SQLAllocHandle(SQL_HANDLE_STMT, SQLHandleDatabaseConnection, &SQLHandleStatement);
	if(SqlReturnCode != SQL_SUCCESS && SqlReturnCode != SQL_SUCCESS_WITH_INFO)
		return -2;

	// Retrieve the actual query from the table of queries
	std::string GetQuery = "SELECT QueryText FROM QueryList WHERE QueryName LIKE '" + QueryName + "'";
	SqlReturnCode = SQLExecDirect(SQLHandleStatement, (SQLCHAR*)GetQuery.c_str(), SQL_NTS);
	if(SqlReturnCode != SQL_SUCCESS && SqlReturnCode != SQL_SUCCESS_WITH_INFO)
		return -3;

	std::string QueryToExecute = "";
	while (SQLFetch(SQLHandleStatement) == SQL_SUCCESS)
	{
		SqlReturnCode=SQLGetData(
						SQLHandleStatement,		//SQLHSTMT StatementHandle,
						1,				//SQLUSMALLINT ColumnNumber,
						SQL_C_CHAR,			//SQLSMALLINT TargetType,
						DBRow_QueryList.Text,		//SQLPOINTER TargetValuePtr,
						sizeof(DBRow_QueryList.Text),	//SQLINTEGER BufferLength,
						&DBRow_QueryList.TextLength);	//SQLINTEGER * StrLen_or_IndPtr
		QueryToExecute += (std::string)((char*)DBRow_QueryList.Text);
	}

	//free the statement handle so that it can be reused
	SQLFreeHandle(SQL_HANDLE_STMT, SQLHandleStatement);

	//allocate the statement handle again
	SqlReturnCode = SQLAllocHandle(SQL_HANDLE_STMT, SQLHandleDatabaseConnection, &SQLHandleStatement);
	if(SqlReturnCode != SQL_SUCCESS && SqlReturnCode != SQL_SUCCESS_WITH_INFO)
		return -2;

	//execute the query string retrieved from the QueryList table
	SqlReturnCode = SQLExecDirect(SQLHandleStatement, (SQLCHAR*)QueryToExecute.c_str(), SQL_NTS);
	if(SqlReturnCode != SQL_SUCCESS && SqlReturnCode != SQL_SUCCESS_WITH_INFO)
		return -3;

	SQLSMALLINT NumColumns;
	SqlReturnCode = SQLNumResultCols(SQLHandleStatement, &NumColumns);
	if(SqlReturnCode != SQL_SUCCESS && SqlReturnCode != SQL_SUCCESS_WITH_INFO)
		return -4;

	//Get specifications for each column in order to fetch the data
	std::vector<ColumnInfo> ColInfo;
	ColInfo.resize(NumColumns);
	for (SQLSMALLINT i=0; i<NumColumns; i++)
	{
			SQLDescribeCol (
					SQLHandleStatement,
					i+1,
					ColInfo[i].ColumnName,
					sizeof (ColInfo[i].ColumnName),
					&ColInfo[i].ColumnNameLength,
					&ColInfo[i].ColumnType,
					&ColInfo[i].ColumnSize,
					&ColInfo[i].DecimalDigits,
					&ColInfo[i].Nullable);
			//convert to SQL_CHAR if necessary so SqlGetData knows how to process
			switch (ColInfo[i].ColumnType)
			{
			case SQL_VARCHAR : ColInfo[i].ColumnType = SQL_CHAR; break;
			default : break;
			}

			std::cout<<"Hello"<<std::endl;

	}
	std::string Result = "";

	int IndexRow	= 0;
	while (SQLFetch(SQLHandleStatement) == SQL_SUCCESS)
	{
		for (SQLSMALLINT IndexColumn=0; IndexColumn < NumColumns; IndexColumn++)
		{
			SqlReturnCode=SQLGetData(
						SQLHandleStatement,			//SQLHSTMT StatementHandle,
					IndexColumn+1,				//SQLUSMALLINT ColumnNumber, starting at 1
						ColInfo[IndexColumn].ColumnType,	//SQLSMALLINT TargetType,
//****************************************************
//						DBRow_Race.Name,			//SQLPOINTER TargetValuePtr,
						_ColumnInfo.TargetValue,		//SQLPOINTER TargetValuePtr,
						sizeof(DBRow_Race.Name),	//SQLINTEGER BufferLength,
						&DBRow_Race.NameLength);//SQLINTEGER * StrLen_or_IndPtr
//****************************************************

//			Result is being used for now just to test my first case. In the end, data will be stored in a two dimensional array of void pointers for the other parts of the application to typecast and dereference
//			Result += (std::string)((char*)DBRow_Race.Name);
			Result += (std::string)((char*)_ColumnInfo.TargetValue);
		}
		IndexRow++;
	}

	//Release the query's handle from memory
	if (SQLHandleStatement != SQL_NULL_HSTMT)
		SQLFreeHandle(SQL_HANDLE_STMT, SQLHandleStatement);
	
	return 0;
}

I guess spending 10 minutes fixing the tabbing didn't work. If anyone needs me to post the code again without words wrapping, let me know.

This article has been dead for over six months. Start a new discussion instead.