Yes, I agree, and the ODBC test I did gave me exactly that.
...
// Attempt to create a command object from the session object
// See IDBCreateCommand
CHECK_HR(hr = driverData_ptr->OLEDBObjects->g_pISession-
// Attempt to get cRows row handles from the provider.
hr = fileData_ptr->pRowset->GetNextRows(
DB_NULL_HCHAPTER, // hChapter
0, // lOffset
driverData_ptr->max_prefetch_rows, //
MAX_PREFETCH_ROWS
&fileData_ptr->RowsObtained, //
pcRowsObtained
&fileData_ptr->rghRows // prghRows
);
// nothing fetched out, return back with NULL data
if ( hr==DB_S_ENDOFROWSET && fileData_ptr->RowsObtained <= 0 ||
fileData_ptr->rghRows == NULL )
{
DumpError("No more rows to fetch!");
return jXDB_ENDOFFILE;
}
else
// fetched some rows, but less than we requested, which
means this is the last round
if (hr == DB_S_ENDOFROWSET && fileData_ptr->RowsObtained >
0)
{
fileData_ptr->last_round_readrowset = 1;
}
else
{
CHECK_HR(hr);
}
// Loop over the row handles obtained from GetNextRows,
// actually fetching the data for these rows into our buffer.
// each time get called, the routine returns one single row to the
caller.
unsigned int iRow = fileData_ptr->index_rows;
// Get the data for this row handle. The provider will copy
// (and convert, if necessary) the data for each of the
// columns that are described in our Aaccessor into the given
// buffer (pCurData).
CHECK_HR(hr = fileData_ptr->pRowset->GetData(
fileData_ptr->rghRows[iRow], // hRow
fileData_ptr->hAccessor, // hAccessor
pCurData // pData
));
If you run a SQL Profiler trace you'll see that you are establishing
multiple connections to SQL Server. You must only call
IDBCreateSession->CreateSession once and call
IDBCreateCommand->CreateCommand multiple times.
Attached is some OLE DB C++ that executes a basic query, sets SHOWPLAN_TEXT
ON and gets the execution plan for the basic query.
--
Cheers,
Stefan Delmarco | SQL Server MVP | http://www.fotia.co.uk/
[
OleDbShowPlan.cpp ]
#include <stdafx.h>
class OleDbCpp
{
public:
static void CanGetShowPlanText();
private:
static void GetBasicResultSet(const CComPtr<IDBCreateCommand> & createCommand);
static void SetShowPlanOn(const CComPtr<IDBCreateCommand> & createCommand);
static void GetQueryPlan(const CComPtr<IDBCreateCommand> & createCommand);
};
void OleDbCpp::CanGetShowPlanText()
{
CLSID CLSID_SQLOLEDB = {};
HRESULT hr = ::CLSIDFromProgID(L"SQLNCLI.1", &CLSID_SQLOLEDB);
if(FAILED(hr))
throw smd::ComException("CLSIDFromProgID(L\"SQLOLEDB\", ...)", hr);
CComPtr<IDBInitialize> initialize;
hr = initialize.CoCreateInstance(CLSID_SQLOLEDB, 0, CLSCTX_INPROC_SERVER);
if(FAILED(hr))
throw new smd::ComException("CoCreateInstance(CLSID_SQLOLEDB, ...) failed", hr);
DBPROP InitProperties[2] = {};
::VariantInit(&InitProperties[0].vValue);
InitProperties[0].dwPropertyID = DBPROP_INIT_PROVIDERSTRING;
InitProperties[0].vValue.vt = VT_BSTR;
InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
InitProperties[0].colid = DB_NULLID;
InitProperties[0].dwStatus = DBPROPSTATUS_OK;
InitProperties[0].vValue.bstrVal = CComBSTR("Server=tcp:chenbro,18980;Trusted_Connection=yes");
::VariantInit(&InitProperties[1].vValue);
DBPROPSET rgInitPropSet[1] = {};
rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
rgInitPropSet[0].cProperties = 2;
rgInitPropSet[0].rgProperties = InitProperties;
CComQIPtr<IDBProperties> properties = initialize;
hr = properties->SetProperties(1, rgInitPropSet);
if(FAILED(hr))
throw smd::ComException("properties->SetProperties(...) failed", hr);
hr = initialize->Initialize();
if(FAILED(hr))
throw smd::ComException("intialize->Initialize() failed", hr);
CComQIPtr<IDBCreateSession> createSession = initialize;
CComPtr<IUnknown> createCommandUnknown;
hr = createSession->CreateSession(NULL, IID_IDBCreateCommand, &createCommandUnknown);
if(FAILED(hr))
throw smd::ComException("createSession->CreateSession(...) failed", hr);
CComQIPtr<IDBCreateCommand> createCommand = createCommandUnknown;
GetBasicResultSet(createCommand);
SetShowPlanOn(createCommand);
GetQueryPlan(createCommand);
}
void OleDbCpp::GetBasicResultSet(const CComPtr<IDBCreateCommand> & createCommand)
{
std::wcout << L"Attempting to retrieve a basic resulset.." << std::endl;
CComPtr<IUnknown> commandTextUnknown;
HRESULT hr = createCommand->CreateCommand(NULL, IID_ICommandText, &commandTextUnknown);
if(FAILED(hr))
throw smd::ComException("createCommand.CreateCommand(...) failed", hr);
CComQIPtr<ICommandText> commandText = commandTextUnknown;
hr = commandText->SetCommandText(DBGUID_DEFAULT, L"SELECT TOP 10 id, name FROM sysObjects");
if(FAILED(hr))
throw smd::ComException("commandText->SetCommandText(...) failed", hr);
LONG numRows = 0;
CComPtr<IUnknown> rowsetUnknown;
hr = commandText->Execute(NULL, IID_IRowset, NULL, &numRows, &rowsetUnknown);
if(FAILED(hr))
throw smd::ComException("commandText->Execute(...) failed", hr);
CComQIPtr<IRowset> rowset = rowsetUnknown;
DBBINDING bindings[2] = {};
struct Row
{
int id;
WCHAR name[128];
};
bindings[0].iOrdinal = 1;
bindings[0].dwPart = DBPART_VALUE;
bindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
bindings[0].cbMaxLen = 4;
bindings[0].dwFlags = 0;
bindings[0].wType = DBTYPE_I4;
bindings[1].iOrdinal = 2;
bindings[1].dwPart = DBPART_VALUE;
bindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
bindings[1].cbMaxLen = 128 * 2;
bindings[1].dwFlags = 0;
bindings[1].wType = DBTYPE_WSTR;
CComQIPtr<IColumnsInfo> columnsInfo = rowset;
ULONG numColumns = 0;
DBCOLUMNINFO * dbColumnInfo;
WCHAR* stringsBuffer;
hr = columnsInfo->GetColumnInfo(&numColumns, &dbColumnInfo, &stringsBuffer);
if(FAILED(hr))
throw smd::ComException("columnsInfo->GetColumnInfo(...) failed", hr);
for(ULONG i = 0; i < numColumns; ++i)
{
std::wcout.width(40);
std::wcout << std::left << dbColumnInfo[i].pwszName;
}
std::wcout << std::endl;
CComQIPtr<IAccessor> accessor = rowset;
HACCESSOR hAccessor;
hr = accessor->CreateAccessor(DBACCESSOR_ROWDATA, numColumns, bindings, 0, &hAccessor, NULL);
if(FAILED(hr))
throw smd::ComException("accessor->CreateAccessor(...) failed", hr);
ULONG rowsRetrieved = 0;
HROW hRows[10];
HROW * rows = &hRows[0];
hr = rowset->GetNextRows(NULL, 0, 10, &rowsRetrieved, &rows);
if(FAILED(hr))
throw smd::ComException("rowset->GetNextRows(...) failed", hr);
Row row;
while(rowsRetrieved > 0)
{
for(ULONG i = 0; i < rowsRetrieved; ++i)
{
::ZeroMemory(&row, sizeof(row));
hr = rowset->GetData(hRows[i], hAccessor, &row);
if(FAILED(hr))
throw smd::ComException("rowset->GetData(...) failed", hr);
std::wcout.width(40);
std::wcout << std::left << row.id;
std::wcout.width(40);
std::wcout << std::left << row.name << std::endl;
}
hr = rowset->ReleaseRows(rowsRetrieved, hRows, NULL, NULL, NULL);
if(FAILED(hr))
throw smd::ComException("rowset->ReleaseRows(...) failed", hr);
hr = rowset->GetNextRows(NULL, 0, 10, &rowsRetrieved, &rows);
if(FAILED(hr))
throw smd::ComException("rowset->GetNextRows(...) failed", hr);
std::wcout << L"OK!\r\n" << std::endl;
}
}
void OleDbCpp::SetShowPlanOn(const CComPtr<IDBCreateCommand> & createCommand)
{
std::wcout << L"Attempting to SET SHOWPLAN_TEXT ON..." << std::endl;
CComPtr<IUnknown> commandTextUnknown;
HRESULT hr = createCommand->CreateCommand(NULL, IID_ICommandText, &commandTextUnknown);
if(FAILED(hr))
throw smd::ComException("createCommand.CreateCommand(...) failed", hr);
CComQIPtr<ICommandText> commandText = commandTextUnknown;
hr = commandText->SetCommandText(DBGUID_DEFAULT, L"SET SHOWPLAN_TEXT ON");
if(FAILED(hr))
throw smd::ComException("commandText->SetCommandText(...) failed", hr);
LONG numRows = 0;
hr = commandText->Execute(NULL, IID_NULL, NULL, &numRows, NULL);
if(FAILED(hr))
throw smd::ComException("commandText->Execute(...) failed", hr);
std::wcout << L"OK!\r\n" << std::endl;
}
void OleDbCpp::GetQueryPlan(const CComPtr<IDBCreateCommand> & createCommand)
{
std::wcout << L"Attempting to get query plan..." << std::endl;
CComPtr<IUnknown> commandTextUnknown;
HRESULT hr = createCommand->CreateCommand(NULL, IID_ICommandText, &commandTextUnknown);
if(FAILED(hr))
throw smd::ComException("createCommand.CreateCommand(...) failed", hr);
CComQIPtr<ICommandText> commandText = commandTextUnknown;
hr = commandText->SetCommandText(DBGUID_DEFAULT, L"SELECT TOP 10 id, name FROM sysObjects");
if(FAILED(hr))
throw smd::ComException("commandText->SetCommandText(...) failed", hr);
CComPtr<IUnknown> multipleRowSetsUnknown;
LONG numRows = 0;
hr = commandText->Execute(NULL, IID_IMultipleResults, NULL, &numRows, &multipleRowSetsUnknown);
if(FAILED(hr))
throw smd::ComException("commandText->Execute(...) failed", hr);
CComQIPtr<IMultipleResults> multipleRowSets = multipleRowSetsUnknown;
DBBINDING bindings[1] = {};
struct Row
{
WCHAR step[128];
};
bindings[0].iOrdinal = 1;
bindings[0].dwPart = DBPART_VALUE;
bindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
bindings[0].cbMaxLen = 128 * 2;
bindings[0].dwFlags = 0;
bindings[0].wType = DBTYPE_WSTR;
for(;;)
{
CComPtr<IUnknown> rowsetUnknown;
hr = multipleRowSets->GetResult(NULL, 0, IID_IRowset, &numRows, &rowsetUnknown);
if(FAILED(hr))
throw smd::ComException("pIMultipleResults->GetResult(...) failed", hr);
if(DB_S_NORESULT == hr)
break;
CComQIPtr<IRowset> rowset = rowsetUnknown;
CComQIPtr<IColumnsInfo> columnsInfo = rowset;
ULONG numColumns = 0;
DBCOLUMNINFO * dbColumnInfo;
WCHAR* stringsBuffer;
hr = columnsInfo->GetColumnInfo(&numColumns, &dbColumnInfo, &stringsBuffer);
if(FAILED(hr))
throw smd::ComException("columnsInfo->GetColumnInfo(...) failed", hr);
for(ULONG i = 0; i < numColumns; ++i)
{
std::wcout.width(40);
std::wcout << std::left << dbColumnInfo[i].pwszName;
}
std::wcout << std::endl;
CComQIPtr<IAccessor> accessor = rowset;
HACCESSOR hAccessor;
hr = accessor->CreateAccessor(DBACCESSOR_ROWDATA, numColumns, bindings, 0, &hAccessor, NULL);
if(FAILED(hr))
throw smd::ComException("accessor->CreateAccessor(...) failed", hr);
ULONG rowsRetrieved = 0;
HROW hRows[10];
HROW * rows = &hRows[0];
hr = rowset->GetNextRows(NULL, 0, 10, &rowsRetrieved, &rows);
if(FAILED(hr))
throw smd::ComException("rowset->GetNextRows(...) failed", hr);
Row row;
while(rowsRetrieved > 0)
{
for(ULONG i = 0; i < rowsRetrieved; ++i)
{
::ZeroMemory(&row, sizeof(row));
hr = rowset->GetData(hRows[i], hAccessor, &row);
if(FAILED(hr))
throw smd::ComException("rowset->GetData(...) failed", hr);
std::wcout.width(40);
std::wcout << std::left << row.step << std::endl;
}
hr = rowset->ReleaseRows(rowsRetrieved, hRows, NULL, NULL, NULL);
if(FAILED(hr))
throw smd::ComException("rowset->ReleaseRows(...) failed", hr);
hr = rowset->GetNextRows(NULL, 0, 10, &rowsRetrieved, &rows);
if(FAILED(hr))
throw smd::ComException("rowset->GetNextRows(...) failed", hr);
}
}
std::wcout << L"OK!\r\n" << std::endl;
}