Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1558 lines
45 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: qryperf.CXX
  7. //
  8. // Contents: performance test program
  9. //
  10. // History: 16 March 1996 dlee Created (from fsdbdrt)
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.cxx"
  14. #pragma hdrstop
  15. #define STRESS
  16. #ifdef STRESS
  17. #define GET_DATA_TOO
  18. unsigned cThreads = 8;
  19. const unsigned cLoopTimes = 0xffffffff;
  20. WCHAR *pwcCatalog = L"system";
  21. WCHAR *pwcMachine = L".";
  22. BOOL g_fStopNow = FALSE;
  23. const unsigned cmsSleep = 3000; // 0
  24. unsigned g_cmsSleep;
  25. BOOL g_fFetchRowsAtWill = TRUE;
  26. #else
  27. const unsigned cThreads = 8;
  28. const unsigned cLoopTimes = 1000;
  29. WCHAR *pwcCatalog = L"encarta";
  30. WCHAR *pwcMachine = L".";
  31. #endif
  32. BOOL g_fSQL = FALSE;
  33. #define DBINITCONSTANTS
  34. #include <crt\io.h>
  35. #include <time.h>
  36. #include <process.h>
  37. #include <propvar.h>
  38. #include <olectl.h>
  39. #include <doquery.hxx>
  40. WCHAR g_awcCatalog[ MAX_PATH ];
  41. WCHAR g_awcMachine[ MAX_PATH ];
  42. BOOL g_fSequential = FALSE;
  43. template<class T> T Rand2( T t ) { return (T) abs( (int) ( rand() % t ) ); }
  44. template<class T> T Rand( T t ) { return (T) abs( GetTickCount() % t ); }
  45. CCoTaskAllocator CoTaskAllocator;
  46. void * CCoTaskAllocator::Allocate(ULONG cbSize)
  47. {
  48. return CoTaskMemAlloc( cbSize );
  49. }
  50. void CCoTaskAllocator::Free( void *pv )
  51. {
  52. CoTaskMemFree( pv );
  53. }
  54. BOOL isEven(unsigned n)
  55. {
  56. return ( 0 == ( n & 1 ) );
  57. }
  58. static const GUID guidSystem = PSGUID_STORAGE;
  59. static const GUID guidQuery = PSGUID_QUERY;
  60. static const GUID guidRowsetProps = DBPROPSET_ROWSET;
  61. static CDbColId psName( guidSystem, PID_STG_NAME );
  62. static CDbColId psPath( guidSystem, PID_STG_PATH );
  63. static CDbColId psSize( guidSystem, PID_STG_SIZE );
  64. static CDbColId psWriteTime( guidSystem, PID_STG_WRITETIME );
  65. static CDbColId psContents( guidSystem, PID_STG_CONTENTS );
  66. static CDbColId psRank( guidQuery, DISPID_QUERY_RANK );
  67. static CDbColId * aColIds[] =
  68. {
  69. &psName, &psPath, &psSize, &psWriteTime, &psRank
  70. };
  71. static ULONG cColIds = sizeof aColIds / sizeof aColIds[0];
  72. CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode * pRst,
  73. CDbColumns & Cols,
  74. CDbSortSet * pSort );
  75. IRowsetScroll * InstantiateRowset(
  76. ICommand *pCommandIn,
  77. DWORD dwDepth,
  78. LPWSTR pwszScope,
  79. XPtr<CDbCmdTreeNode> & xTree,
  80. WCHAR const * pwcQuery,
  81. REFIID riid,
  82. BOOL fAsynchronous );
  83. HACCESSOR MapColumns(
  84. IUnknown * pUnknown,
  85. ULONG cCols,
  86. DBBINDING * pBindings,
  87. const DBID * pColIds );
  88. void ReleaseAccessor( IUnknown * pUnknown, HACCESSOR hAcc );
  89. DWORD __stdcall RunPerfTest(void *pv);
  90. void LogError( char const * pszFormat, ... );
  91. void GetProcessInfo(
  92. WCHAR * pwcImage,
  93. LARGE_INTEGER & liUserTime,
  94. LARGE_INTEGER & liKernelTime,
  95. ULONG & cHandles,
  96. ULONGLONG & cbWorkingSet,
  97. ULONGLONG & cbPeakWorkingSet,
  98. ULONGLONG & cbPeakVirtualSize,
  99. ULONGLONG & cbNonPagedPoolUsage,
  100. ULONGLONG & cbPeakNonPagedPoolUsage );
  101. inline _int64 mkTime( FILETIME ft )
  102. {
  103. return (_int64) ft.dwLowDateTime +
  104. ( ( (_int64 ) ft.dwHighDateTime ) << 32 );
  105. } //mkTime
  106. inline _int64 mkTime( FILETIME ftK, FILETIME ftU )
  107. {
  108. return mkTime( ftK ) + mkTime( ftU );
  109. } //mkTime
  110. inline _int64 mkTime( LARGE_INTEGER li )
  111. {
  112. return (_int64) li.LowPart +
  113. ( ( (_int64) li.HighPart ) << 32 );
  114. } //mkTime
  115. inline _int64 mkTime( LARGE_INTEGER liK, LARGE_INTEGER liU )
  116. {
  117. return mkTime( liK ) + mkTime( liU );
  118. } //mkTime
  119. void GetCiSvcTimes(
  120. LARGE_INTEGER & liCiSvcKernelTime,
  121. LARGE_INTEGER & liCiSvcUserTime )
  122. {
  123. ULONG cHandles;
  124. ULONGLONG cbWorkingSet;
  125. ULONGLONG cbPeakWorkingSet;
  126. ULONGLONG cbPeakVirtualSize;
  127. ULONGLONG cbNonPagedPoolUsage;
  128. ULONGLONG cbPeakNonPagedPoolUsage;
  129. GetProcessInfo( L"cisvc.exe",
  130. liCiSvcUserTime,
  131. liCiSvcKernelTime,
  132. cHandles,
  133. cbWorkingSet,
  134. cbPeakWorkingSet,
  135. cbPeakVirtualSize,
  136. cbNonPagedPoolUsage,
  137. cbPeakNonPagedPoolUsage );
  138. } //GetCiSvcTimes
  139. void RunQuerySuite()
  140. {
  141. HANDLE ah[ 200 ];
  142. DWORD dwID;
  143. for ( unsigned x = 0; x < cThreads; x++ )
  144. {
  145. #ifdef STRESS
  146. Sleep( GetCurrentThreadId() );
  147. #endif // STRESS
  148. ah[x] = CreateThread( 0,
  149. 65536,
  150. RunPerfTest,
  151. 0,
  152. 0,
  153. &dwID );
  154. }
  155. WaitForMultipleObjects( cThreads, ah, TRUE, INFINITE );
  156. for ( x = 0; x < cThreads; x++ )
  157. CloseHandle( ah[x] );
  158. } //RunQuerySuite
  159. void Usage()
  160. {
  161. printf( "usage: qryperf [-c:catalog] [-m:machine] [-d:delay(ms)] [-q(onarch)] [-s:(0|1)] [-t:threads] -f(etch at will)\n" );
  162. exit(1);
  163. } //Usage
  164. extern "C" int __cdecl wmain( int argc, WCHAR * argv[] )
  165. {
  166. HRESULT hr = CoInitialize( 0 );
  167. if ( FAILED( hr ) )
  168. exit( 1 );
  169. wcscpy( g_awcCatalog, pwcCatalog );
  170. wcscpy( g_awcMachine, pwcMachine );
  171. #ifdef STRESS
  172. g_cmsSleep = cmsSleep;
  173. #endif
  174. for ( int i = 1; i < argc; i++ )
  175. {
  176. if ( '/' == argv[i][0] || '-' == argv[i][0] )
  177. {
  178. WCHAR c = (WCHAR) tolower( argv[i][1] );
  179. if ( L':' != argv[i][2] && c != L'q' && c != 'f' )
  180. Usage();
  181. if ( L'c' == c )
  182. {
  183. if ( wcslen( argv[i] + 3 ) >= MAX_PATH )
  184. Usage();
  185. wcscpy( g_awcCatalog, argv[i] + 3 );
  186. }
  187. else if ( L'm' == c )
  188. {
  189. if ( wcslen( argv[i] + 3 ) >= MAX_PATH )
  190. Usage();
  191. wcscpy( g_awcMachine, argv[i] + 3 );
  192. }
  193. #ifdef STRESS
  194. else if ( L'd' == c )
  195. g_cmsSleep = _wtoi( argv[i] + 3 );
  196. else if ( 't' == c )
  197. cThreads = _wtoi( argv[i] + 3 );
  198. else if ( 'f' == c )
  199. g_fFetchRowsAtWill = FALSE;
  200. #endif
  201. else if ( 'q' == c )
  202. g_fSQL = TRUE;
  203. else if ( L's' == c )
  204. g_fSequential = _wtoi( argv[i] + 3 );
  205. else
  206. Usage();
  207. }
  208. else
  209. Usage();
  210. }
  211. HANDLE hproc = GetCurrentProcess();
  212. FILETIME ftCreate,ftExit,ftKernel,ftUser;
  213. GetProcessTimes( hproc, &ftCreate, &ftExit, &ftKernel, &ftUser );
  214. _int64 openTime = mkTime( ftKernel, ftUser );
  215. {
  216. CI_STATE state;
  217. state.cbStruct = sizeof state;
  218. CIState( g_awcCatalog, g_awcMachine, &state );
  219. }
  220. LARGE_INTEGER liCiSvcUserTime;
  221. LARGE_INTEGER liCiSvcKernelTime;
  222. GetCiSvcTimes( liCiSvcKernelTime, liCiSvcUserTime );
  223. _int64 ciStartTime = mkTime( liCiSvcKernelTime, liCiSvcUserTime );
  224. GetProcessTimes( hproc, &ftCreate, &ftExit, &ftKernel, &ftUser );
  225. _int64 startTime = mkTime( ftKernel, ftUser );
  226. RunQuerySuite();
  227. CIShutdown();
  228. GetProcessTimes( hproc, &ftCreate, &ftExit, &ftKernel, &ftUser );
  229. _int64 endTime = mkTime( ftKernel, ftUser );
  230. GetCiSvcTimes( liCiSvcKernelTime, liCiSvcUserTime );
  231. _int64 ciEndTime = mkTime( liCiSvcKernelTime, liCiSvcUserTime );
  232. #ifdef STRESS
  233. printf( "stress test client time: %d ms cisvc time: %d ms\n",
  234. (DWORD) ((endTime - startTime) / 10000 ),
  235. (DWORD) ((ciEndTime - ciStartTime) / 10000 ) );
  236. #else
  237. printf( "%s test client time: %d ms cisvc time: %d ms\n",
  238. g_fSequential ? "sequential" : "non-sequential",
  239. (DWORD) ((endTime - startTime) / 10000 ),
  240. (DWORD) ((ciEndTime - ciStartTime) / 10000 ) );
  241. #endif
  242. CoUninitialize();
  243. return 0;
  244. } //main
  245. #ifdef GET_DATA_TOO
  246. class CBookMark
  247. {
  248. public:
  249. CBookMark() : cbBmk (0) {}
  250. CBookMark( DBBOOKMARK bmkSpecial ) : cbBmk (1)
  251. {
  252. abBmk[0] = (BYTE) bmkSpecial;
  253. }
  254. BOOL IsValid() const { return 0 != cbBmk; }
  255. void Invalidate () { cbBmk = 0; }
  256. BOOL IsEqual ( CBookMark& bmk)
  257. {
  258. if (cbBmk != bmk.cbBmk)
  259. return FALSE;
  260. return memcmp ( abBmk, bmk.abBmk, cbBmk ) == 0;
  261. }
  262. void MakeFirst()
  263. {
  264. cbBmk = sizeof (BYTE);
  265. abBmk[0] = (BYTE) DBBMK_FIRST;
  266. }
  267. BOOL IsFirst()
  268. {
  269. return cbBmk == sizeof(BYTE) && abBmk[0] == (BYTE) DBBMK_FIRST;
  270. }
  271. DBLENGTH cbBmk;
  272. BYTE abBmk[ 50 ];
  273. };
  274. void FetchAtWill(
  275. IRowset * pRowset,
  276. IUnknown * pAccessor,
  277. HACCESSOR hAccessor,
  278. DBCOUNTITEM cHits )
  279. {
  280. if ( 0 == cHits )
  281. return;
  282. XInterface<IRowsetScroll> xRS;
  283. SCODE sc = pRowset->QueryInterface( IID_IRowsetScroll, xRS.GetQIPointer() );
  284. if ( FAILED( sc ) )
  285. {
  286. LogError( "Can't QI for IID_IRowsetScroll\n" );
  287. return;
  288. }
  289. const DBROWCOUNT cMaxToGet = 8;
  290. HROW aHRows[ cMaxToGet ];
  291. HROW * paHRows = aHRows;
  292. // Fetch relative to first
  293. const BYTE bmkFirst = (BYTE) DBBMK_FIRST;
  294. for ( unsigned i = 0; i < 5 && !g_fStopNow; i++ )
  295. {
  296. DBCOUNTITEM cRows;
  297. DBROWCOUNT cToGet = 1 + Rand2( cMaxToGet - 1 );
  298. DBROWOFFSET iStart = Rand2( cHits );
  299. sc = xRS->GetRowsAt( 0, 0, 1, &bmkFirst, iStart, cToGet, &cRows, &paHRows );
  300. if ( SUCCEEDED( sc ) )
  301. xRS->ReleaseRows( cRows, aHRows, 0, 0, 0 );
  302. else
  303. LogError( "can't get %d rows at %d out of %d\n", cToGet, iStart, cHits );
  304. }
  305. // Fetch relative to last
  306. const BYTE bmkLast = (BYTE) DBBMK_LAST;
  307. for ( i = 0; i < 5 && !g_fStopNow; i++ )
  308. {
  309. DBCOUNTITEM cRows;
  310. DBROWCOUNT cToGet = 1 + Rand2( cMaxToGet - 1 );
  311. DBROWOFFSET iStart = Rand2( cHits );
  312. sc = xRS->GetRowsAt( 0, 0, 1, &bmkLast, -iStart, cToGet, &cRows, &paHRows );
  313. if ( SUCCEEDED( sc ) )
  314. xRS->ReleaseRows( cRows, aHRows, 0, 0, 0 );
  315. else
  316. LogError( "can't get %d rows at %d from last out of %d\n", cToGet, -iStart, cHits );
  317. }
  318. // Fetch relative to a random location
  319. static GUID guidBmk = DBBMKGUID;
  320. static CDbColId dbcolBookMark( guidBmk, PROPID_DBBMK_BOOKMARK );
  321. DBBINDING aBmkColumn[] = { 0, sizeof DBLENGTH, 0, 0, 0, 0, 0,
  322. DBPART_VALUE | DBPART_LENGTH,
  323. DBMEMOWNER_CLIENTOWNED,
  324. DBPARAMIO_NOTPARAM,
  325. 50,
  326. 0,
  327. DBTYPE_BYTES,
  328. 0, 0 };
  329. XInterface<IAccessor> xAccessor;
  330. sc = xRS->QueryInterface( IID_IAccessor, xAccessor.GetQIPointer() );
  331. if ( FAILED( sc ) )
  332. {
  333. LogError( "can't create bookmark accessor IAccessor: %#x\n", sc );
  334. return;
  335. }
  336. HACCESSOR hBmkAccessor;
  337. sc = xAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
  338. 1,
  339. aBmkColumn,
  340. 0,
  341. &hBmkAccessor,
  342. 0 );
  343. if ( FAILED(sc) )
  344. {
  345. LogError( "can't create accessor\n" );
  346. return;
  347. }
  348. HROW aBmkHRows[ 1 ];
  349. HROW * paBmkHRows = aBmkHRows;
  350. DBROWOFFSET iBmkStart = Rand2( cHits );
  351. DBCOUNTITEM cBmkRows;
  352. sc = xRS->GetRowsAt( 0, 0, 1, &bmkFirst, iBmkStart, 1, &cBmkRows, &paBmkHRows );
  353. if ( SUCCEEDED( sc ) )
  354. {
  355. CBookMark bmk;
  356. sc = xRS->GetData( aBmkHRows[0], hBmkAccessor, &bmk );
  357. if ( SUCCEEDED( sc ) && ( DB_S_ERRORSOCCURRED != sc ) )
  358. {
  359. for ( unsigned i = 0; i < 5 && !g_fStopNow; i++ )
  360. {
  361. DBCOUNTITEM cRows;
  362. DBROWCOUNT cToGet = 1 + Rand2( cMaxToGet - 1 );
  363. DBROWOFFSET iStart = Rand2( cHits ) - iBmkStart;
  364. sc = xRS->GetRowsAt( 0, 0, bmk.cbBmk, bmk.abBmk, iStart,
  365. cToGet, &cRows, &paHRows );
  366. if ( SUCCEEDED( sc ) )
  367. xRS->ReleaseRows( cRows, aHRows, 0, 0, 0 );
  368. else
  369. LogError( "can't getrowsat %d rows %d relative to bmk at %d, rowset has %d: %#x\n",
  370. cToGet, iStart, iBmkStart, cHits, sc );
  371. }
  372. }
  373. else
  374. LogError( "can't GetData the bmk row: %#x\n", sc );
  375. xRS->ReleaseRows( 1, aBmkHRows, 0, 0, 0 );
  376. }
  377. else
  378. LogError( "can't GetRowsAt the bmk row: %#x\n", sc );
  379. ReleaseAccessor( pAccessor, hBmkAccessor );
  380. } //FetchAtWill
  381. #endif
  382. static DBBINDING aPropTestCols[] =
  383. {
  384. { 0,(sizeof ULONG_PTR)*0,0,0,0,0,0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0 },
  385. { 0,(sizeof ULONG_PTR)*1,0,0,0,0,0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0 },
  386. { 0,(sizeof ULONG_PTR)*2,0,0,0,0,0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0 },
  387. { 0,(sizeof ULONG_PTR)*3,0,0,0,0,0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0 },
  388. { 0,(sizeof ULONG_PTR)*4,0,0,0,0,0, DBPART_VALUE, DBMEMOWNER_PROVIDEROWNED, DBPARAMIO_NOTPARAM, 0, 0, DBTYPE_VARIANT|DBTYPE_BYREF, 0, 0 },
  389. };
  390. void RunPerfQuery(
  391. CDbRestriction & CiRst,
  392. WCHAR const * pwcQuery,
  393. unsigned cExpectedHits,
  394. ICommand * pCommand,
  395. BOOL fSeq,
  396. BOOL fAsynchronous )
  397. {
  398. CDbColumns cols( 5 );
  399. BOOL fOk = cols.Add( psName, 0 );
  400. if ( fOk )
  401. cols.Add( psSize, 1 );
  402. if ( fOk )
  403. cols.Add( psWriteTime, 2 );
  404. if ( fOk )
  405. cols.Add( psPath, 3 );
  406. if ( fOk )
  407. cols.Add( psRank, 4 );
  408. if ( !fOk )
  409. {
  410. LogError(" can't create column specification\n" );
  411. return;
  412. }
  413. unsigned cRetries = 0;
  414. DBCOUNTITEM cRowsReturned = 0;
  415. IRowset * pRowset = 0;
  416. {
  417. CDbSortSet ss( 1 );
  418. #ifdef STRESS
  419. int x = Rand( cColIds );
  420. int y = rand();
  421. fOk = ss.Add( *aColIds[x],
  422. isEven( rand() ) ? QUERY_SORTDESCEND : QUERY_SORTASCEND,
  423. 0 );
  424. #else
  425. fOk = ss.Add( psRank, QUERY_SORTDESCEND, 0);
  426. #endif
  427. if ( !fOk )
  428. {
  429. LogError(" can't create sort specification\n" );
  430. return;
  431. }
  432. XPtr<CDbCmdTreeNode> xCmdTree( FormQueryTree( &CiRst,
  433. cols,
  434. fSeq ? 0 : &ss ) );
  435. if ( xCmdTree.IsNull() )
  436. return;
  437. pRowset = InstantiateRowset( pCommand,
  438. QUERY_DEEP, // Depth
  439. L"\\", // Scope
  440. xCmdTree, // DBCOMMANDTREE
  441. pwcQuery,
  442. fSeq ? IID_IRowset :
  443. IID_IRowsetScroll,
  444. fAsynchronous );
  445. if ( 0 == pRowset )
  446. {
  447. LogError(" can't get rowset\n" );
  448. return;
  449. }
  450. XInterface<IRowset> xRowset( pRowset );
  451. #ifdef GET_DATA_TOO
  452. // Get data
  453. DBID aDbCols[5];
  454. aDbCols[0] = psName;
  455. aDbCols[1] = psSize;
  456. aDbCols[2] = psWriteTime;
  457. aDbCols[3] = psPath;
  458. aDbCols[4] = psRank;
  459. IUnknown * pAccessor = pRowset;
  460. HACCESSOR hAccessor = MapColumns( pAccessor,
  461. 5,
  462. aPropTestCols,
  463. aDbCols );
  464. if ( 0 == hAccessor )
  465. return;
  466. #endif // GET_DATA_TOO
  467. DBCOUNTITEM cTotal = 0;
  468. #ifdef STRESS
  469. const unsigned cFetchPasses = g_fFetchRowsAtWill ? 1000 : 5;
  470. #else
  471. const unsigned cFetchPasses = 3;
  472. #endif
  473. for ( unsigned i = 0; i < cFetchPasses; i++ )
  474. {
  475. #ifdef STRESS
  476. if ( g_fStopNow )
  477. break;
  478. #endif
  479. HROW aHRow[10];
  480. HROW * pgrhRows = aHRow;
  481. SCODE sc = pRowset->GetNextRows(0, 0, 10, &cRowsReturned, &pgrhRows);
  482. if ( FAILED( sc ) )
  483. {
  484. LogError( "'%ws' IRowset->GetNextRows returned 0x%x, cTotal: %d, cRowsReturned: %d\n",
  485. pwcQuery, sc, cTotal, cRowsReturned );
  486. break;
  487. }
  488. cTotal += cRowsReturned;
  489. #ifdef GET_DATA_TOO
  490. PROPVARIANT* data[5];
  491. for ( ULONG r = 0; r < cRowsReturned; r++ )
  492. {
  493. SCODE sc = pRowset->GetData( pgrhRows[r],
  494. hAccessor,
  495. &data );
  496. }
  497. #endif // GET_DATA_TOO
  498. if ( 0 != cRowsReturned )
  499. pRowset->ReleaseRows( cRowsReturned, pgrhRows, 0, 0, 0 );
  500. if ( DB_S_ENDOFROWSET == sc )
  501. break;
  502. }
  503. #ifdef GET_DATA_TOO
  504. if ( !fSeq && g_fFetchRowsAtWill )
  505. FetchAtWill( pRowset, pAccessor, hAccessor, cTotal );
  506. ReleaseAccessor( pAccessor, hAccessor );
  507. //printf( "query %ws returned %d hits\n", pwcQuery, cTotal );
  508. #endif // GET_DATA_TOO
  509. if ( 0 == cTotal )
  510. printf( "query %ws returned no hits\n", pwcQuery );
  511. #if 0
  512. if ( cTotal < __min( 30, cExpectedHits ) )
  513. printf( "query %ws returned %d hits, expecting %d\n",
  514. pwcQuery, cTotal, cExpectedHits );
  515. #endif
  516. }
  517. } //RunPerfQuery
  518. struct SQuery
  519. {
  520. WCHAR const * pwcQuery;
  521. unsigned cEncartaHits;
  522. };
  523. static SQuery aQueries[] =
  524. {
  525. #ifdef STRESS
  526. { L"stereo", 4 },
  527. { L"flex", 2 },
  528. { L"agassi", 1 },
  529. { L"detroit", 108 },
  530. { L"miami", 60 },
  531. { L"edison", 25 },
  532. { L"bulb", 33 },
  533. { L"elephant", 87 },
  534. { L"radius", 43 },
  535. { L"amplifier", 17 },
  536. { L"drunk", 10 },
  537. { L"grunt", 3 },
  538. { L"war", 4241 },
  539. { L"peace", 812 },
  540. { L"river", 3402 },
  541. { L"not", 4002 },
  542. { L"city", 5567 },
  543. { L"century", 4470 },
  544. #else
  545. { L"stereo", 4 },
  546. { L"flex", 2 },
  547. { L"agassi", 1 },
  548. { L"detroit", 108 },
  549. { L"miami", 60 },
  550. { L"edison", 25 },
  551. { L"web", 57 },
  552. { L"bulb", 33 },
  553. { L"microsoft", 15 },
  554. { L"elephant", 87 },
  555. { L"radius", 43 },
  556. { L"amplifier", 17 },
  557. { L"drunk", 10 },
  558. { L"grunt", 3 },
  559. #endif // STRESS
  560. };
  561. DWORD __stdcall RunPerfTest(void *pv)
  562. {
  563. static long cQueriesSoFar = 0;
  564. // #ifdef STRESS
  565. // srand( GetTickCount() + GetCurrentThreadId() );
  566. // #endif
  567. XInterface<ICommand> xCommand;
  568. do
  569. {
  570. ICommand * pCommand = 0;
  571. SCODE sc = CICreateCommand( (IUnknown **) &pCommand,
  572. 0,
  573. IID_ICommand,
  574. g_awcCatalog,
  575. g_awcMachine );
  576. if ( FAILED( sc ) )
  577. LogError( "CICreateCommand failed: 0x%x\n", sc );
  578. else
  579. xCommand.Set( pCommand );
  580. } while ( xCommand.IsNull() );
  581. for ( int x = 0; x < cLoopTimes; x++ )
  582. {
  583. try
  584. {
  585. const int cQueries = sizeof aQueries / sizeof aQueries[0];
  586. #ifdef STRESS
  587. int j = Rand( cQueries );
  588. #else
  589. int j = ( x % cQueries );
  590. #endif // STRESS
  591. CDbContentRestriction CiRst( aQueries[j].pwcQuery, psContents );
  592. if ( !CiRst.IsValid() )
  593. continue;
  594. #ifdef STRESS
  595. if ( 0 != g_cmsSleep )
  596. Sleep( Rand( g_cmsSleep ) );
  597. ICommand *pCmd = isEven( x ) ? xCommand.GetPointer() : 0;
  598. BOOL fSeq = ( Rand( 100 ) < 70 );
  599. BOOL fAsynchronous = FALSE;
  600. if ( !fSeq )
  601. fAsynchronous = ( Rand( 100 ) < 30 );
  602. RunPerfQuery( CiRst,
  603. aQueries[j].pwcQuery,
  604. aQueries[j].cEncartaHits,
  605. pCmd,
  606. fSeq,
  607. fAsynchronous );
  608. InterlockedIncrement( &cQueriesSoFar );
  609. if ( 0 == ( cQueriesSoFar % 10 ) )
  610. printf( "%d queries on catalog '%ws', machine '%ws'\n",
  611. cQueriesSoFar, g_awcCatalog, g_awcMachine );
  612. if ( g_fStopNow )
  613. return 0;
  614. #else
  615. RunPerfQuery( CiRst,
  616. aQueries[j].pwcQuery,
  617. aQueries[j].cEncartaHits,
  618. xCommand.GetPointer(),
  619. g_fSequential,
  620. FALSE );
  621. #endif //STRESS
  622. }
  623. catch( CException & e )
  624. {
  625. // ignore
  626. }
  627. }
  628. return 0;
  629. } //RunPerfTest
  630. //+---------------------------------------------------------------------------
  631. //
  632. // Function: FormQueryTree
  633. //
  634. // Synopsis: Forms a query tree consisting of the projection nodes,
  635. // sort node(s), selection node and the restriction tree.
  636. //
  637. // Arguments: [pRst] - pointer to Restriction tree describing the query
  638. // [Cols] - Columns in the resulting table
  639. // [pSort] - pointer to sort set; may be null
  640. //
  641. // Returns: A pointer to the query tree. It is the responsibility of
  642. // the caller to later free it.
  643. //
  644. // History: 06 July 1995 AlanW Created
  645. //
  646. //----------------------------------------------------------------------------
  647. CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode * pRst,
  648. CDbColumns & Cols,
  649. CDbSortSet * pSort )
  650. {
  651. CDbCmdTreeNode * pTree = 0; // return value
  652. if ( 0 != pRst )
  653. {
  654. //
  655. // First create a selection node and append the restriction tree to it
  656. //
  657. CDbSelectNode * pSelect = new CDbSelectNode();
  658. if ( 0 == pSelect )
  659. {
  660. LogError("FormQueryTree: can't make CDbSelectNode\n" );
  661. return 0;
  662. }
  663. pTree = pSelect;
  664. if ( !pSelect->IsValid() )
  665. {
  666. delete pTree;
  667. LogError("FormQueryTree: select node isn't valid\n" );
  668. return 0;
  669. }
  670. //
  671. // Clone the restriction and use it.
  672. //
  673. CDbCmdTreeNode * pExpr = pRst->Clone();
  674. if ( 0 == pExpr )
  675. {
  676. delete pTree;
  677. LogError("FormQueryTree: can't clone the restriction\n" );
  678. return 0;
  679. }
  680. #ifdef STRESS
  681. else
  682. {
  683. CDbContentRestriction * p = (CDbContentRestriction *) pExpr;
  684. if ( !p->IsValid() )
  685. {
  686. LogError( "clone failed illegally!\n" );
  687. DebugBreak();
  688. }
  689. }
  690. #endif
  691. //
  692. // Now make the restriction a child of the selection node.
  693. //
  694. pSelect->AddRestriction( pExpr );
  695. }
  696. else
  697. {
  698. //
  699. // No restriction. Just use table ID node as start of tree.
  700. //
  701. pTree = new CDbTableId();
  702. if ( 0 == pTree )
  703. {
  704. LogError("FormQueryTree: can't make CDbTableId\n" );
  705. return 0;
  706. }
  707. }
  708. //
  709. // Next create the projection nodes
  710. //
  711. CDbProjectNode * pProject = new CDbProjectNode();
  712. if ( 0 == pProject )
  713. {
  714. delete pTree;
  715. LogError("FormQueryTree: can't make CDbProjectNode\n" );
  716. return 0;
  717. }
  718. //
  719. // Make the selection a child of the projection node.
  720. //
  721. pProject->AddTable( pTree );
  722. pTree = pProject;
  723. //
  724. // Next add all the columns in the state.
  725. //
  726. unsigned int cCol = Cols.Count();
  727. for ( unsigned int i = 0; i < cCol; i++ )
  728. {
  729. if ( !pProject->AddProjectColumn( Cols.Get(i) ))
  730. {
  731. delete pTree;
  732. LogError("FormQueryTree: can't add project column\n" );
  733. return 0;
  734. }
  735. }
  736. //
  737. // Next add a sort node and make the project node a child of the
  738. // sort node
  739. //
  740. if (pSort && pSort->Count())
  741. {
  742. unsigned int cSortProp = pSort->Count();
  743. CDbSortNode * pSortNode = new CDbSortNode();
  744. if ( 0 == pSortNode )
  745. {
  746. delete pTree;
  747. LogError("FormQueryTree: create sort node\n" );
  748. return 0;
  749. }
  750. //
  751. // Make the project node a child of the sort node.
  752. //
  753. if ( ! pSortNode->AddTable( pTree ) )
  754. {
  755. delete pTree;
  756. delete pSortNode;
  757. LogError( "FormQueryTree: can't add table to sortnode\n" );
  758. return 0;
  759. }
  760. pTree = pSortNode;
  761. for( i = 0; i < cSortProp; i++ )
  762. {
  763. //
  764. // Add the sort column.
  765. //
  766. CDbSortKey const &key = pSort->Get( i );
  767. #ifdef STRESS
  768. if ( 0 == &key )
  769. {
  770. LogError( "0 sort key!\n" );
  771. DebugBreak();
  772. }
  773. #endif
  774. if ( !pSortNode->AddSortColumn( key ) )
  775. {
  776. delete pTree;
  777. LogError("FormQueryTree: can't add sort column\n");
  778. return 0;
  779. }
  780. #ifdef STRESS
  781. DBCOMMANDTREE *p = (DBCOMMANDTREE *) (void *) pSortNode;
  782. p = p->pctFirstChild;
  783. p = p->pctNextSibling;
  784. p = p->pctFirstChild;
  785. if ( DBOP_sort_list_element != p->op ||
  786. DBVALUEKIND_SORTINFO != p->wKind ||
  787. 0 == p->value.pdbsrtinfValue )
  788. {
  789. LogError( "p: %#p, bad sort element!\n", p );
  790. DebugBreak();
  791. }
  792. #endif
  793. }
  794. }
  795. return pTree;
  796. } //FormQueryTree
  797. //+---------------------------------------------------------------------------
  798. //
  799. // Class: CAsynchNotify
  800. //
  801. // Synopsis: Class for the IDBAsynchNotify callbacks
  802. //
  803. // History: 07 May 1999 dlee Created
  804. //
  805. //----------------------------------------------------------------------------
  806. class CAsynchNotify : public IDBAsynchNotify
  807. {
  808. public:
  809. CAsynchNotify() :
  810. _cRef( 1 ),
  811. _cLowResource( 0 ),
  812. _hEvent( 0 )
  813. {
  814. _hEvent = CreateEventW( 0, TRUE, FALSE, 0 );
  815. if ( 0 == _hEvent )
  816. LogError( "can't create notify event, %d\n", GetLastError() );
  817. }
  818. ~CAsynchNotify()
  819. {
  820. if ( 0 != _cRef )
  821. LogError( "CAsynchNotify refcounting is broken: %d\n", _cRef );
  822. if ( 0 != _hEvent )
  823. CloseHandle( _hEvent );
  824. }
  825. BOOL IsValid() const { return 0 != _hEvent; }
  826. //
  827. // IUnknown methods.
  828. //
  829. STDMETHOD(QueryInterface) ( REFIID riid, LPVOID *ppiuk )
  830. {
  831. *ppiuk = (void **) this; // hold our breath and jump
  832. AddRef();
  833. return S_OK;
  834. }
  835. STDMETHOD_( ULONG, AddRef ) () { return InterlockedIncrement( &_cRef ); }
  836. STDMETHOD_( ULONG, Release) () { return InterlockedDecrement( &_cRef ); }
  837. //
  838. // IDBAsynchNotify methods
  839. //
  840. STDMETHOD( OnLowResource ) ( DB_DWRESERVE dwReserved )
  841. {
  842. _cLowResource++;
  843. // If we've failed a few times due to low resource, give up
  844. // on the query since there may not be sufficient resources
  845. // to ever get an OnStop call.
  846. if ( _cLowResource >= 5 )
  847. SetEvent( _hEvent );
  848. return S_OK;
  849. }
  850. STDMETHOD( OnProgress ) ( HCHAPTER hChap, DBASYNCHOP ulOp,
  851. DBCOUNTITEM ulProg, DBCOUNTITEM ulProgMax,
  852. DBASYNCHPHASE ulStat, LPOLESTR pwszStatus )
  853. {
  854. return S_OK;
  855. }
  856. STDMETHOD( OnStop ) ( HCHAPTER hChap, ULONG ulOp,
  857. HRESULT hrStat, LPOLESTR pwszStatus )
  858. {
  859. // If the query is complete (successfully or not), set the event
  860. if ( DBASYNCHOP_OPEN == ulOp )
  861. SetEvent( _hEvent );
  862. return S_OK;
  863. }
  864. void Wait()
  865. {
  866. WaitForSingleObject( _hEvent, INFINITE );
  867. }
  868. private:
  869. LONG _cRef;
  870. LONG _cLowResource;
  871. HANDLE _hEvent;
  872. };
  873. //+---------------------------------------------------------------------------
  874. //
  875. // Function: WaitForQueryToComplete
  876. //
  877. // Synopsis: Waits for the query to complete.
  878. //
  879. // Arguments: [pRowset] -- the asynchronous rowset
  880. //
  881. // History: 07 May 1999 dlee Created
  882. //
  883. //----------------------------------------------------------------------------
  884. SCODE WaitForQueryCompletion( IRowset * pRowset )
  885. {
  886. SCODE sc = S_OK;
  887. if ( Rand( 100 ) < 50 )
  888. {
  889. // Register for notifications
  890. XInterface<IConnectionPointContainer> xCPC;
  891. sc = pRowset->QueryInterface( IID_IConnectionPointContainer,
  892. xCPC.GetQIPointer() );
  893. if (FAILED(sc))
  894. {
  895. LogError( "Can't QI for IConnectionPointContainer: %#x\n",sc );
  896. return sc;
  897. }
  898. XInterface<IConnectionPoint> xCP;
  899. sc = xCPC->FindConnectionPoint( IID_IDBAsynchNotify,
  900. xCP.GetPPointer() );
  901. if (FAILED(sc) && CONNECT_E_NOCONNECTION != sc )
  902. {
  903. LogError( "FindConnectionPoint failed: %#x\n",sc );
  904. return sc;
  905. }
  906. CAsynchNotify Notify;
  907. if ( !Notify.IsValid() )
  908. return HRESULT_FROM_WIN32( GetLastError() );
  909. DWORD dwAdviseID;
  910. sc = xCP->Advise( (IUnknown *) &Notify, &dwAdviseID );
  911. if (FAILED(sc))
  912. {
  913. LogError( "IConnectionPoint->Advise failed: %#x\n",sc );
  914. return sc;
  915. }
  916. //
  917. // In a real app, we'd be off doing other work rather than waiting
  918. // for the query to complete, but this will do.
  919. // MsgWaitForSingleObject is a good choice for a GUI app. You could
  920. // also post a user-defined windows message when a notification is
  921. // received.
  922. //
  923. Notify.Wait();
  924. sc = xCP->Unadvise( dwAdviseID );
  925. if ( S_OK != sc )
  926. {
  927. LogError( "IConnectionPoint->Unadvise returned %#x\n", sc );
  928. return sc;
  929. }
  930. Notify.Release();
  931. }
  932. else
  933. {
  934. // Poll. In a real app, real work would happen between checks.
  935. XInterface<IDBAsynchStatus> xIDBAsynch;
  936. sc = pRowset->QueryInterface( IID_IDBAsynchStatus,
  937. xIDBAsynch.GetQIPointer() );
  938. if ( FAILED( sc ) )
  939. return sc;
  940. do
  941. {
  942. DBCOUNTITEM Numerator, Denominator;
  943. DBASYNCHPHASE Phase;
  944. sc = xIDBAsynch->GetStatus( DB_NULL_HCHAPTER,
  945. DBASYNCHOP_OPEN,
  946. &Numerator,
  947. &Denominator,
  948. &Phase,
  949. 0 );
  950. if ( FAILED( sc ) || ( DBASYNCHPHASE_COMPLETE == Phase ) )
  951. break;
  952. Sleep( 20 ); // Give the query a chance to run
  953. } while ( TRUE );
  954. }
  955. return sc;
  956. } //WaitForQueryCompletion
  957. //+---------------------------------------------------------------------------
  958. //
  959. // Function: InstantiateRowset
  960. //
  961. // Synopsis: Forms a query tree consisting of the projection nodes,
  962. // sort node(s), selection node and the restriction tree.
  963. //
  964. // Arguments: [dwDepth] - Query depth, one of QUERY_DEEP or QUERY_SHALLOW
  965. // [pswzScope] - Query scope
  966. // [pTree] - pointer to DBCOMMANDTREE for the query
  967. // [riid] - Interface ID of the desired rowset interface
  968. //
  969. // Returns: IRowsetScroll* - a pointer to an instantiated rowset
  970. //
  971. // History: 22 July 1995 AlanW Created
  972. //
  973. // Notes: Although the returned pointer is to IRowsetScroll, the
  974. // returned pointer may only support IRowset, depending
  975. // upon the riid parameter.
  976. //
  977. // Ownership of the query tree is given to the ICommandTree
  978. // object. The caller does not need to delete it.
  979. //
  980. // Use InstantiateMultipleRowsets for categorized queries.
  981. //
  982. //----------------------------------------------------------------------------
  983. static const DBID dbcolNull = { {0,0,0,{0,0,0,0,0,0,0,0}},DBKIND_GUID_PROPID,0};
  984. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  985. IRowsetScroll * InstantiateRowset(
  986. ICommand * pCommandIn,
  987. DWORD dwDepth,
  988. LPWSTR pwszScope,
  989. XPtr<CDbCmdTreeNode> & xTree,
  990. WCHAR const * pwcQuery,
  991. REFIID riid,
  992. BOOL fAsynchronous )
  993. {
  994. ICommand * pCommand;
  995. XInterface<ICommand> xCommand;
  996. if ( 0 == pCommandIn )
  997. {
  998. SCODE sc = CICreateCommand( (IUnknown **) &pCommand,
  999. 0,
  1000. IID_ICommand,
  1001. g_awcCatalog,
  1002. g_awcMachine );
  1003. if ( FAILED( sc ) )
  1004. {
  1005. LogError( "InstantiateRowset - error 0x%x, Unable to create icommand'\n", sc );
  1006. return 0;
  1007. }
  1008. xCommand.Set( pCommand );
  1009. }
  1010. else
  1011. {
  1012. pCommand = pCommandIn;
  1013. }
  1014. if ( 0 == pCommand )
  1015. return 0;
  1016. if ( g_fSQL )
  1017. {
  1018. XInterface<ICommandText> xCommandText;
  1019. SCODE sc = pCommand->QueryInterface( IID_ICommandText,
  1020. xCommandText.GetQIPointer() );
  1021. if ( FAILED( sc ) )
  1022. {
  1023. LogError( "InstantiateRowset error %#x, can't qi ICommandText\n", sc );
  1024. return 0;
  1025. }
  1026. WCHAR awc[ 300 ];
  1027. swprintf( awc,
  1028. L"SELECT %ws FROM %ws..SCOPE('\"%ws\"') WHERE CONTAINS('%ws')",
  1029. L"Filename, Size, Write, Path, Rank",
  1030. //g_awcMachine,
  1031. g_awcCatalog,
  1032. pwszScope,
  1033. pwcQuery );
  1034. sc = xCommandText->SetCommandText( DBGUID_SQL, awc );
  1035. if ( FAILED( sc ) )
  1036. {
  1037. LogError( "InstantiateRowset error %#x, can't set text\n", sc );
  1038. return 0;
  1039. }
  1040. #if 1
  1041. XInterface<ICommandProperties> xCommandProperties;
  1042. sc = xCommandText->QueryInterface( IID_ICommandProperties,
  1043. xCommandProperties.GetQIPointer() );
  1044. if ( FAILED (sc) )
  1045. {
  1046. LogError( "InstantiateRowset error %#x, can't qi commandprops\n", sc );
  1047. return 0;
  1048. }
  1049. // set the machine name
  1050. DBPROPSET PropSet;
  1051. DBPROP Prop;
  1052. const GUID guidQueryCorePropset = DBPROPSET_CIFRMWRKCORE_EXT;
  1053. PropSet.rgProperties = &Prop;
  1054. PropSet.cProperties = 1;
  1055. PropSet.guidPropertySet = guidQueryCorePropset;
  1056. Prop.dwPropertyID = DBPROP_MACHINE;
  1057. Prop.colid = DB_NULLID;
  1058. Prop.vValue.vt = VT_BSTR;
  1059. Prop.vValue.bstrVal = SysAllocString( g_awcMachine );
  1060. if ( 0 == Prop.vValue.bstrVal )
  1061. {
  1062. LogError( "InstantiateRowset error %#x, can't allocate sql machine\n", sc );
  1063. return 0;
  1064. }
  1065. sc = xCommandProperties->SetProperties ( 1, &PropSet );
  1066. VariantClear( &Prop.vValue );
  1067. if ( FAILED (sc) )
  1068. {
  1069. LogError( "InstantiateRowset error %#x can't set sql machine\n", sc );
  1070. return 0;
  1071. }
  1072. #endif
  1073. XInterface<ICommandPrepare> xCommandPrepare;
  1074. sc = xCommandText->QueryInterface( IID_ICommandPrepare,
  1075. xCommandPrepare.GetQIPointer() );
  1076. if ( FAILED (sc) )
  1077. {
  1078. LogError( "InstantiateRowset error %#x, can't qi prepare\n", sc );
  1079. return 0;
  1080. }
  1081. sc = xCommandPrepare->Prepare( 1 );
  1082. if ( FAILED (sc) )
  1083. {
  1084. LogError( "InstantiateRowset error %#x, can't prepare\n", sc );
  1085. return 0;
  1086. }
  1087. }
  1088. else
  1089. {
  1090. XInterface<ICommandTree> xCmdTree;
  1091. HRESULT sc = pCommand->QueryInterface( IID_ICommandTree,
  1092. xCmdTree.GetQIPointer() );
  1093. if (FAILED (sc) )
  1094. {
  1095. LogError( "QI for ICommandTree failed %#x\n", sc );
  1096. return 0;
  1097. }
  1098. DBCOMMANDTREE * pRoot = xTree->CastToStruct();
  1099. sc = xCmdTree->SetCommandTree( &pRoot, DBCOMMANDREUSE_NONE, FALSE);
  1100. if (FAILED (sc) )
  1101. {
  1102. LogError("SetCommandTree failed, %08x\n", sc);
  1103. return 0;
  1104. }
  1105. xTree.Acquire();
  1106. }
  1107. #ifdef GET_DATA_TOO
  1108. {
  1109. const unsigned MAX_PROPS = 8;
  1110. DBPROPSET aPropSet[MAX_PROPS];
  1111. DBPROP aProp[MAX_PROPS];
  1112. ULONG cProps = 0;
  1113. // We can handle PROPVARIANTs
  1114. aProp[cProps].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  1115. aProp[cProps].dwOptions = DBPROPOPTIONS_OPTIONAL;
  1116. aProp[cProps].dwStatus = 0;
  1117. aProp[cProps].colid = dbcolNull;
  1118. aProp[cProps].vValue.vt = VT_BOOL;
  1119. aProp[cProps].vValue.boolVal = VARIANT_TRUE;
  1120. aPropSet[cProps].rgProperties = &aProp[cProps];
  1121. aPropSet[cProps].cProperties = 1;
  1122. aPropSet[cProps].guidPropertySet = guidQueryExt;
  1123. cProps++;
  1124. XInterface<ICommandProperties> xCmdProp;
  1125. SCODE sc = pCommand->QueryInterface( IID_ICommandProperties,
  1126. xCmdProp.GetQIPointer() );
  1127. if (FAILED (sc) )
  1128. {
  1129. LogError( "can't qi to commandprops\n", sc );
  1130. return 0;
  1131. }
  1132. sc = xCmdProp->SetProperties( cProps, aPropSet );
  1133. if (FAILED (sc) || DB_S_ERRORSOCCURRED == sc )
  1134. {
  1135. LogError( "can't set commandprops: 0x%lx\n", sc );
  1136. return 0;
  1137. }
  1138. }
  1139. #endif // GET_DATA_TOO
  1140. #ifdef STRESS
  1141. {
  1142. const unsigned MAX_PROPS = 1;
  1143. DBPROPSET aPropSet[MAX_PROPS];
  1144. DBPROP aProp[MAX_PROPS];
  1145. ULONG cProps = 0;
  1146. // Mark the icommand as synch or asynch. Note that we always have
  1147. // to set it since we may have an old ICommand that previously had
  1148. // a different state set.
  1149. aProp[cProps].dwPropertyID = DBPROP_IDBAsynchStatus;
  1150. aProp[cProps].dwOptions = DBPROPOPTIONS_REQUIRED;
  1151. aProp[cProps].dwStatus = 0;
  1152. aProp[cProps].colid = dbcolNull;
  1153. aProp[cProps].vValue.vt = VT_BOOL;
  1154. aProp[cProps].vValue.boolVal = fAsynchronous ? VARIANT_TRUE : VARIANT_FALSE;
  1155. aPropSet[cProps].rgProperties = &aProp[cProps];
  1156. aPropSet[cProps].cProperties = 1;
  1157. aPropSet[cProps].guidPropertySet = guidRowsetProps;
  1158. cProps++;
  1159. XInterface<ICommandProperties> xCmdProp;
  1160. SCODE sc = pCommand->QueryInterface( IID_ICommandProperties,
  1161. xCmdProp.GetQIPointer() );
  1162. if (FAILED (sc) )
  1163. {
  1164. LogError( "can't qi to commandprops\n", sc );
  1165. return 0;
  1166. }
  1167. sc = xCmdProp->SetProperties( cProps, aPropSet );
  1168. if (FAILED (sc) || DB_S_ERRORSOCCURRED == sc )
  1169. {
  1170. LogError( "can't set commandprops: 0x%lx\n", sc );
  1171. return 0;
  1172. }
  1173. }
  1174. #endif
  1175. XInterface<IRowsetScroll> xRowset;
  1176. SCODE sc = pCommand->Execute( 0, // no aggr. IUnknown
  1177. riid, // IID for i/f to return
  1178. 0, // disp. params
  1179. 0, // chapter
  1180. (IUnknown **) xRowset.GetPPointer() );
  1181. if ( FAILED (sc) )
  1182. {
  1183. LogError("ICommand::Execute failed, %08x\n", sc);
  1184. if ( !xRowset.IsNull() )
  1185. LogError( "pRowset is 0x%x when it should be 0\n", xRowset.GetPointer() );
  1186. }
  1187. if ( SUCCEEDED( sc ) && fAsynchronous )
  1188. {
  1189. sc = WaitForQueryCompletion( xRowset.GetPointer() );
  1190. if ( FAILED( sc ) )
  1191. xRowset.Free();
  1192. }
  1193. return xRowset.Acquire();
  1194. } //InstantiateRowset
  1195. //+-------------------------------------------------------------------------
  1196. //
  1197. // Function: MapColumns, public
  1198. //
  1199. // Synopsis: Map column IDs in column bindings. Create an accessor
  1200. // for the binding array.
  1201. //
  1202. // Arguments: [pUnknown] -- Interface capable of returning IColumnsInfo and
  1203. // IAccessor
  1204. // [cCols] -- number of columns in arrays
  1205. // [pBindings] -- column data binding array
  1206. // [pDbCols] -- column IDs array
  1207. //
  1208. // Returns: HACCESSOR - a read accessor for the column bindings.
  1209. //
  1210. // History: 18 May 1995 AlanW Created
  1211. //
  1212. //--------------------------------------------------------------------------
  1213. static DBORDINAL aMappedColumnIDs[20];
  1214. HACCESSOR MapColumns(
  1215. IUnknown * pUnknown,
  1216. ULONG cCols,
  1217. DBBINDING * pBindings,
  1218. const DBID * pDbCols )
  1219. {
  1220. XInterface<IColumnsInfo> xColumnsInfo;
  1221. SCODE sc = pUnknown->QueryInterface( IID_IColumnsInfo,
  1222. xColumnsInfo.GetQIPointer() );
  1223. if ( FAILED( sc ) )
  1224. {
  1225. LogError( "IUnknown::QueryInterface for IColumnsInfo returned 0x%lx\n", sc );
  1226. return 0;
  1227. }
  1228. sc = xColumnsInfo->MapColumnIDs(cCols, pDbCols, aMappedColumnIDs);
  1229. if (S_OK != sc)
  1230. {
  1231. LogError( "IColumnsInfo->MapColumnIDs returned 0x%lx\n",sc);
  1232. return 0;
  1233. }
  1234. for (ULONG i = 0; i < cCols; i++)
  1235. pBindings[i].iOrdinal = aMappedColumnIDs[i];
  1236. XInterface<IAccessor> xAccessor;
  1237. sc = pUnknown->QueryInterface( IID_IAccessor, xAccessor.GetQIPointer() );
  1238. if ( FAILED( sc ) )
  1239. {
  1240. LogError( "IRowset::QueryInterface for IAccessor returned 0x%lx\n", sc );
  1241. return 0;
  1242. }
  1243. HACCESSOR hAcc = 0;
  1244. sc = xAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
  1245. cCols, pBindings, 0, &hAcc, 0 );
  1246. if (S_OK != sc)
  1247. LogError( "IAccessor->CreateAccessor returned 0x%lx\n",sc);
  1248. return hAcc;
  1249. } //MapColumns
  1250. //+-------------------------------------------------------------------------
  1251. //
  1252. // Function: ReleaseAccessor, public
  1253. //
  1254. // Synopsis: Release an accessor obtained from MapColumns
  1255. //
  1256. // Arguments: [pUnknown] -- Something that we can QI the IAccessor on
  1257. // [hAcc] -- Accessor handle to be released.
  1258. //
  1259. // Returns: nothing
  1260. //
  1261. // History: 14 June 1995 AlanW Created
  1262. //
  1263. //--------------------------------------------------------------------------
  1264. void ReleaseAccessor( IUnknown * pUnknown, HACCESSOR hAcc )
  1265. {
  1266. XInterface<IAccessor> xAccessor;
  1267. SCODE sc = pUnknown->QueryInterface( IID_IAccessor, xAccessor.GetQIPointer() );
  1268. if ( FAILED( sc ) )
  1269. {
  1270. LogError( "IUnknown::QueryInterface for IAccessor returned 0x%lx\n", sc );
  1271. return;
  1272. }
  1273. sc = xAccessor->ReleaseAccessor( hAcc, 0 );
  1274. if (S_OK != sc)
  1275. LogError( "IAccessor->ReleaseAccessor returned 0x%lx\n",sc);
  1276. } //ReleaseAccessor
  1277. //+-------------------------------------------------------------------------
  1278. //
  1279. // Function: LogError, public
  1280. //
  1281. // Synopsis: Prints a verbose-mode message.
  1282. //
  1283. // Arguments: [pszfmt] -- Format string
  1284. //
  1285. // History: 13-Jul-93 KyleP Created
  1286. //
  1287. //--------------------------------------------------------------------------
  1288. void LogError( char const * pszfmt, ... )
  1289. {
  1290. va_list pargs;
  1291. va_start(pargs, pszfmt);
  1292. vprintf( pszfmt, pargs );
  1293. va_end(pargs);
  1294. _flushall();
  1295. } //LogError