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.

932 lines
30 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1998.
  5. //
  6. // File: wqiter.cxx
  7. //
  8. // Contents: WEB Query cache iterators
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. //+---------------------------------------------------------------------------
  16. //
  17. // Member: CBaseQueryResultsIter::CBaseQueryResultsIter - public constructor
  18. //
  19. // Arguments: [item] - the query results we are iterating over
  20. // [hAccessor] - an accessor to the query results
  21. // [cCols] - number of output columns
  22. // [xVariableSet] - a list of replaceable parameters
  23. //
  24. // Synopsis: Initializes common vars between sequential & non-sequential
  25. // iterators
  26. //
  27. // History: 96-Jan-18 DwightKr Created
  28. //
  29. //----------------------------------------------------------------------------
  30. CBaseQueryResultsIter::CBaseQueryResultsIter( CWQueryItem & item,
  31. HACCESSOR hAccessor,
  32. ULONG cCols ) :
  33. _item(item),
  34. _hAccessor(hAccessor),
  35. _cColumns(cCols),
  36. _pVariableSet(0),
  37. _cRowsReturnedToCache(0),
  38. _iCurrentCachedRow(0),
  39. _lFirstRecordNumber(1),
  40. _lMaxRecordsPerPage(0),
  41. _lNextRecordNumber(1),
  42. _lRecordsToRetrieve(0),
  43. _lTotalMatchedRecords(LONG_MAX),
  44. _pOutputColumns(_aOutputColumns)
  45. {
  46. }
  47. //+---------------------------------------------------------------------------
  48. //
  49. // Member: CBaseQueryResultsIter::~CBaseQueryResultsIter - public destructor
  50. //
  51. // History: 96-Jan-18 DwightKr Created
  52. //
  53. //----------------------------------------------------------------------------
  54. CBaseQueryResultsIter::~CBaseQueryResultsIter()
  55. {
  56. if ( _pOutputColumns != _aOutputColumns )
  57. {
  58. delete _pOutputColumns;
  59. }
  60. }
  61. //+---------------------------------------------------------------------------
  62. //
  63. // Member: CBaseQueryResultsIter::InitalizeLocalVariables - protected
  64. //
  65. // Arguments: [variableSet] -- local variables from browser
  66. // [outputFormat] -- Output formatter
  67. //
  68. // Synopsis: Sets up the common local variables for this query
  69. //
  70. // History: 96-Jan-18 DwightKr Created
  71. //
  72. //----------------------------------------------------------------------------
  73. void CBaseQueryResultsIter::InitializeLocalVariables( CVariableSet & variableSet,
  74. COutputFormat & outputFormat )
  75. {
  76. //
  77. // Setup the following variables:
  78. //
  79. // CiMaxRecordsPerPage
  80. // CiBookmark
  81. // CiCurrentPageNumber
  82. // CiContainsFirstRecord
  83. // CiOutOfDate
  84. // CiQueryTime
  85. // CiQueryDate
  86. // CiQueryTimezone
  87. // CiColumns
  88. // CiTemplate
  89. //
  90. _pVariableSet = &variableSet;
  91. PROPVARIANT Variant;
  92. CIDQFile const & idqFile = _item.GetIDQFile();
  93. //
  94. // Set CiMaxRecordsPerPage
  95. //
  96. _lMaxRecordsPerPage = ReplaceNumericParameter ( idqFile.GetMaxRecordsPerPage(),
  97. variableSet,
  98. outputFormat,
  99. 10,
  100. 1,
  101. 0x10000 );
  102. _lRecordsToRetrieve = _lMaxRecordsPerPage;
  103. Variant.vt = VT_I4;
  104. Variant.lVal = _lMaxRecordsPerPage;
  105. _pVariableSet->SetVariable( ISAPI_CI_MAX_RECORDS_PER_PAGE, &Variant, 0 );
  106. //
  107. // Calulate the # of the first record to display
  108. //
  109. ULONG cwcValue;
  110. CVariable * pVariable = variableSet.Find(ISAPI_CI_BOOKMARK);
  111. if ( (0 != pVariable) &&
  112. (0 != pVariable->GetStringValueRAW(outputFormat, cwcValue)) &&
  113. (0 != cwcValue) )
  114. {
  115. CWQueryBookmark bookMark( pVariable->GetStringValueRAW(outputFormat, cwcValue) );
  116. _lFirstRecordNumber = bookMark.GetRecordNumber();
  117. }
  118. pVariable = variableSet.Find(ISAPI_CI_BOOKMARK_SKIP_COUNT);
  119. if ( (0 != pVariable) && (0 != pVariable->GetStringValueRAW(outputFormat, cwcValue)) )
  120. {
  121. _lFirstRecordNumber += IDQ_wtol( pVariable->GetStringValueRAW(outputFormat, cwcValue) );
  122. }
  123. //
  124. // Set CiContainsFirstRecord
  125. //
  126. Variant.vt = VT_BOOL;
  127. Variant.boolVal = VARIANT_FALSE;
  128. if ( 1 == _lFirstRecordNumber )
  129. {
  130. Variant.boolVal = VARIANT_TRUE;
  131. }
  132. _pVariableSet->SetVariable( ISAPI_CI_CONTAINS_FIRST_RECORD, &Variant, 0 );
  133. //
  134. // The first record must be at least 1. If the browser specified a
  135. // large negative skipcount, we need to move the first record number
  136. // forward to 1.
  137. //
  138. _lFirstRecordNumber = max( 1, _lFirstRecordNumber );
  139. //
  140. // For sequential queries, _lTotalMatchedRecords is LONG_MAX, not the
  141. // total number of matched records.
  142. //
  143. if (_lFirstRecordNumber > _lTotalMatchedRecords)
  144. _lFirstRecordNumber = (LONG) _lTotalMatchedRecords+1;
  145. //
  146. // Set CiBookmark
  147. //
  148. CWQueryBookmark bookMark( _item.IsSequential(),
  149. &_item,
  150. _item.GetSequenceNumber(),
  151. _lFirstRecordNumber );
  152. ULONG cwcBookmark = wcslen( bookMark.GetBookmark() );
  153. XArray<WCHAR> wcsCiBookMark( cwcBookmark + 1 );
  154. RtlCopyMemory( wcsCiBookMark.Get(),
  155. bookMark.GetBookmark(),
  156. (cwcBookmark+1) * sizeof(WCHAR) );
  157. Variant.vt = VT_LPWSTR;
  158. Variant.pwszVal = wcsCiBookMark.Get();
  159. _pVariableSet->SetVariable( ISAPI_CI_BOOKMARK,
  160. &Variant,
  161. eParamOwnsVariantMemory );
  162. wcsCiBookMark.Acquire();
  163. _lNextRecordNumber = _lFirstRecordNumber;
  164. //
  165. //
  166. // Set CiCurrentPageNumber
  167. //
  168. Variant.vt = VT_I4;
  169. Variant.lVal = _lFirstRecordNumber / _lMaxRecordsPerPage;
  170. if ( (_lFirstRecordNumber % _lMaxRecordsPerPage) != 0 )
  171. {
  172. Variant.lVal++;
  173. }
  174. _pVariableSet->SetVariable( ISAPI_CI_CURRENT_PAGE_NUMBER, &Variant, 0 );
  175. SetCGIVariables( *_pVariableSet, outputFormat );
  176. #if 1 //nuke this soon
  177. //
  178. // Set CiQueryTime
  179. //
  180. ULONG cwcQueryTime = 40;
  181. XArray<WCHAR> wcsQueryTime(cwcQueryTime-1);
  182. cwcQueryTime = outputFormat.FormatTime( _item.GetQueryTime(),
  183. wcsQueryTime.GetPointer(),
  184. cwcQueryTime );
  185. //
  186. // SetCiQueryDate
  187. //
  188. ULONG cwcQueryDate = 40;
  189. XArray<WCHAR> wcsQueryDate(cwcQueryDate-1);
  190. cwcQueryDate = outputFormat.FormatDate( _item.GetQueryTime(),
  191. wcsQueryDate.GetPointer(),
  192. cwcQueryDate );
  193. variableSet.AcquireStringValue( ISAPI_CI_QUERY_TIME, wcsQueryTime.GetPointer(), 0 );
  194. wcsQueryTime.Acquire();
  195. variableSet.AcquireStringValue( ISAPI_CI_QUERY_DATE, wcsQueryDate.GetPointer(), 0 );
  196. wcsQueryDate.Acquire();
  197. #endif
  198. variableSet.CopyStringValue( ISAPI_CI_QUERY_TIMEZONE, _item.GetQueryTimeZone(), 0 );
  199. variableSet.CopyStringValue( ISAPI_CI_COLUMNS, _item.GetColumns(), 0 );
  200. variableSet.CopyStringValue( ISAPI_CI_TEMPLATE, _item.GetTemplate(), 0 );
  201. }
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Member: CQueryResultsIter::CQueryResultsIter - public constructor
  205. //
  206. // Arguments: [item] - the query results we are iterating over
  207. // [pIRowsetScroll] - a IRowsetScroll interface
  208. // [hAccessor] - an accessor to the query results
  209. // [cCols] - number of output columns
  210. //
  211. // Synopsis: Builds an iterator used to access a non-sequential set of
  212. // query results.
  213. //
  214. // Notes: ownership of the xVariableSet is transferred to this class
  215. // as well as the IRowsetScroll interface
  216. //
  217. // History: 96-Jan-18 DwightKr Created
  218. //
  219. //----------------------------------------------------------------------------
  220. CQueryResultsIter::CQueryResultsIter( CWQueryItem & item,
  221. IRowsetScroll * pIRowsetScroll,
  222. HACCESSOR hAccessor,
  223. ULONG cCols ) :
  224. CBaseQueryResultsIter( item,
  225. hAccessor,
  226. cCols ),
  227. _pIRowsetScroll(pIRowsetScroll)
  228. {
  229. Win4Assert( pIRowsetScroll != 0 );
  230. Win4Assert( hAccessor != 0 );
  231. }
  232. //+---------------------------------------------------------------------------
  233. //
  234. // Member: CQueryResultsIter::~CQueryResultsIter - public destructor
  235. //
  236. // Synopsis: Releases storage & IRowsetScroll interface
  237. //
  238. // History: 96-Jan-18 DwightKr Created
  239. //
  240. //----------------------------------------------------------------------------
  241. CQueryResultsIter::~CQueryResultsIter()
  242. {
  243. ReleaseRowsetCache();
  244. _pIRowsetScroll->Release();
  245. }
  246. //+---------------------------------------------------------------------------
  247. //
  248. // Member: CQueryResultsIter::Init - public
  249. //
  250. // Arguments: [variableSet] -- local variables from the user's browser
  251. // [outputFormat] -- format of $'s & dates
  252. //
  253. // Synopsis: Sets up the number & date/time formatting, and fills the
  254. // cache with the first set of rows.
  255. //
  256. // History: 96-Jan-18 DwightKr Created
  257. //
  258. //----------------------------------------------------------------------------
  259. void CQueryResultsIter::Init( CVariableSet & variableSet,
  260. COutputFormat & outputFormat )
  261. {
  262. //
  263. // If the in-line buffer isn't big enough, allocate a new buffer
  264. //
  265. if ( _cColumns > NUMBER_INLINE_COLS )
  266. {
  267. _pOutputColumns = new COutputColumn[_cColumns];
  268. }
  269. InitializeLocalVariables( variableSet, outputFormat );
  270. FillRowsetCache();
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. // Member: CQueryResultsIter::Next - public
  275. //
  276. // Synopsis: Sets up the next row to be acessed by the GetRowData()
  277. // method, and fills the cache if necessary.
  278. //
  279. // History: 96-Jan-18 DwightKr Created
  280. //
  281. //----------------------------------------------------------------------------
  282. void CQueryResultsIter::Next()
  283. {
  284. _iCurrentCachedRow++;
  285. if ( _iCurrentCachedRow >= _cRowsReturnedToCache )
  286. {
  287. ReleaseRowsetCache();
  288. FillRowsetCache();
  289. }
  290. Win4Assert( _iCurrentCachedRow <= _cRowsReturnedToCache );
  291. }
  292. //+---------------------------------------------------------------------------
  293. //
  294. // Member: CQueryResultsIter::InitalizeLocalVariables - private
  295. //
  296. // Arguments: [variableSet] - local variables from browser
  297. // [outputFormat] - format of numbers & dates
  298. //
  299. // Synopsis: Sets up the local variables for this query
  300. //
  301. // History: 96-Jan-18 DwightKr Created
  302. //
  303. //----------------------------------------------------------------------------
  304. void CQueryResultsIter::InitializeLocalVariables( CVariableSet & variableSet,
  305. COutputFormat & outputFormat )
  306. {
  307. //
  308. // Set CiMatchedRecordCount
  309. //
  310. DBCOUNTITEM ulPosition;
  311. HRESULT sc = _pIRowsetScroll->GetApproximatePosition(0,0,0,
  312. &ulPosition,
  313. (DBCOUNTITEM *) &_lTotalMatchedRecords );
  314. if ( FAILED( sc ) )
  315. {
  316. THROW( CException(sc) );
  317. }
  318. PROPVARIANT Variant;
  319. Variant.vt = VT_I4;
  320. Variant.lVal = (LONG) _lTotalMatchedRecords;
  321. variableSet.SetVariable( ISAPI_CI_MATCHED_RECORD_COUNT, &Variant, 0 );
  322. //
  323. // Setup the following variables:
  324. //
  325. // CiMatchRecordCount
  326. // CiContainsLastRecord
  327. // CiTotalNumberPages
  328. // CiFirstRecordNumber
  329. // CiLastRecordNumber
  330. //
  331. CBaseQueryResultsIter::InitializeLocalVariables( variableSet, outputFormat );
  332. CIDQFile const & idqFile = _item.GetIDQFile();
  333. //
  334. // Set CiContainsLastRecord
  335. //
  336. Variant.vt = VT_BOOL;
  337. Variant.boolVal = VARIANT_FALSE;
  338. if ( (_lFirstRecordNumber + _lMaxRecordsPerPage) > _lTotalMatchedRecords )
  339. {
  340. Variant.boolVal = VARIANT_TRUE;
  341. }
  342. _pVariableSet->SetVariable( ISAPI_CI_CONTAINS_LAST_RECORD, &Variant, 0 );
  343. //
  344. // Set CiTotalNumberPages
  345. //
  346. Variant.vt = VT_I4;
  347. Variant.lVal = (LONG) _lTotalMatchedRecords / _lMaxRecordsPerPage;
  348. if ( (_lTotalMatchedRecords % _lMaxRecordsPerPage) != 0 )
  349. {
  350. Variant.lVal++;
  351. }
  352. _pVariableSet->SetVariable( ISAPI_CI_TOTAL_NUMBER_PAGES, &Variant, 0 );
  353. //
  354. // Set CiFirstRecordNumber
  355. //
  356. Variant.vt = VT_I4;
  357. Variant.lVal = _lFirstRecordNumber;
  358. _pVariableSet->SetVariable( ISAPI_CI_FIRST_RECORD_NUMBER, &Variant, 0 );
  359. //
  360. // Set CiLastRecordNumber
  361. //
  362. LONG lLastRecordNumber = _lFirstRecordNumber + _lMaxRecordsPerPage - 1;
  363. if ( lLastRecordNumber > _lTotalMatchedRecords )
  364. {
  365. lLastRecordNumber = (LONG) _lTotalMatchedRecords;
  366. }
  367. Variant.vt = VT_I4;
  368. Variant.lVal = lLastRecordNumber;
  369. _pVariableSet->SetVariable( ISAPI_CI_LAST_RECORD_NUMBER, &Variant, 0 );
  370. //
  371. // Set CiRecordsNextPage
  372. //
  373. Variant.vt = VT_I4;
  374. if ( (lLastRecordNumber + _lMaxRecordsPerPage) <= _lTotalMatchedRecords )
  375. {
  376. Variant.lVal = _lMaxRecordsPerPage;
  377. }
  378. else
  379. {
  380. Variant.lVal = (LONG) _lTotalMatchedRecords - lLastRecordNumber;
  381. }
  382. _pVariableSet->SetVariable( ISAPI_CI_RECORDS_NEXT_PAGE , &Variant, 0 );
  383. }
  384. //+---------------------------------------------------------------------------
  385. //
  386. // Member: CQueryResultsIter::FillRowsetCache - public
  387. //
  388. // Synopsis: Fills the cache with the next set of hRows
  389. //
  390. // History: 96-Jan-18 DwightKr Created
  391. //
  392. //----------------------------------------------------------------------------
  393. void CQueryResultsIter::FillRowsetCache()
  394. {
  395. ULONG ulRecordsToRetrieve = min(ITER_CACHE_SIZE, _lRecordsToRetrieve );
  396. if ( ulRecordsToRetrieve > 0 )
  397. {
  398. BYTE bookMark = DBBMK_FIRST;
  399. HROW * phCachedRows = _ahCachedRows;
  400. HRESULT sc = _pIRowsetScroll->GetRowsAt( DBWATCHREGION_NULL,
  401. NULL,
  402. 1,
  403. &bookMark,
  404. _lNextRecordNumber - 1,
  405. ulRecordsToRetrieve,
  406. &_cRowsReturnedToCache,
  407. &phCachedRows );
  408. if ( DB_E_BADSTARTPOSITION == sc )
  409. {
  410. // Requested fetch outside available rows. Treat as end of rowset.
  411. Win4Assert(_lNextRecordNumber > 0);
  412. sc = DB_S_ENDOFROWSET;
  413. _cRowsReturnedToCache = 0;
  414. }
  415. if ( FAILED(sc) )
  416. {
  417. THROW( CException(sc) );
  418. }
  419. _lNextRecordNumber += (LONG) _cRowsReturnedToCache;
  420. if ( 0 == _cRowsReturnedToCache ||
  421. DB_S_ENDOFROWSET == sc )
  422. {
  423. Win4Assert( DB_S_ENDOFROWSET == sc );
  424. _lRecordsToRetrieve = 0;
  425. }
  426. else
  427. {
  428. _lRecordsToRetrieve -= (LONG) _cRowsReturnedToCache;
  429. }
  430. }
  431. }
  432. //+---------------------------------------------------------------------------
  433. //
  434. // Member: CQueryResultsIter::ReleaseRowsetCache - public
  435. //
  436. // Synopsis: Releases the hRows currently in the cache
  437. //
  438. // History: 96-Jan-18 DwightKr Created
  439. //
  440. //----------------------------------------------------------------------------
  441. void CQueryResultsIter::ReleaseRowsetCache()
  442. {
  443. if ( _cRowsReturnedToCache > 0 )
  444. {
  445. _pIRowsetScroll->ReleaseRows( _cRowsReturnedToCache,
  446. _ahCachedRows,
  447. 0,
  448. 0,
  449. 0 );
  450. }
  451. _cRowsReturnedToCache = 0;
  452. _iCurrentCachedRow = 0;
  453. }
  454. //+---------------------------------------------------------------------------
  455. //
  456. // Member: CQueryResultsIter::GetRowData - public
  457. //
  458. // Synopsis: Returns the output columns for the current row.
  459. //
  460. // Results: [COutputColumn *] an array of output columns
  461. //
  462. // History: 96-Jan-18 DwightKr Created
  463. //
  464. //----------------------------------------------------------------------------
  465. COutputColumn * CQueryResultsIter::GetRowData()
  466. {
  467. Win4Assert( _iCurrentCachedRow < _cRowsReturnedToCache );
  468. HRESULT hr = _pIRowsetScroll->GetData( _ahCachedRows[_iCurrentCachedRow],
  469. _hAccessor,
  470. _pOutputColumns );
  471. if ( FAILED(hr) )
  472. {
  473. THROW( CException(hr) );
  474. }
  475. return _pOutputColumns;
  476. }
  477. //+---------------------------------------------------------------------------
  478. //
  479. // Member: CSeqQueryResultsIter::CSeqQueryResultsIter - public constructor
  480. //
  481. // Arguments: [item] - the query results we are iterating over
  482. // [pIRowset] - an IRowset interface
  483. // [hAccessor] - an accessor to the query results
  484. // [cCols] - number of output columns
  485. // [xVariableSet] - a list of replaceable parameters
  486. // [ulNextRecordNumnber] - next available rec # in this query
  487. //
  488. // Synopsis: Builds an iterator used to access a non-sequential set of
  489. // query results.
  490. //
  491. // Notes: ownership of the pVariableSet is transferred to this class
  492. //
  493. // History: 96-Jan-18 DwightKr Created
  494. //
  495. //----------------------------------------------------------------------------
  496. CSeqQueryResultsIter::CSeqQueryResultsIter( CWQueryItem & item,
  497. IRowset * pIRowset,
  498. HACCESSOR hAccessor,
  499. ULONG cCols,
  500. ULONG ulNextRecordNumber ) :
  501. CBaseQueryResultsIter( item,
  502. hAccessor,
  503. cCols ),
  504. _pIRowset(pIRowset)
  505. {
  506. Win4Assert( pIRowset != 0 );
  507. Win4Assert( hAccessor != 0 );
  508. _lNextRecordNumber = ulNextRecordNumber;
  509. }
  510. //+---------------------------------------------------------------------------
  511. //
  512. // Member: CSeqQueryResultsIter::~CSeqQueryResultsIter - public destructor
  513. //
  514. // Synopsis: Releases storage.
  515. //
  516. // History: 96-Jan-18 DwightKr Created
  517. //
  518. //----------------------------------------------------------------------------
  519. CSeqQueryResultsIter::~CSeqQueryResultsIter()
  520. {
  521. ReleaseRowsetCache();
  522. }
  523. //+---------------------------------------------------------------------------
  524. //
  525. // Member: CSeqQueryResultsIter::Init - public
  526. //
  527. // Arguments: [outputFormat] - format of numbers & dates
  528. // [variableSet] - local variables from the user's browser
  529. //
  530. // Synopsis: Sets up the number & date/time formatting, and fills the
  531. // cache with the first set of rows.
  532. //
  533. // History: 96-Jan-18 DwightKr Created
  534. //
  535. //----------------------------------------------------------------------------
  536. void CSeqQueryResultsIter::Init( CVariableSet & variableSet,
  537. COutputFormat & outputFormat )
  538. {
  539. //
  540. // If the in-line buffer isn't big enough, allocate a new buffer
  541. //
  542. if ( _cColumns > NUMBER_INLINE_COLS )
  543. {
  544. _pOutputColumns = new COutputColumn[_cColumns];
  545. }
  546. InitializeLocalVariables( variableSet, outputFormat );
  547. ULONG cRowsToSkip = _lFirstRecordNumber - _item.GetNextRecordNumber();
  548. FillRowsetCache( cRowsToSkip );
  549. }
  550. //+---------------------------------------------------------------------------
  551. //
  552. // Member: CSeqQueryResultsIter::Next - public
  553. //
  554. // Synopsis: Sets up the next row to be acessed by the GetRowData()
  555. // method, and fills the cache if necessary.
  556. //
  557. // History: 96-Jan-18 DwightKr Created
  558. //
  559. //----------------------------------------------------------------------------
  560. void CSeqQueryResultsIter::Next()
  561. {
  562. _iCurrentCachedRow++;
  563. if ( _iCurrentCachedRow >= _cRowsReturnedToCache )
  564. {
  565. ReleaseRowsetCache();
  566. FillRowsetCache(0);
  567. }
  568. Win4Assert( _iCurrentCachedRow <= _cRowsReturnedToCache );
  569. }
  570. //+---------------------------------------------------------------------------
  571. //
  572. // Member: CSeqQueryResultsIter::FillRowsetCache - public
  573. //
  574. // Arguments: [cRowsToSkip] - number of rows to skip before filling cache
  575. //
  576. // Synopsis: Fills the cache with the next set of hRows
  577. //
  578. // History: 96-Jan-18 DwightKr Created
  579. //
  580. //----------------------------------------------------------------------------
  581. void CSeqQueryResultsIter::FillRowsetCache( ULONG cRowsToSkip )
  582. {
  583. ULONG ulRecordsToRetrieve = min(ITER_CACHE_SIZE, _lRecordsToRetrieve);
  584. if ( ulRecordsToRetrieve > 0 )
  585. {
  586. HROW * phCachedRows = _ahCachedRows;
  587. HRESULT sc = _pIRowset->GetNextRows( NULL,
  588. cRowsToSkip,
  589. ulRecordsToRetrieve,
  590. &_cRowsReturnedToCache,
  591. &phCachedRows );
  592. if ( DB_E_BADSTARTPOSITION == sc )
  593. sc = DB_S_ENDOFROWSET;
  594. if ( FAILED(sc) )
  595. {
  596. THROW( CException(sc) );
  597. }
  598. _lNextRecordNumber += (LONG) _cRowsReturnedToCache;
  599. _lRecordsToRetrieve -= (LONG) _cRowsReturnedToCache;
  600. //
  601. // Set the CiContainsLastRecord variable to TRUE if we have
  602. // exhausted the query results.
  603. //
  604. PROPVARIANT Variant;
  605. Variant.vt = VT_BOOL;
  606. Variant.boolVal = VARIANT_FALSE;
  607. if ( 0 == _cRowsReturnedToCache ||
  608. DB_S_ENDOFROWSET == sc ||
  609. DB_S_STOPLIMITREACHED == sc )
  610. {
  611. Win4Assert( DB_S_ENDOFROWSET == sc || DB_S_STOPLIMITREACHED == sc );
  612. _lRecordsToRetrieve = 0;
  613. Variant.boolVal = VARIANT_TRUE;
  614. }
  615. _pVariableSet->SetVariable( ISAPI_CI_CONTAINS_LAST_RECORD, &Variant, 0 );
  616. if ( DB_S_STOPLIMITREACHED == sc )
  617. {
  618. Variant.boolVal = VARIANT_TRUE;
  619. _pVariableSet->SetVariable( ISAPI_CI_QUERY_TIMEDOUT, &Variant, 0 );
  620. }
  621. //
  622. // Set CiLastRecordNumber
  623. //
  624. Variant.vt = VT_I4;
  625. Variant.lVal = _lNextRecordNumber - 1;
  626. _pVariableSet->SetVariable( ISAPI_CI_LAST_RECORD_NUMBER, &Variant, 0 );
  627. _item.SetNextRecordNumber( _lNextRecordNumber );
  628. }
  629. }
  630. //+---------------------------------------------------------------------------
  631. //
  632. // Member: CSeqQueryResultsIter::ReleaseRowsetCache - public
  633. //
  634. // Synopsis: Releases the hRows currently in the cache
  635. //
  636. // History: 96-Jan-18 DwightKr Created
  637. //
  638. //----------------------------------------------------------------------------
  639. void CSeqQueryResultsIter::ReleaseRowsetCache()
  640. {
  641. if ( _cRowsReturnedToCache > 0 )
  642. {
  643. _pIRowset->ReleaseRows( _cRowsReturnedToCache,
  644. _ahCachedRows,
  645. 0,
  646. 0,
  647. 0 );
  648. }
  649. _cRowsReturnedToCache = 0;
  650. _iCurrentCachedRow = 0;
  651. }
  652. //+---------------------------------------------------------------------------
  653. //
  654. // Member: CSeqQueryResultsIter::GetRowData - public
  655. //
  656. // Synopsis: Returns the output columns for the current row.
  657. //
  658. // Results: [COutputColumn *] an array of output columns
  659. //
  660. // History: 96-Jan-18 DwightKr Created
  661. //
  662. //----------------------------------------------------------------------------
  663. COutputColumn * CSeqQueryResultsIter::GetRowData()
  664. {
  665. Win4Assert( _iCurrentCachedRow < _cRowsReturnedToCache );
  666. HRESULT hr = _pIRowset->GetData( _ahCachedRows[_iCurrentCachedRow],
  667. _hAccessor,
  668. _pOutputColumns );
  669. if ( FAILED(hr) )
  670. {
  671. THROW( CException(hr) );
  672. }
  673. return _pOutputColumns;
  674. }
  675. //+---------------------------------------------------------------------------
  676. //
  677. // Member: CSeqQueryResultsIter::InitalizeLocalVariables - private
  678. //
  679. // Arguments: [variableSet] - local variables from browser
  680. // [outputFormat] - format of numbers & dates
  681. //
  682. // Synopsis: Sets up the local variables for this query
  683. //
  684. // History: 96-Jan-18 DwightKr Created
  685. //
  686. //----------------------------------------------------------------------------
  687. void CSeqQueryResultsIter::InitializeLocalVariables( CVariableSet & variableSet,
  688. COutputFormat & outputFormat )
  689. {
  690. //
  691. // Setup the following variables:
  692. //
  693. // CiContainsLastRecord
  694. // CiFirstRecordNumber
  695. //
  696. CBaseQueryResultsIter::InitializeLocalVariables( variableSet, outputFormat );
  697. //
  698. // Set CiFirstRecordNumber
  699. //
  700. PROPVARIANT Variant;
  701. Variant.vt = VT_I4;
  702. Variant.lVal = _lFirstRecordNumber;
  703. _pVariableSet->SetVariable( ISAPI_CI_FIRST_RECORD_NUMBER, &Variant, 0 );
  704. }
  705. //+---------------------------------------------------------------------------
  706. //
  707. // Member: SetCGIVariables - public
  708. //
  709. // History: 96-Mar-04 DwightKr Created
  710. //
  711. //----------------------------------------------------------------------------
  712. void SetCGIVariables( CVariableSet & variableSet, CWebServer & webServer )
  713. {
  714. {
  715. XArray<WCHAR> xValue;
  716. ULONG cwcValue;
  717. if ( webServer.GetCGI_REQUEST_METHOD( xValue, cwcValue ) )
  718. variableSet.SetVariable( ISAPI_REQUEST_METHOD, xValue );
  719. if ( webServer.GetCGI_PATH_INFO( xValue, cwcValue ) )
  720. variableSet.SetVariable( ISAPI_PATH_INFO, xValue );
  721. if ( webServer.GetCGI_PATH_TRANSLATED( xValue, cwcValue ) )
  722. variableSet.SetVariable( ISAPI_PATH_TRANSLATED, xValue );
  723. if ( webServer.GetCGI_CONTENT_TYPE( xValue, cwcValue ) )
  724. variableSet.SetVariable( ISAPI_CONTENT_TYPE, xValue );
  725. }
  726. //
  727. // The HTTP variables can be obtained from ALL_HTTP. attribute/value
  728. // pairs are delimited by \n and the attribute is separated from
  729. // the value by a colon. For example:
  730. //
  731. // HTTP_DWIGHT:This is a HTTP_DWIGHT\nHTTP_KRUGER:This is another\n...
  732. //
  733. XArray<WCHAR> wcsALLHTTP;
  734. ULONG cwcALLHTTP;
  735. if ( webServer.GetCGIVariable( "ALL_HTTP",
  736. wcsALLHTTP,
  737. cwcALLHTTP ) )
  738. {
  739. WCHAR * wcsToken = wcsALLHTTP.Get();
  740. XArray<WCHAR> wcsCopyOfValue;
  741. while ( 0 != wcsToken )
  742. {
  743. WCHAR * wcsAttribute = wcsToken;
  744. wcsToken = wcschr( wcsToken, L'\n' );
  745. WCHAR * wcsValue = wcschr( wcsAttribute, L':' );
  746. if ( 0 != wcsValue )
  747. {
  748. *wcsValue++ = '\0';
  749. ULONG cwcValue;
  750. if (wcsToken)
  751. {
  752. if ( wcsValue > wcsToken )
  753. THROW( CException( E_INVALIDARG ) );
  754. cwcValue = (ULONG)(wcsToken - wcsValue);
  755. *wcsToken++ = '\0';
  756. }
  757. else
  758. {
  759. cwcValue = wcslen( wcsValue );
  760. }
  761. wcsCopyOfValue.Init(cwcValue+1);
  762. RtlCopyMemory( wcsCopyOfValue.Get(), wcsValue, (cwcValue+1) * sizeof(WCHAR) );
  763. PROPVARIANT Variant;
  764. Variant.vt = VT_LPWSTR;
  765. Variant.pwszVal = wcsCopyOfValue.Get();
  766. variableSet.SetVariable( wcsAttribute,
  767. &Variant,
  768. eParamOwnsVariantMemory );
  769. wcsCopyOfValue.Acquire();
  770. }
  771. }
  772. }
  773. }