ほぇ?(#^ω^)ピキピキ
デバッガでトレースしていくと、m_pAccessor のメンバが nullptr で初期化されないまま放置されていた。
で、Accessor クラスは、どこに行った?
おそらく、class template refactoring により、自分自身に継承する形になったようです。
なので、CCommand<CDynamicStringAccessor>::SetAccessor 関数を使用して自分自身を設定する必要がありました。
せっかくなので、使い方のサンプル込みで、紹介です。
#include <iostream>
#include <objbase.h>
#include <atldbcli.h>
int main(int argc, char* argv[] )
{
HRESULT hr = CoInitialize(NULL );
if(FAILED(hr)) {
std::cerr << "Fail to Initialize COM:" << hr << std::endl;
}
CDataSource ds;
// OLEDBによるODBC接続文字列
hr = ds.OpenFromInitializationString(
L"Provider=MSDASQL.1;Password=password;"
L"Persist Security Info=True;"
L"User ID=username;"
L"Data Source=odbc_data_source_name;"
L"Extended Properties=\"DSN=data_source_name;UID=username;PWD=password\""
);
CSession ss;
CCommand<CDynamicStringAccessor> rs;
hr = ss.Open(ds );
hr = rs.Open(ss, "select * from hoge" );
// CCommand<typename T>::m_pAccessor を初期化するコードが欠落しているため
// 自分自身を設定する必要がある(どこかのタイミングで混入したバグ対応)
// 2023/7/13 修正されたような気がしますが、下記コードは正しくなくなった感じがします。
// 仕様がよくわかりません。
rs.SetAccessor(&rs);
hr = rs.MoveNext();
if( FAILED(hr) || hr == DB_S_ENDOFROWSET ) {
std::cerr << "Fail to MoveNext: " << hr << std::endl;
}
// Get the column information
ULONG ulColumns = rs.GetColumnCount();
DBTYPE dbtype;
rs.GetColumnType( 1, &dbtype );
dbtype &= 0x3FFF; // DBTYPE_BYREF を除去
if(
dbtype == DBTYPE_I4
|| dbtype == DBTYPE_UI4
|| dbtype == DBTYPE_R8
|| dbtype == DBTYPE_STR
|| dbtype == DBTYPE_WSTR
|| dbtype == DBTYPE_DECIMAL
|| dbtype == DBTYPE_VARNUMERIC
|| dbtype == DBTYPE_NUMERIC
) {
// よくあるフィールド型
} else {
// 対応可能か検討が必要なフィールド型
std::cerr << "Un supported dbtype: " << dbtype << std::endl;
}
int nMax = 10;
while(nMax) {
std::string strData;
for( DBORDINAL col = 1; col <= ulColumns; col++ ) {
DBSTATUS dStatus;
DBLENGTH nLength;
rs.GetStatus( col, &dStatus );
rs.GetLength( col, &nLength );
if( col > 1 ) {
std::cout << ", ";
}
if( FAILED( dStatus ) ) {
std::cout << "<<ERROR>>";
} else if( dStatus == DBSTATUS_S_ISNULL ) {
std::cout << "<<NULL>>";
} else {
std::cout << rs.GetString(col);
}
}
std::cout << std::endl;
hr = rs.MoveNext();
if( FAILED(hr) || hr == DB_S_ENDOFROWSET ) break;
--nMax;
}
rs.Close();
ss.Close();
ds.Close();
CoUninitialize();
return 0;
}
2023/07/13 追記: バグは修正されたのか、仕様が変わったのか、よくわからない状況になりました。