Почему OLE DB IRowset.Нарушение доступа getnextrow

#sql-server #com #oledb

#sql-сервер #com #oledb

Вопрос:

Я использую OLE DB для извлечения некоторых данных с SQL server, схема кода такова

 m_spCmd->SetCommandText(DBGUID_DEFAULT,L"SELECT * FROM sys.DM_OS_PERFORMANCE_COUNTERS"); // S_OK
CComPtr<IRowset> result;
m_spCmd->Execute(nullptr,__uuidof(IRowset),nullptr,nullptr,(IUnknown**)amp;result); // S_OK
DBCOUNTITEM fetched;
HROW *hrow;
result->GetNextRows(DB_NULL_HCHAPTER,0,1,amp;fetched,amp;hrow);  // A
  

при A я получил access violation exception (что означает, что что-то равно нулю, result само по себе не равно нулю). Мне кажется, я пропустил какой-то шаг (ы) в коде, что это? Большое спасибо!!!

Обновить

  1. sqlcmd.h
 #pragma once

#include <windows.h>
#include <msdaguid.h>
#include <msdasql.h>
#include <oledb.h>
#include <oledberr.h>
#include <iostream>
#include <atlbase.h>
#include <atldbcli.h>

using namespace std;

struct SQLCmd
{
  SQLCmd();
  ~SQLCmd();
private:
  template<typename T> void print(T);
private:
  CComPtr<IDBInitialize>  m_spDb;
  CComPtr<IDBProperties>  m_spDbProperty;
  CComPtr<ISessionProperties> m_spSsProperty;
  CComPtr<ICommandText> m_spCmd;
  CComPtr<ISQLErrorInfo> m_spErr;
  CComPtr<IAccessor> m_spAccessor;
  CComPtr<IDBCreateSession> m_spCrsession;
  HRESULT hr;
};
  
  1. sqlcmd.cpp
 #include "sqlcmd.h"

template<> 
void SQLCmd::print(CComPtr<IRowset> ptr)
{
  DBORDINAL count;
  DBCOLUMNINFO *info;
  OLECHAR *buf;
  
  auto accessor = CComQIPtr<IAccessor>(ptr);
  auto colinfo = CComQIPtr<IColumnsInfo>(ptr);
  colinfo->GetColumnInfo(amp;count,amp;info,amp;buf);
  
  /*
  DBBINDING *bindings = new DBBINDING[count];
  memset(bindings,0,sizeof(DBBINDING)*count);

  DBBINDSTATUS *bindingstatus = new DBBINDSTATUS[count];
  memset(bindingstatus,0,sizeof(DBBINDSTATUS)*count);
  
  DBBYTEOFFSET offset = 0;
  int rowsize = 0;
  for(int i = 0 ; i < count ; i  )
  {
    auto amp;[pwszName,pTypeInfo,iOrdinal,dwFlags,ulColumnSize,wType,bPrecision,bScale,columnid] = info[i];
    bindings[i].iOrdinal = iOrdinal;
    bindings[i].obValue = offset;
    bindings[i].wType = wType;
    bindings[i].dwPart = DBPART_VALUE;
    bindings[i].bPrecision = bPrecision;
    bindings[i].bScale = bScale;
    offset  = ulColumnSize;
    rowsize  = ulColumnSize;
    printf("%ws %lld %dn",pwszName,ulColumnSize,wType);
  }
  
  HACCESSOR haccessor;
  hr = accessor->CreateAccessor(DBACCESSOR_ROWDATA,count,bindings,rowsize,amp;haccessor,bindingstatus);
  printf("CreateAccessor %x %llxn",hr,haccessor);
  for(int i = 0 ; i < count ; i  )
    if(DBBINDSTATUS_OK != bindingstatus[i])
      printf("%d - %dn",i,bindingstatus[i]);*/
  
  DBCOUNTITEM fetched;
  HROW *hrow;
  printf("before GetNextRowsn");
  hr = ptr->GetNextRows(DB_NULL_HCHAPTER,0,1,amp;fetched,amp;hrow);  
  printf("GetNextRows %x %lldn",hr,fetched);
}

SQLCmd::SQLCmd()
{
  GUID msoledbsql;
  CLSIDFromString(L"{5A23DE84-1D7B-4A16-8DED-B29C09CB648D}",amp;msoledbsql);
  m_spDb.CoCreateInstance(msoledbsql);
  
  m_spDbProperty = CComQIPtr<IDBProperties>(m_spDb);
  CDBPropSet set(DBPROPSET_DBINIT);
  set.AddProperty(DBPROP_AUTH_INTEGRATED,L"SSPI");
  set.AddProperty(DBPROP_INIT_CATALOG,L"master");
  set.AddProperty(DBPROP_INIT_DATASOURCE,L"localhost");
  m_spDbProperty->SetProperties(1,amp;set);
  
  m_spDb->Initialize();

  auto m_spCrsession = CComQIPtr<IDBCreateSession>(m_spDb);
  if (!!m_spCrsession)
  {
    hr = m_spCrsession->CreateSession(nullptr,__uuidof(ISessionProperties),(IUnknown**)amp;m_spSsProperty);
    auto _ = CComQIPtr<IDBCreateCommand>(m_spSsProperty);
    if (!!_)
      hr = _->CreateCommand(nullptr,__uuidof(ICommandText),(IUnknown**)amp;m_spCmd);      
  }
  
  CComPtr<IRowset> result;
  hr = m_spCmd->SetCommandText(DBGUID_DEFAULT,L"SELECT * FROM sys.DM_OS_PERFORMANCE_COUNTERS");
  printf("SetCommandText 0x%xn",hr);
  DBROWCOUNT rowcount;
  hr = m_spCmd->Execute(nullptr,__uuidof(IRowset),nullptr,amp;rowcount,(IUnknown**)amp;result);
  printf("Execute 0x%x %lldn",hr,rowcount);
  if (!!result)
  {
    print(result);
  } 
}

SQLCmd::~SQLCmd()
{
  if (!!m_spDb) m_spDb->Uninitialize();
}
  
  1. test.cpp
 #include "sqlcmd.h"
int main()
{
  CoInitialize(nullptr);
  SQLCmd cmd;
}
  
  1. скомпилировать
 cl /nologo /EHsc /std:c  latest test.cpp sqlcmd.cpp /link /debug
  
  1. выполнить
 >test
SetCommandText 0x0
Execute 0x0 -1
before GetNextRows
  

Комментарии:

1. У вас есть полный небольшой воспроизводящий код?

2. Загрузил код для проверки 🙂

Ответ №1:

Документация IRowset::getnextrow: гласит следующее

Если *prghRows не является нулевым указателем при вводе, это должен быть указатель на выделенную потребителем память, достаточно большую, чтобы возвращать дескрипторы запрошенного количества строк. Если выделенная потребителем память больше, чем необходимо, поставщик заполняет столько дескрипторов строк, сколько указано в pcRowsObtained; содержимое оставшейся памяти не определено.

Таким образом, вы не можете передать случайный указатель на ввод. Вы должны установить для него значение valid или NULL:

 HROW* hrow = NULL;