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;
}