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.

1216 lines
40 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: wqitem.cxx
  7. //
  8. // Contents: WEB Query item class
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <params.hxx>
  16. static const DBID dbcolNull = { {0,0,0,{0,0,0,0,0,0,0,0}},DBKIND_GUID_PROPID,0};
  17. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  18. static const GUID guidRowsetProps = DBPROPSET_ROWSET;
  19. static const DBID dbidVirtualPath = { QueryGuid, DBKIND_GUID_PROPID, (LPWSTR) 9 };
  20. DBBINDING g_aDbBinding[ MAX_QUERY_COLUMNS ];
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Member: CWQueryItem::CWQueryItem - public constructor
  24. //
  25. // Arguments: [idqFile] - IDQ file corresponding to this query
  26. // [htxFile] - HTX file corresponding to this query
  27. // [wcsColumns] - string representation of output columns
  28. // [dbColumns] - OLE-DB column representation of output
  29. // [avarColumns] - Variables from [dbColumns]. Same order.
  30. // [ulSequenceNumber] - sequence # to assign this query
  31. // [lNextRecordNumber] - # of next available record from query
  32. // results; important for reconstructing
  33. // stale sequential queries
  34. // [securityIdentity] - security context of this query
  35. //
  36. // Synopsis: Builds a new query object, parses the IDQ file, and parses
  37. // the HTX file.
  38. //
  39. // History: 96-Jan-18 DwightKr Created
  40. //
  41. //----------------------------------------------------------------------------
  42. CWQueryItem::CWQueryItem(CIDQFile & idqFile,
  43. CHTXFile & htxFile,
  44. XPtrST<WCHAR> & wcsColumns,
  45. XPtr<CDbColumns> & dbColumns,
  46. CDynArray<WCHAR> & awcsColumns,
  47. ULONG ulSequenceNumber,
  48. LONG lNextRecordNumber,
  49. CSecurityIdentity securityIdentity ) :
  50. _signature(CWQueryItemSignature),
  51. _idqFile(idqFile),
  52. _htxFile(htxFile),
  53. _ulSequenceNumber(ulSequenceNumber),
  54. _refCount(0),
  55. _fIsZombie(FALSE),
  56. _fInCache(FALSE),
  57. _fCanCache(TRUE),
  58. _locale(InvalidLCID),
  59. _wcsRestriction(0),
  60. _wcsDialect(0),
  61. _ulDialect(0),
  62. _wcsSort(0),
  63. _wcsScope(0),
  64. _wcsCatalog(0),
  65. _wcsCiFlags(0),
  66. _wcsForceUseCI(0),
  67. _wcsDeferTrimming(0),
  68. _wcsColumns(wcsColumns.Acquire()),
  69. _wcsQueryTimeZone(0),
  70. _pDbColumns(dbColumns.Acquire()),
  71. _awcsColumns( awcsColumns ),
  72. _pIRowset(0),
  73. _pIAccessor(0),
  74. _pIRowsetStatus(0),
  75. _pICommand(0),
  76. _lNextRecordNumber(lNextRecordNumber),
  77. _cFilteredDocuments(0),
  78. _securityIdentity(securityIdentity)
  79. {
  80. time ( &_lastAccessTime );
  81. }
  82. //+---------------------------------------------------------------------------
  83. //
  84. // Member: CWQueryItem::~CWQueryItem - public destructor
  85. //
  86. // Synopsis: Releases storage and interfaces.
  87. //
  88. // History: 96-Jan-18 DwightKr Created
  89. //
  90. //----------------------------------------------------------------------------
  91. CWQueryItem::~CWQueryItem()
  92. {
  93. Win4Assert( _refCount == 0 );
  94. delete _wcsRestriction;
  95. delete _wcsDialect;
  96. delete _wcsSort;
  97. delete _wcsScope;
  98. delete _wcsCatalog;
  99. delete _wcsColumns;
  100. delete _wcsCiFlags;
  101. delete _wcsForceUseCI;
  102. delete _wcsDeferTrimming;
  103. delete _wcsQueryTimeZone;
  104. delete _pDbColumns;
  105. if ( 0 != _pIAccessor )
  106. {
  107. _pIAccessor->ReleaseAccessor( _hAccessor, 0 );
  108. _pIAccessor->Release();
  109. }
  110. if ( 0 != _pIRowset )
  111. {
  112. _pIRowset->Release();
  113. }
  114. if ( 0 != _pIRowsetStatus )
  115. {
  116. _pIRowsetStatus->Release();
  117. }
  118. if ( 0 != _pICommand )
  119. {
  120. TheICommandCache.Release( _pICommand );
  121. }
  122. _idqFile.Release();
  123. _htxFile.Release();
  124. }
  125. //+---------------------------------------------------------------------------
  126. //
  127. // Member: CWQueryItem::ExecuteQuery - public
  128. //
  129. // Synopsis: Executes the query and builds an IRowset or IRowsetScroll
  130. // as necessary.
  131. //
  132. // Arguments: [variableSet] - list of replaceable parameters
  133. // [outputFormat] - format of numbers & dates
  134. //
  135. // History: 96-Jan-18 DwightKr Created
  136. //
  137. //----------------------------------------------------------------------------
  138. void CWQueryItem::ExecuteQuery( CVariableSet & variableSet,
  139. COutputFormat & outputFormat )
  140. {
  141. Win4Assert( 0 == _pIRowset ); // Should not have executed query
  142. Win4Assert( 0 == _pIAccessor );
  143. _locale = outputFormat.GetLCID();
  144. //
  145. // Setup the variables needed to execute this query; including:
  146. //
  147. // CiRestriction
  148. // CiMaxRecordsInResultSet
  149. // CiSort
  150. // CiScope
  151. //
  152. //
  153. // Build the final restriction from the existing restriction string
  154. // and the additional parameters passed in from the browser.
  155. //
  156. ULONG cwcOut;
  157. _wcsRestriction = ReplaceParameters( _idqFile.GetRestriction(),
  158. variableSet,
  159. outputFormat,
  160. cwcOut );
  161. variableSet.CopyStringValue( ISAPI_CI_RESTRICTION, _wcsRestriction, 0, cwcOut );
  162. ciGibDebugOut(( DEB_ITRACE, "Restriction = '%ws'\n", _wcsRestriction ));
  163. if ( 0 == *_wcsRestriction )
  164. {
  165. THROW( CIDQException(MSG_CI_IDQ_MISSING_RESTRICTION , 0) );
  166. }
  167. //
  168. // Setup CiMaxRecordsInResultSet
  169. //
  170. _lMaxRecordsInResultSet =
  171. ReplaceNumericParameter( _idqFile.GetMaxRecordsInResultSet(),
  172. variableSet,
  173. outputFormat,
  174. TheIDQRegParams.GetMaxISRowsInResultSet(),
  175. IS_MAX_ROWS_IN_RESULT_MIN,
  176. IS_MAX_ROWS_IN_RESULT_MAX );
  177. PROPVARIANT propVariant;
  178. propVariant.vt = VT_I4;
  179. propVariant.lVal = _lMaxRecordsInResultSet;
  180. variableSet.SetVariable( ISAPI_CI_MAX_RECORDS_IN_RESULTSET, &propVariant, 0 );
  181. ciGibDebugOut(( DEB_ITRACE, "CiMaxRecordsInResultSet = %d\n", _lMaxRecordsInResultSet ));
  182. // Setup CiFirstRowsInResultSet
  183. //
  184. _lFirstRowsInResultSet =
  185. ReplaceNumericParameter( _idqFile.GetFirstRowsInResultSet(),
  186. variableSet,
  187. outputFormat,
  188. TheIDQRegParams.GetISFirstRowsInResultSet(),
  189. IS_FIRST_ROWS_IN_RESULT_MIN,
  190. IS_FIRST_ROWS_IN_RESULT_MAX );
  191. PROPVARIANT propVar;
  192. propVar.vt = VT_I4;
  193. propVar.lVal = _lFirstRowsInResultSet;
  194. variableSet.SetVariable( ISAPI_CI_FIRST_ROWS_IN_RESULTSET, &propVar, 0 );
  195. ciGibDebugOut(( DEB_ITRACE, "CiFirstRowsInResultSet = %d\n", _lFirstRowsInResultSet ));
  196. _ulDialect =
  197. ReplaceNumericParameter( _idqFile.GetDialect(),
  198. variableSet,
  199. outputFormat,
  200. ISQLANG_V2, // default
  201. ISQLANG_V1, // min
  202. ISQLANG_V2 ); // max
  203. Win4Assert( 0 != _ulDialect );
  204. propVariant.vt = VT_UI4;
  205. propVariant.ulVal = _ulDialect;
  206. variableSet.SetVariable( ISAPI_CI_DIALECT, &propVariant, 0 );
  207. ciGibDebugOut(( DEB_ITRACE, "CiDialect = %d\n", _ulDialect ));
  208. //
  209. // Build the final sort set from the existing sortset string
  210. // and the additional parameters passed in from the browser.
  211. //
  212. XPtr<CDbSortNode> xDbSortNode;
  213. if ( 0 != _idqFile.GetSort() )
  214. {
  215. _wcsSort = ReplaceParameters( _idqFile.GetSort(),
  216. variableSet,
  217. outputFormat,
  218. cwcOut );
  219. variableSet.CopyStringValue( ISAPI_CI_SORT, _wcsSort, 0, cwcOut );
  220. ciGibDebugOut(( DEB_ITRACE, "Sort = '%ws'\n", _wcsSort ));
  221. Win4Assert( 0 != _wcsSort );
  222. }
  223. //
  224. // Build the projection list from the column list.
  225. //
  226. CTextToTree textToTree( _wcsRestriction,
  227. _ulDialect,
  228. _pDbColumns,
  229. _idqFile.GetColumnMapper(),
  230. _locale,
  231. _wcsSort,
  232. 0,
  233. 0,
  234. _lMaxRecordsInResultSet,
  235. _lFirstRowsInResultSet );
  236. CDbCmdTreeNode * pDbCmdTree = (CDbCmdTreeNode *) (void *) textToTree.FormFullTree();
  237. XPtr<CDbCmdTreeNode> xDbCmdTree( pDbCmdTree );
  238. //
  239. // Remap the scope from a replaceable parameter
  240. //
  241. _wcsScope = ReplaceParameters( _idqFile.GetScope(),
  242. variableSet,
  243. outputFormat,
  244. cwcOut );
  245. variableSet.CopyStringValue( ISAPI_CI_SCOPE, _wcsScope, 0, cwcOut );
  246. ciGibDebugOut(( DEB_ITRACE, "Scope = '%ws'\n", _wcsScope ));
  247. Win4Assert( 0 != _wcsScope );
  248. if ( 0 == *_wcsScope )
  249. {
  250. THROW( CIDQException(MSG_CI_IDQ_MISSING_SCOPE , 0) );
  251. }
  252. //
  253. // Build the location of the catalog
  254. //
  255. ULONG cwcCatalog;
  256. Win4Assert( 0 != _idqFile.GetCatalog() );
  257. _wcsCatalog = ReplaceParameters( _idqFile.GetCatalog(),
  258. variableSet,
  259. outputFormat,
  260. cwcCatalog );
  261. variableSet.CopyStringValue( ISAPI_CI_CATALOG, _wcsCatalog, 0, cwcCatalog );
  262. ciGibDebugOut(( DEB_ITRACE, "Catalog = '%ws'\n", _wcsCatalog ));
  263. Win4Assert( 0 != _wcsCatalog );
  264. if ( !IsAValidCatalog( _wcsCatalog, cwcCatalog ) )
  265. {
  266. THROW( CIDQException(MSG_CI_IDQ_NO_SUCH_CATALOG, 0) );
  267. }
  268. XPtrST<WCHAR> xpCat;
  269. XPtrST<WCHAR> xpMach;
  270. if ( ( ! SUCCEEDED( ParseCatalogURL( _wcsCatalog, xpCat, xpMach ) ) ) ||
  271. ( xpCat.IsNull() ) )
  272. {
  273. THROW( CIDQException(MSG_CI_IDQ_NO_SUCH_CATALOG, 0) );
  274. }
  275. //
  276. // Get the query flags.
  277. //
  278. ULONG cwcCiFlags;
  279. _wcsCiFlags = ReplaceParameters( _idqFile.GetCiFlags(),
  280. variableSet,
  281. outputFormat,
  282. cwcCiFlags );
  283. if ( 0 != _wcsCiFlags )
  284. {
  285. variableSet.CopyStringValue( ISAPI_CI_FLAGS, _wcsCiFlags, 0, cwcCiFlags );
  286. }
  287. ULONG ulFlags = _idqFile.ParseFlags( _wcsCiFlags );
  288. ciGibDebugOut(( DEB_ITRACE, "CiFlags = '%ws' (%x)\n", _wcsCiFlags, ulFlags ));
  289. //
  290. // We've setup all the parameters to run the query. Run the query
  291. // now.
  292. //
  293. _pICommand = 0;
  294. //
  295. // Paths start out as one of:
  296. // ?:\...
  297. // \\....\....\
  298. // /...
  299. //
  300. SCODE scIC = S_OK;
  301. if ( _wcsicmp( _wcsScope, L"VIRTUAL_ROOTS" ) == 0 )
  302. {
  303. _fCanCache = FALSE;
  304. CheckAdminSecurity( xpMach.GetPointer() );
  305. IUnknown * pIUnknown;
  306. scIC = MakeMetadataICommand( &pIUnknown,
  307. CiVirtualRoots,
  308. xpCat.GetPointer(),
  309. xpMach.GetPointer() );
  310. if (SUCCEEDED (scIC))
  311. {
  312. XInterface<IUnknown> xUnk( pIUnknown );
  313. scIC = pIUnknown->QueryInterface(IID_ICommand, (void **)&_pICommand);
  314. }
  315. }
  316. else if ( _wcsicmp( _wcsScope, L"PROPERTIES" ) == 0 )
  317. {
  318. _fCanCache = FALSE;
  319. CheckAdminSecurity( xpMach.GetPointer() );
  320. IUnknown * pIUnknown;
  321. scIC = MakeMetadataICommand( &pIUnknown,
  322. CiProperties,
  323. xpCat.GetPointer(),
  324. xpMach.GetPointer() );
  325. if (SUCCEEDED (scIC))
  326. {
  327. XInterface<IUnknown> xUnk( pIUnknown );
  328. scIC = pIUnknown->QueryInterface(IID_ICommand, (void **)&_pICommand);
  329. }
  330. }
  331. else
  332. {
  333. //
  334. // Verify that the caller has admin security for DontTimeout queries.
  335. //
  336. if ( _idqFile.IsDontTimeout() )
  337. CheckAdminSecurity( xpMach.GetPointer() );
  338. scIC = TheICommandCache.Make( &_pICommand,
  339. ulFlags,
  340. xpMach.GetPointer(),
  341. xpCat.GetPointer(),
  342. _wcsScope );
  343. }
  344. #if CIDBG == 1
  345. if ( FAILED( scIC ) )
  346. Win4Assert( 0 == _pICommand );
  347. else
  348. Win4Assert( 0 != _pICommand );
  349. #endif // CIDBG == 1
  350. if ( 0 == _pICommand )
  351. {
  352. ciGibDebugOut(( DEB_ITRACE, "Make*ICommand failed with error 0x%x\n", scIC ));
  353. // Make*ICommand returns SCODEs, not Win32 error codes
  354. Win4Assert( ERROR_FILE_NOT_FOUND != scIC );
  355. Win4Assert( ERROR_SEM_TIMEOUT != scIC );
  356. // These errors are no longer returned -- the work isn't
  357. // done until Execute(), and the errors are mapped to
  358. // the popular E_FAIL. Leave the code in since now the
  359. // OLE DB spec allows the errors and we may change the provider.
  360. if ( ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == scIC ) ||
  361. ( HRESULT_FROM_WIN32( ERROR_SEM_TIMEOUT ) == scIC ) )
  362. {
  363. THROW( CIDQException( MSG_CI_IDQ_CISVC_NOT_RUNNING, 0 ) );
  364. }
  365. else
  366. {
  367. THROW( CIDQException( MSG_CI_IDQ_BAD_SCOPE_OR_CATALOG, 0 ) );
  368. }
  369. }
  370. ICommandTree * pICmdTree = 0;
  371. SCODE sc = _pICommand->QueryInterface( IID_ICommandTree,
  372. (void **) &pICmdTree );
  373. if (FAILED (sc) )
  374. {
  375. THROW( CException( QUERY_EXECUTE_FAILED ) );
  376. }
  377. DBCOMMANDTREE * pDbCommandTree = pDbCmdTree->CastToStruct();
  378. sc = pICmdTree->SetCommandTree(&pDbCommandTree, DBCOMMANDREUSE_NONE, FALSE);
  379. pICmdTree->Release();
  380. if ( FAILED(sc) )
  381. {
  382. THROW( CException(sc) );
  383. }
  384. xDbCmdTree.Acquire();
  385. //
  386. // Save the time this query started execution
  387. //
  388. GetLocalTime( &_queryTime );
  389. //
  390. // If we should NOT be using a enumerated query, notify pCommand
  391. //
  392. const unsigned MAX_PROPS = 5;
  393. DBPROPSET aPropSet[MAX_PROPS];
  394. DBPROP aProp[MAX_PROPS];
  395. ULONG cProp = 0;
  396. // Set the property that says we accept PROPVARIANTs
  397. aProp[cProp].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  398. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  399. aProp[cProp].dwStatus = 0; // Ignored
  400. aProp[cProp].colid = dbcolNull;
  401. aProp[cProp].vValue.vt = VT_BOOL;
  402. aProp[cProp].vValue.boolVal = VARIANT_TRUE;
  403. aPropSet[cProp].rgProperties = &aProp[cProp];
  404. aPropSet[cProp].cProperties = 1;
  405. aPropSet[cProp].guidPropertySet = guidQueryExt;
  406. cProp++;
  407. ULONG cwc;
  408. _wcsForceUseCI = ReplaceParameters( _idqFile.GetForceUseCI(),
  409. variableSet,
  410. outputFormat,
  411. cwc );
  412. if ( 0 != _wcsForceUseCI )
  413. {
  414. variableSet.CopyStringValue( ISAPI_CI_FORCE_USE_CI, _wcsForceUseCI, 0, cwc );
  415. }
  416. BOOL fForceUseCI = _idqFile.ParseForceUseCI( _wcsForceUseCI );
  417. ciGibDebugOut(( DEB_ITRACE, "CiForceUseCi = '%ws'\n", _wcsForceUseCI ));
  418. {
  419. // Set the property that says we don't want to enumerate
  420. aProp[cProp].dwPropertyID = DBPROP_USECONTENTINDEX;
  421. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  422. aProp[cProp].dwStatus = 0; // Ignored
  423. aProp[cProp].colid = dbcolNull;
  424. aProp[cProp].vValue.vt = VT_BOOL;
  425. aProp[cProp].vValue.boolVal = fForceUseCI ? VARIANT_TRUE : VARIANT_FALSE;
  426. aPropSet[cProp].rgProperties = &aProp[cProp];
  427. aPropSet[cProp].cProperties = 1;
  428. aPropSet[cProp].guidPropertySet = guidQueryExt;
  429. cProp++;
  430. }
  431. PROPVARIANT Variant;
  432. Variant.vt = VT_BOOL;
  433. Variant.boolVal = fForceUseCI ? VARIANT_TRUE : VARIANT_FALSE;
  434. variableSet.SetVariable( ISAPI_CI_FORCE_USE_CI, &Variant, 0 );
  435. _wcsDeferTrimming = ReplaceParameters( _idqFile.GetDeferTrimming(),
  436. variableSet,
  437. outputFormat,
  438. cwc );
  439. if ( 0 != _wcsDeferTrimming )
  440. {
  441. variableSet.CopyStringValue( ISAPI_CI_DEFER_NONINDEXED_TRIMMING, _wcsDeferTrimming, 0, cwc );
  442. }
  443. BOOL fDeferTrimming = _idqFile.ParseDeferTrimming( _wcsDeferTrimming );
  444. ciGibDebugOut(( DEB_ITRACE, "CiDeferNonIndexedTrimming = '%ws'\n", _wcsDeferTrimming ));
  445. {
  446. // Set the property that says we don't want to enumerate
  447. aProp[cProp].dwPropertyID = DBPROP_DEFERNONINDEXEDTRIMMING;
  448. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  449. aProp[cProp].dwStatus = 0; // Ignored
  450. aProp[cProp].colid = dbcolNull;
  451. aProp[cProp].vValue.vt = VT_BOOL;
  452. aProp[cProp].vValue.boolVal = fDeferTrimming ? VARIANT_TRUE : VARIANT_FALSE;
  453. aPropSet[cProp].rgProperties = &aProp[cProp];
  454. aPropSet[cProp].cProperties = 1;
  455. aPropSet[cProp].guidPropertySet = guidQueryExt;
  456. cProp++;
  457. }
  458. if ( _idqFile.IsDontTimeout() )
  459. {
  460. // Set the property that says we don't want to timeout
  461. aProp[cProp].dwPropertyID = DBPROP_COMMANDTIMEOUT;
  462. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  463. aProp[cProp].dwStatus = 0; // Ignored
  464. aProp[cProp].colid = dbcolNull;
  465. aProp[cProp].vValue.vt = VT_I4;
  466. aProp[cProp].vValue.lVal = 0;
  467. aPropSet[cProp].rgProperties = &aProp[cProp];
  468. aPropSet[cProp].cProperties = 1;
  469. aPropSet[cProp].guidPropertySet = guidRowsetProps;
  470. cProp++;
  471. }
  472. Win4Assert( Variant.vt == VT_BOOL );
  473. Variant.boolVal = fDeferTrimming ? VARIANT_TRUE : VARIANT_FALSE;
  474. variableSet.SetVariable( ISAPI_CI_DEFER_NONINDEXED_TRIMMING, &Variant, 0 );
  475. //
  476. // If this is a non-Sequential query, make it asynchronous
  477. //
  478. if (! IsSequential() )
  479. {
  480. // Set the property that says we want to use asynch. queries
  481. aProp[cProp].dwPropertyID = DBPROP_ROWSET_ASYNCH;
  482. aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
  483. aProp[cProp].dwStatus = 0; // Ignored
  484. aProp[cProp].colid = dbcolNull;
  485. aProp[cProp].vValue.vt = VT_I4;
  486. aProp[cProp].vValue.lVal = DBPROPVAL_ASYNCH_SEQUENTIALPOPULATION |
  487. DBPROPVAL_ASYNCH_RANDOMPOPULATION;
  488. aPropSet[cProp].rgProperties = &aProp[cProp];
  489. aPropSet[cProp].cProperties = 1;
  490. aPropSet[cProp].guidPropertySet = guidRowsetProps;
  491. cProp++;
  492. }
  493. if ( cProp > 0 )
  494. {
  495. Win4Assert( cProp <= MAX_PROPS );
  496. ICommandProperties * pCmdProp = 0;
  497. sc = _pICommand->QueryInterface( IID_ICommandProperties,
  498. (void **)&pCmdProp );
  499. if (FAILED (sc) )
  500. {
  501. THROW( CException( QUERY_EXECUTE_FAILED ) );
  502. }
  503. sc = pCmdProp->SetProperties( cProp, aPropSet );
  504. pCmdProp->Release();
  505. if ( FAILED(sc) || DB_S_ERRORSOCCURRED == sc )
  506. {
  507. THROW( CException( QUERY_EXECUTE_FAILED ) );
  508. }
  509. }
  510. //
  511. // Execute the query
  512. //
  513. sc = _pICommand->Execute( 0, // No aggr
  514. IsSequential() ? IID_IRowset : IID_IRowsetScroll,
  515. 0, // disp params
  516. 0, // # rowsets returned
  517. (IUnknown **) &_pIRowset );
  518. if ( FAILED(sc) )
  519. {
  520. ERRORINFO ErrorInfo;
  521. XInterface<IErrorInfo> xErrorInfo;
  522. SCODE sc2 = GetOleDBErrorInfo(_pICommand,
  523. IID_ICommand,
  524. GetLocale(),
  525. eMostDetailedCIError,
  526. &ErrorInfo,
  527. (IErrorInfo **)xErrorInfo.GetQIPointer());
  528. // Post IErrorInfo only if we have a valid ptr to it.
  529. if (SUCCEEDED(sc2) && 0 != xErrorInfo.GetPointer())
  530. {
  531. sc = ErrorInfo.hrError;
  532. // Maybe the ICommand is stale because cisvc was stopped and
  533. // restarted -- purge it from the cache.
  534. TheICommandCache.Remove( _pICommand );
  535. _pICommand = 0;
  536. THROW( CPostedOleDBException(sc, eDefaultISAPIError, xErrorInfo.GetPointer()) );
  537. }
  538. else
  539. {
  540. // Maybe the ICommand is stale because cisvc was stopped and
  541. // restarted -- purge it from the cache.
  542. TheICommandCache.Remove( _pICommand );
  543. _pICommand = 0;
  544. THROW( CException(sc) );
  545. }
  546. }
  547. //
  548. // Create an accessor
  549. //
  550. _pIAccessor = 0;
  551. sc = _pIRowset->QueryInterface( IID_IAccessor, (void **)&_pIAccessor);
  552. if ( FAILED( sc ) || _pIAccessor == 0 )
  553. {
  554. THROW( CException( DB_E_ERRORSOCCURRED ) );
  555. }
  556. ULONG cCols = _pDbColumns->Count();
  557. if ( cCols > MAX_QUERY_COLUMNS )
  558. {
  559. THROW( CException( DB_E_ERRORSOCCURRED ) );
  560. }
  561. sc = _pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // Type of access required
  562. cCols, // # of bindings
  563. g_aDbBinding, // Array of bindings
  564. 0, // reserved
  565. &_hAccessor,
  566. 0 );
  567. if ( FAILED( sc ) )
  568. {
  569. THROW( CException(sc) );
  570. }
  571. //
  572. // Create some of the restriction specific variables.
  573. //
  574. //
  575. // Get _pIRowsetStatus interface
  576. //
  577. sc = _pIRowset->QueryInterface( IID_IRowsetQueryStatus,
  578. (void **) &_pIRowsetStatus );
  579. if ( FAILED(sc) )
  580. {
  581. THROW( CException(sc) );
  582. }
  583. Win4Assert( 0 != _pIRowsetStatus );
  584. //
  585. // Save the # of filtered documents for this catalog and get the
  586. // query status.
  587. //
  588. DWORD dwStatus = 0;
  589. DWORD cToFilter;
  590. DBCOUNTITEM cDen, cNum;
  591. DBCOUNTITEM iCur, cTotal;
  592. sc = _pIRowsetStatus->GetStatusEx( &dwStatus,
  593. &_cFilteredDocuments,
  594. &cToFilter,
  595. &cDen,
  596. &cNum,
  597. 0,
  598. 0,
  599. &iCur,
  600. &cTotal );
  601. if ( FAILED( sc ) )
  602. {
  603. THROW( CException(sc) );
  604. }
  605. propVariant.vt = VT_BOOL;
  606. if ( QUERY_RELIABILITY_STATUS(dwStatus) &
  607. (STAT_CONTENT_OUT_OF_DATE | STAT_REFRESH_INCOMPLETE) )
  608. {
  609. propVariant.boolVal = VARIANT_TRUE;
  610. ciGibDebugOut(( DEB_ITRACE, "The query is out of date\n" ));
  611. }
  612. else
  613. {
  614. propVariant.boolVal = VARIANT_FALSE;
  615. }
  616. variableSet.SetVariable( ISAPI_CI_OUT_OF_DATE, &propVariant, 0 );
  617. if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_CONTENT_QUERY_INCOMPLETE )
  618. {
  619. propVariant.boolVal = VARIANT_TRUE;
  620. ciGibDebugOut(( DEB_ITRACE, "The query is incomplete\n" ));
  621. }
  622. else
  623. {
  624. propVariant.boolVal = VARIANT_FALSE;
  625. }
  626. variableSet.SetVariable( ISAPI_CI_QUERY_INCOMPLETE, &propVariant, 0 );
  627. if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_TIME_LIMIT_EXCEEDED )
  628. {
  629. propVariant.boolVal = VARIANT_TRUE;
  630. ciGibDebugOut(( DEB_ITRACE, "The query timed out\n" ));
  631. }
  632. else
  633. {
  634. propVariant.boolVal = VARIANT_FALSE;
  635. }
  636. variableSet.SetVariable( ISAPI_CI_QUERY_TIMEDOUT, &propVariant, 0 );
  637. //
  638. // Set CiQueryTimeZone
  639. //
  640. TIME_ZONE_INFORMATION TimeZoneInformation;
  641. DWORD dwResult = GetTimeZoneInformation( &TimeZoneInformation );
  642. LPWSTR pwszTimeZoneName = 0;
  643. if ( TIME_ZONE_ID_DAYLIGHT == dwResult )
  644. {
  645. pwszTimeZoneName = TimeZoneInformation.DaylightName;
  646. }
  647. else if ( 0xFFFFFFFF == dwResult )
  648. {
  649. # if CIDBG == 1
  650. DWORD dwError = GetLastError();
  651. ciGibDebugOut(( DEB_ERROR, "Error %d from GetTimeZoneInformation.\n", dwError ));
  652. THROW(CException( HRESULT_FROM_WIN32(dwError) ));
  653. # else
  654. THROW( CException() );
  655. # endif
  656. }
  657. else
  658. {
  659. pwszTimeZoneName = TimeZoneInformation.StandardName;
  660. }
  661. ULONG cchQueryTimeZone = wcslen( pwszTimeZoneName );
  662. _wcsQueryTimeZone = new WCHAR[ cchQueryTimeZone + 1 ];
  663. RtlCopyMemory( _wcsQueryTimeZone,
  664. pwszTimeZoneName,
  665. (cchQueryTimeZone+1) * sizeof(WCHAR) );
  666. }
  667. //+---------------------------------------------------------------------------
  668. //
  669. // Member: CWQueryItem::GetQueryResultsIterator - private
  670. //
  671. // Synopsis: Builds a CBaseQueryResultsIter which can subsequently be used
  672. // to send the query results back to the web browser. All
  673. // per-browser data relative to the query is kept in the iterator.
  674. //
  675. // Returns: [CBaseQueryResultsIter] - a sequential or non-sequential
  676. // iterator depending on the paramaters requested in the HTX
  677. // file.
  678. //
  679. // History: 96-Jan-18 DwightKr Created
  680. //
  681. //----------------------------------------------------------------------------
  682. CBaseQueryResultsIter * CWQueryItem::GetQueryResultsIterator( COutputFormat & outputFormat )
  683. {
  684. CBaseQueryResultsIter *pIter;
  685. //
  686. // Setup the formatting for the vector types
  687. //
  688. _idqFile.GetVectorFormatting( outputFormat );
  689. if ( IsSequential() )
  690. {
  691. Win4Assert( _lNextRecordNumber > 0 );
  692. pIter = new CSeqQueryResultsIter( *this,
  693. _pIRowset,
  694. _hAccessor,
  695. _pDbColumns->Count(),
  696. _lNextRecordNumber-1 );
  697. ciGibDebugOut(( DEB_ITRACE, "Using a sequential iterator\n" ));
  698. }
  699. else
  700. {
  701. IRowsetScroll *pIRowsetScroll = 0;
  702. HRESULT sc = _pIRowset->QueryInterface(IID_IRowsetScroll, (void **) &pIRowsetScroll);
  703. if ( FAILED( sc ) )
  704. {
  705. THROW( CException(sc) );
  706. }
  707. XInterface<IRowsetScroll> xIRowsetScroll(pIRowsetScroll);
  708. pIter = new CQueryResultsIter( *this,
  709. pIRowsetScroll,
  710. _hAccessor,
  711. _pDbColumns->Count() );
  712. xIRowsetScroll.Acquire();
  713. ciGibDebugOut(( DEB_ITRACE, "Using a NON-sequential iterator\n" ));
  714. }
  715. return pIter;
  716. }
  717. //+---------------------------------------------------------------------------
  718. //
  719. // Member: CWQueryItem::OutputQueryResults - public
  720. //
  721. // Arguments: [variableSet] - list of browser-supplied replaceable parameters
  722. // [outputFormat] - format of numbers & dates
  723. // [vString] - destination buffer for output results
  724. //
  725. // Synopsis: Using the parameters passed, build an iterator to walk the
  726. // query results and buffer output into the vString.
  727. //
  728. // History: 18-Jan-96 DwightKr Created
  729. // 11-Jun-97 KyleP Use web server from output format
  730. //
  731. //----------------------------------------------------------------------------
  732. void CWQueryItem::OutputQueryResults( CVariableSet & variableSet,
  733. COutputFormat & outputFormat,
  734. CVirtualString & vString )
  735. {
  736. //
  737. // Build the query results iterator based on the parameters passed in.
  738. //
  739. CBaseQueryResultsIter *pIter = GetQueryResultsIterator( outputFormat );
  740. XPtr<CBaseQueryResultsIter> iter(pIter);
  741. iter->Init( variableSet, outputFormat );
  742. UpdateQueryStatus( variableSet );
  743. //
  744. // Build the HTML pages in three sections: first the header
  745. // section (evenything before the <%begindetail%>), next the detail
  746. // section (everything between the <%begindetail%> and <%enddetail%>),
  747. // and finally the footer section (everything after the
  748. // <%enddetail%> section).
  749. //
  750. //
  751. // Output the header section.
  752. //
  753. _htxFile.GetHeader( vString, variableSet, outputFormat ) ;
  754. LONG lCurrentRecordNumber = iter->GetFirstRecordNumber();
  755. if ( _htxFile.DoesDetailSectionExist() )
  756. {
  757. //
  758. // Output the detail section
  759. //
  760. ULONG cCols = iter->GetColumnCount();
  761. XArray<CVariable *> xVariables( cCols );
  762. for ( ULONG i=0; i<cCols; i++ )
  763. {
  764. xVariables[i] = variableSet.SetVariable( _awcsColumns.Get(i), 0, 0 );
  765. Win4Assert( 0 != xVariables[i] );
  766. }
  767. PROPVARIANT VariantRecordNumber;
  768. VariantRecordNumber.vt = VT_I4;
  769. CVariable * pvarRecordNumber = variableSet.SetVariable( ISAPI_CI_CURRENT_RECORD_NUMBER, 0, 0 );
  770. Win4Assert( 0 != pvarRecordNumber );
  771. //
  772. // Execute the detail section for each row/record in the query results
  773. //
  774. for ( ;
  775. !iter->AtEnd();
  776. iter->Next(), lCurrentRecordNumber++ )
  777. {
  778. COutputColumn * pColumns = iter->GetRowData();
  779. //
  780. // Update the replaceable parameters for each of the columns
  781. // in this row.
  782. //
  783. for ( i = 0; i < cCols; i++ )
  784. xVariables[i]->FastSetValue( pColumns[i].GetVariant() );
  785. VariantRecordNumber.lVal = lCurrentRecordNumber;
  786. pvarRecordNumber->FastSetValue( &VariantRecordNumber );
  787. _htxFile.GetDetailSection( vString, variableSet, outputFormat );
  788. }
  789. //
  790. // The query output columns are no longer defined outside of the
  791. // DETAIL section. Delete these variables here so that any reference
  792. // to them will return a NULL string.
  793. //
  794. for ( i=0; i<cCols; i++ )
  795. {
  796. variableSet.Delete( xVariables[i] );
  797. }
  798. }
  799. //
  800. // If we couldn't get the first record #, then the current page #
  801. // should be set to 0.
  802. //
  803. if ( iter->GetFirstRecordNumber() == lCurrentRecordNumber )
  804. {
  805. PROPVARIANT Variant;
  806. Variant.vt = VT_I4;
  807. Variant.lVal = 0;
  808. variableSet.SetVariable( ISAPI_CI_CURRENT_PAGE_NUMBER, &Variant, 0 );
  809. }
  810. //
  811. // Output the footer section.
  812. //
  813. _htxFile.GetFooter( vString, variableSet, outputFormat );
  814. }
  815. //+---------------------------------------------------------------------------
  816. //
  817. // Member: CWQueryItem::UpdateQueryStatus - public
  818. //
  819. // Synopsis: Updates variables relating to query status.
  820. //
  821. // Arguments: [variableSet] - VariableSet to be updated
  822. //
  823. // Returns: Nothing
  824. //
  825. // Notes: These are post-execution checks that can change an up-to-date
  826. // query to an out-of-date query, but not the reverse. The
  827. // following variables are set:
  828. // CiOutOfDate
  829. // CiQueryIncomplete
  830. // CiQueryTimedOut
  831. //
  832. // History: 96 Apr 16 AlanW Created
  833. //
  834. //----------------------------------------------------------------------------
  835. void CWQueryItem::UpdateQueryStatus( CVariableSet & variableSet )
  836. {
  837. Win4Assert( 0 != _pIRowsetStatus );
  838. DWORD dwStatus = 0;
  839. DWORD cDocsFiltered, cToFilter;
  840. DBCOUNTITEM cDen, cNum;
  841. DBCOUNTITEM iCur, cTotal;
  842. SCODE sc = _pIRowsetStatus->GetStatusEx( &dwStatus,
  843. &cDocsFiltered,
  844. &cToFilter,
  845. &cDen,
  846. &cNum,
  847. 0,
  848. 0,
  849. &iCur,
  850. &cTotal );
  851. if ( FAILED( sc ) )
  852. THROW( CException(sc) );
  853. PROPVARIANT propVariant;
  854. propVariant.vt = VT_BOOL;
  855. BOOL fUpToDate = ( ( cDocsFiltered == _cFilteredDocuments ) &&
  856. ( 0 == cToFilter ) );
  857. if (( QUERY_RELIABILITY_STATUS(dwStatus) &
  858. (STAT_CONTENT_OUT_OF_DATE | STAT_REFRESH_INCOMPLETE) ) ||
  859. ! fUpToDate )
  860. {
  861. propVariant.boolVal = VARIANT_TRUE;
  862. ciGibDebugOut(( DEB_ITRACE, "The query is out of date\n" ));
  863. variableSet.SetVariable( ISAPI_CI_OUT_OF_DATE, &propVariant, 0 );
  864. }
  865. if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_CONTENT_QUERY_INCOMPLETE )
  866. {
  867. propVariant.boolVal = VARIANT_TRUE;
  868. ciGibDebugOut(( DEB_ITRACE, "The query is incomplete\n" ));
  869. variableSet.SetVariable( ISAPI_CI_QUERY_INCOMPLETE, &propVariant, 0 );
  870. }
  871. if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_TIME_LIMIT_EXCEEDED )
  872. {
  873. propVariant.boolVal = VARIANT_TRUE;
  874. ciGibDebugOut(( DEB_ITRACE, "The query timed out\n" ));
  875. variableSet.SetVariable( ISAPI_CI_QUERY_TIMEDOUT, &propVariant, 0 );
  876. }
  877. }
  878. //+---------------------------------------------------------------------------
  879. //
  880. // Member: CWQueryItem::IsQueryDone - public
  881. //
  882. // History: 96-Mar-01 DwightKr Created
  883. //
  884. //----------------------------------------------------------------------------
  885. BOOL CWQueryItem::IsQueryDone()
  886. {
  887. Win4Assert( 0 != _pIRowsetStatus );
  888. DWORD dwStatus = 0;
  889. SCODE sc = _pIRowsetStatus->GetStatus( &dwStatus );
  890. if ( FAILED( sc ) )
  891. {
  892. THROW( CException(sc) );
  893. }
  894. BOOL fQueryDone = FALSE;
  895. if ( QUERY_FILL_STATUS(dwStatus) == STAT_DONE ||
  896. QUERY_FILL_STATUS(dwStatus) == STAT_ERROR)
  897. {
  898. fQueryDone = TRUE;
  899. }
  900. return fQueryDone;
  901. }
  902. #if (DBG == 1)
  903. //+---------------------------------------------------------------------------
  904. //
  905. // Member: CWQueryItem::LokDump - public
  906. //
  907. // Arguments: [string] - buffer to send results to
  908. //
  909. // Synopsis: Dumps the state of the query
  910. //
  911. // History: 96-Jan-18 DwightKr Created
  912. //
  913. //----------------------------------------------------------------------------
  914. void CWQueryItem::LokDump( CVirtualString & string,
  915. CVariableSet * pVariableSet,
  916. COutputFormat * pOutputFormat )
  917. {
  918. if ( IsSequential() )
  919. {
  920. string.StrCat( L"<I>Sequential cursor</I><BR>\n" );
  921. }
  922. else
  923. {
  924. string.StrCat( L"<I>Non-Sequential cursor</I><BR>\n" );
  925. }
  926. if ( 0 != pVariableSet )
  927. pVariableSet->Dump( string, *pOutputFormat );
  928. WCHAR wcsBuffer[80];
  929. LONG cwcBuffer = swprintf( wcsBuffer, L"Refcount=%d<BR>\n", _refCount );
  930. string.StrCat( wcsBuffer, cwcBuffer );
  931. cwcBuffer = swprintf( wcsBuffer, L"NextRecordNumber=%d<BR>\n", _lNextRecordNumber );
  932. string.StrCat( wcsBuffer, cwcBuffer );
  933. cwcBuffer = swprintf( wcsBuffer, L"SequenceNumber=%d<BR>\n", _ulSequenceNumber );
  934. string.StrCat( wcsBuffer, cwcBuffer );
  935. cwcBuffer = swprintf( wcsBuffer, L"IDQ File name=" );
  936. string.StrCat( wcsBuffer, cwcBuffer );
  937. string.StrCat( _idqFile.GetIDQFileName() );
  938. string.StrCat( L"<BR>\n" );
  939. cwcBuffer = swprintf( wcsBuffer, L"# documents filtered when query created=%d<BR>\n", _cFilteredDocuments );
  940. string.StrCat( wcsBuffer, cwcBuffer );
  941. string.StrCat( L"<P>\n" );
  942. }
  943. #endif // DBG
  944. //+---------------------------------------------------------------------------
  945. //
  946. // Member: CWPendingQueryItem::CWPendingQueryItem - public constructor
  947. //
  948. // Synposis: Builds a item for use to track an asynchronous query.
  949. //
  950. // Arguments: [queryItem] - query item that is pending
  951. // [outputFormat] - output format supplied by the browser
  952. // [variableSet] - browser supplied variables
  953. //
  954. // History: 96-Mar-01 DwightKr Created
  955. //
  956. //----------------------------------------------------------------------------
  957. CWPendingQueryItem::CWPendingQueryItem( XPtr<CWQueryItem> & queryItem,
  958. XPtr<COutputFormat> & outputFormat,
  959. XPtr<CVariableSet> & variableSet ) :
  960. _pQueryItem(queryItem.GetPointer()),
  961. _pOutputFormat(outputFormat.GetPointer()),
  962. _pVariableSet(variableSet.GetPointer())
  963. {
  964. queryItem.Acquire();
  965. outputFormat.Acquire();
  966. variableSet.Acquire();
  967. }
  968. //+---------------------------------------------------------------------------
  969. //
  970. // Member: CWPendingQueryItem::~CWPendingQueryItem - public destructor
  971. //
  972. // Synposis: Destrolys a query item
  973. //
  974. // History: 96-Mar-01 DwightKr Created
  975. // 96-Nov-25 dlee added header, moved out of .hxx
  976. //
  977. //----------------------------------------------------------------------------
  978. CWPendingQueryItem::~CWPendingQueryItem()
  979. {
  980. Win4Assert( 0 != _pOutputFormat );
  981. if ( _pOutputFormat->IsValid() )
  982. {
  983. TheWebQueryCache.DecrementActiveRequests();
  984. ciGibDebugOut(( DEB_ITRACE, "~cwpendingqueryitem releasing session hse %d http %d\n",
  985. HSE_STATUS_SUCCESS, HTTP_STATUS_OK ));
  986. //
  987. // Processing the query may not have been successful, but if so
  988. // we wrote an error message, so from an isapi standpoint this was
  989. // a success.
  990. //
  991. _pOutputFormat->SetHttpStatus( HTTP_STATUS_OK );
  992. _pOutputFormat->ReleaseSession( HSE_STATUS_SUCCESS );
  993. }
  994. delete _pQueryItem;
  995. delete _pOutputFormat;
  996. delete _pVariableSet;
  997. }
  998. #if (DBG == 1)
  999. //+---------------------------------------------------------------------------
  1000. //
  1001. // Member: CWPendingQueryItem::LokDump - public
  1002. //
  1003. // Arguments: [string] - buffer to send results to
  1004. //
  1005. // Synopsis: Dumps the state of a pending query
  1006. //
  1007. // History: 96 Mar 20 Alanw Created
  1008. //
  1009. //----------------------------------------------------------------------------
  1010. void CWPendingQueryItem::LokDump( CVirtualString & string )
  1011. {
  1012. if ( IsQueryDone() )
  1013. {
  1014. string.StrCat( L"<I>Completed query, </I>" );
  1015. }
  1016. else
  1017. {
  1018. string.StrCat( L"<I>Executing query, </I>" );
  1019. }
  1020. _pQueryItem->LokDump( string, _pVariableSet, _pOutputFormat );
  1021. }
  1022. #endif // DBG