I have an Azure Database Server with two databases. I hooked up the second table as an external table to the first table like shown here.(https://learn.microsoft.com/en-us/azure/azure-sql/database/elastic-query-vertical-partitioning)
The Problem:
When I now try to select from the second table, with ODBC, I get the SQLState: 4200 and the NativeError: 8624 with the message: "The query processor could not produce a query plan. For more information, contact Customer Support Services."
BUT this only happens when I perform SQLSetStmtAttr before the SQLExecute Statement.
Any Ideas how I can avoid this error while still performing SQLSetStmtAttr before the SQLExecute Statement?
I have a legacy application and would not like to move the SQLSetStmtAttr to another location.
Code:
#include <windows.h>
#include <sqlext.h>
#include <string>
#include <iostream>
int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLCHAR OutConnStr[255];
SQLSMALLINT OutConnStrLen;
HWND desktopHandle = GetDesktopWindow();
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
retcode = SQLDriverConnect(
hdbc,
desktopHandle,
(SQLCHAR*)"DSN=[ODBC Servername];Uid=[Username];Pwd=[Password];Database=Databasename;",
_countof("DSN=[ODBC Servername];Uid=[Username];Pwd=[Password];Database=Databasename;"),
OutConnStr,
255,
&OutConnStrLen,
SQL_DRIVER_PROMPT );
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
std::string statement = "select name FROM <ExternalTable>";
SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_ARRAY_SIZE,reinterpret_cast <SQLPOINTER> (static_cast <SQLULEN> (2)), sizeof 2);
SQLPrepare (hstmt, (SQLCHAR *) sql.data(), sql.length());
SQLRETURN excecuteRetCode = SQLExecute(hstmt);
if (excecuteRetCode == SQL_SUCCESS || excecuteRetCode == SQL_SUCCESS_WITH_INFO)
int i = 0;
else {
SQLLEN numRecs = 0;
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
int i = 1;
std::string msg;
msg.reserve (SQL_MAX_MESSAGE_LENGTH);
SQLRETURN diagRecReturn;
SQLSMALLINT msgLen;
SQLCHAR SqlState[6];
SQLINTEGER NativeError;
while (i <= numRecs && (diagRecReturn = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError,
(SQLCHAR *) msg.data (), msg.capacity (), &msgLen)) != SQL_NO_DATA)
{
i++;
}
}
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}
Does it work if you specify 1 instead of 2?
At which another location does SQLSetStmtAttr work and why is it needed at current location?
Hi Pierre,
I tried setting SQL_SOPT_SS_DEFER_PREPARE to SQL_DP_ON but it did not solve my problem.
Yes it works if i set it to 1, but 1 is the default value and I wanted to improve the perfomance so this does not help.
SQLSetStmtAttr works if I set it after SQLPrepare but if i wanted to change the location in my legacy code it would require wayyy to much work.
Sign in to comment