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.

3152 lines
95 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: rowset.cxx
  7. //
  8. // Contents: OLE DB IRowset implementation for file stores.
  9. // Runs entirely in user space at the client machine.
  10. //
  11. // Classes: CRowset
  12. //
  13. // History: 07 Nov 94 AlanW Created
  14. // 07 May 97 KrishnaN Added Ole-DB error support
  15. //
  16. //--------------------------------------------------------------------------
  17. #include <pch.cxx>
  18. #pragma hdrstop
  19. #include <initguid.h> // needed for IServiceProperties
  20. #include <rowset.hxx>
  21. #include <query.hxx>
  22. #include <rownotfy.hxx>
  23. #include <tgrow.hxx>
  24. #include "tabledbg.hxx"
  25. const unsigned MAX_ROW_FETCH = 1000;
  26. inline DBROWSTATUS ScodeToRowstatus( SCODE sc )
  27. {
  28. switch (sc)
  29. {
  30. case S_OK:
  31. return DBROWSTATUS_S_OK;
  32. case E_INVALIDARG:
  33. case DB_E_BADBOOKMARK:
  34. return DBROWSTATUS_E_INVALID;
  35. case E_OUTOFMEMORY:
  36. return DBROWSTATUS_E_OUTOFMEMORY;
  37. default:
  38. tbDebugOut(( DEB_ERROR, "ScodeToRowStatus: missing conversion for %x\n", sc ));
  39. Win4Assert( FAILED( sc ) );
  40. return DBROWSTATUS_E_INVALID;
  41. }
  42. }
  43. // Rowset object Interfaces that support Ole DB error objects
  44. static const IID * apRowsetErrorIFs[] =
  45. {
  46. &IID_IAccessor,
  47. &IID_IChapteredRowset,
  48. &IID_IColumnsInfo,
  49. &IID_IColumnsRowset,
  50. &IID_IConnectionPointContainer,
  51. &IID_IConvertType,
  52. &IID_IDBAsynchStatus,
  53. &IID_IRowset,
  54. //&IID_IRowsetAsynch,
  55. &IID_IRowsetIdentity,
  56. &IID_IRowsetInfo,
  57. &IID_IRowsetLocate,
  58. &IID_IRowsetQueryStatus,
  59. //&IID_IRowsetResynch,
  60. &IID_IRowsetScroll,
  61. //&IID_IRowsetUpdate,
  62. &IID_IRowsetWatchAll,
  63. &IID_IRowsetWatchRegion,
  64. //&IID_ISupportErrorInfo,
  65. &IID_IServiceProperties,
  66. };
  67. static const ULONG cRowsetErrorIFs = sizeof(apRowsetErrorIFs)/sizeof(apRowsetErrorIFs[0]);
  68. //+---------------------------------------------------------------------------
  69. //
  70. // Member: CRowset::CRowset, public
  71. //
  72. // Synopsis: Creates a locally accessible Table
  73. //
  74. // Arguments: [pUnkOuter] - Outer unknown
  75. // [ppMyUnk] - OUT: filled in with pointer to non-delegated
  76. // IUnknown on return
  77. // [cols] - A reference to the output column set
  78. // [pidmap] - a pid mapper for column IDs and names in cols
  79. // [rQuery] - A reference to an instantiated query
  80. // [rControllingQuery] - OLE controlling unknown (IQuery)
  81. // [fIsCategorized] - TRUE if not the highest-level rowset
  82. // [xProps] - Rowset properties, indicates special semantics,
  83. // such as sequential cursor, use CI for prop
  84. // queries.
  85. // [hCursor] - table cursor handle.
  86. // [aAccessors] -- Bag of accessors which rowsets need to inherit
  87. //
  88. // Notes: Ownership of the output column set may be transferred to
  89. // the table cursor.
  90. //
  91. //----------------------------------------------------------------------------
  92. CRowset::CRowset(
  93. IUnknown * pUnkOuter,
  94. IUnknown ** ppMyUnk,
  95. CColumnSet const & cols,
  96. CPidMapperWithNames const & pidmap,
  97. PQuery & rQuery,
  98. IUnknown & rControllingQuery,
  99. BOOL fIsCategorized,
  100. XPtr<CMRowsetProps> & xProps,
  101. ULONG hCursor,
  102. CAccessorBag & aAccessors,
  103. IUnknown * pUnkCreator )
  104. :_rQuery( rQuery ),
  105. _xProperties( xProps.Acquire() ),
  106. _hCursor( hCursor ),
  107. _pRowBufs(0),
  108. _pConnectionPointContainer( 0 ),
  109. _pRowsetNotification( 0 ),
  110. _pAsynchNotification( 0 ),
  111. _fForwardOnly( (_xProperties->GetPropertyFlags() & eLocatable) == 0),
  112. #pragma warning(disable : 4355) // 'this' in a constructor
  113. _ColumnsInfo( cols,
  114. pidmap,
  115. _DBErrorObj,
  116. * ((IUnknown *) (IRowsetScroll *) this),
  117. _fForwardOnly ),
  118. _aAccessors( (IUnknown *) (IRowset *)this ),
  119. _DBErrorObj( * ((IUnknown *) (IRowset *) this), _mutex ),
  120. _impIUnknown(rControllingQuery, this),
  121. #pragma warning(default : 4355) // 'this' in a constructor
  122. _PropInfo(),
  123. _fIsCategorized( fIsCategorized ),
  124. _fExtendedTypes( (_xProperties->GetPropertyFlags() & eExtendedTypes) != 0 ),
  125. _fHoldRows( (_xProperties->GetPropertyFlags() & eHoldRows) != 0 ),
  126. _fAsynchronous( (_xProperties->GetPropertyFlags() & eAsynchronous) != 0),
  127. _pRelatedRowset( 0 ),
  128. _pChapterRowbufs( 0 )
  129. {
  130. Win4Assert(_hCursor != 0);
  131. if (_hCursor == 0)
  132. THROW(CException(E_NOINTERFACE));
  133. if (pUnkOuter)
  134. _pControllingUnknown = pUnkOuter;
  135. else
  136. _pControllingUnknown = (IUnknown * )&_impIUnknown;
  137. _DBErrorObj.SetInterfaceArray(cRowsetErrorIFs, apRowsetErrorIFs);
  138. ULONG obRowRefcount, obRowWorkId;
  139. ULONG obChaptRefcount, obChaptId;
  140. _ColumnsInfo.SetColumnBindings( rQuery, _hCursor,
  141. obRowRefcount, obRowWorkId,
  142. obChaptRefcount, obChaptId );
  143. //
  144. // GetBindings for each accessor in bag, and use them to create accessor
  145. // in IRowset
  146. //
  147. // only CAccessors can be used by commands
  148. CAccessorBase * pAccBase = (CAccessorBase *)aAccessors.First();
  149. while ( 0 != pAccBase )
  150. {
  151. DBCOUNTITEM cBindings;
  152. DBBINDING * rgBindings;
  153. DBACCESSORFLAGS dwAccessorFlags;
  154. SCODE sc = pAccBase->GetBindings( &dwAccessorFlags, &cBindings, &rgBindings);
  155. if ( FAILED( sc ) )
  156. THROW( CException( sc ) );
  157. HACCESSOR hAccessor;
  158. sc = CreateAccessor(dwAccessorFlags, cBindings, rgBindings, 0, &hAccessor, 0);
  159. CoTaskMemFree(rgBindings); //cleanup from GetBindings
  160. if (FAILED(sc))
  161. THROW( CException( sc ) );
  162. //
  163. // inherited accessors are accessed through same hAccessor as original.
  164. // Set parent of newly created accessor so that we can link the 2 copies.
  165. // Client never knows the direct HACESSOR for the inherited accessor.
  166. // All accessor methods check bag for an accessor with a match on
  167. // the parent or the creator.
  168. //
  169. ((CAccessorBase *)hAccessor)->SetParent(pAccBase);
  170. //
  171. // Increment inheritor count for parent accessor
  172. //
  173. pAccBase->IncInheritors();
  174. pAccBase = (CAccessor *)aAccessors.Next();
  175. }
  176. _pRowBufs = new CRowBufferSet( _fForwardOnly,
  177. obRowRefcount,
  178. obRowWorkId,
  179. obChaptRefcount,
  180. obChaptId );
  181. *ppMyUnk = ((IUnknown *)&_impIUnknown);
  182. // can't fail after this or _pRowBufs will leak
  183. (*ppMyUnk)->AddRef();
  184. rQuery.AddRef();
  185. if ( 0 != pUnkCreator )
  186. {
  187. _xUnkCreator.Set( pUnkCreator );
  188. _xUnkCreator->AddRef();
  189. }
  190. } //CRowset
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Member: CRowset::~CRowset, public
  194. //
  195. // Synopsis: Destroy the rowset and its component objects
  196. //
  197. //----------------------------------------------------------------------------
  198. CRowset::~CRowset()
  199. {
  200. Win4Assert( _impIUnknown._ref == 0 );
  201. Win4Assert( _hCursor != 0 );
  202. delete _pRowBufs;
  203. // free cursor will fail if the pipe is broken
  204. TRY
  205. {
  206. if ( !_pRowsetNotification.IsNull() )
  207. _pRowsetNotification->OnRowsetChange( this,
  208. DBREASON_ROWSET_RELEASE,
  209. DBEVENTPHASE_DIDEVENT,
  210. TRUE);
  211. _rQuery.FreeCursor( _hCursor );
  212. }
  213. CATCH( CException, e )
  214. {
  215. }
  216. END_CATCH;
  217. if ( !_pRowsetNotification.IsNull() )
  218. _pRowsetNotification->StopNotifications();
  219. delete _pConnectionPointContainer;
  220. _rQuery.Release();
  221. } //~CRowset
  222. //+-------------------------------------------------------------------------
  223. //
  224. // Member: CRowset::RealQueryInterface, public
  225. //
  226. // Synopsis: Get a reference to another interface on the cursor
  227. //
  228. // Notes: ref count is incremented inside QueryInterface
  229. //
  230. //--------------------------------------------------------------------------
  231. SCODE CRowset::RealQueryInterface(
  232. REFIID ifid,
  233. void * *ppiuk )
  234. {
  235. SCODE sc = S_OK;
  236. *ppiuk = 0;
  237. // note -- IID_IUnknown covered in QueryInterface
  238. if ( IID_IRowset == ifid )
  239. {
  240. *ppiuk = (void *) (IRowset *) this;
  241. }
  242. else if ( IID_IAccessor == ifid )
  243. {
  244. *ppiuk = (void *) (IAccessor *) this;
  245. }
  246. else if ( IID_IRowsetInfo == ifid )
  247. {
  248. *ppiuk = (void *) (IRowsetInfo *) this;
  249. }
  250. else if ( IID_IColumnsInfo == ifid )
  251. {
  252. *ppiuk = (void *) (IColumnsInfo *) &_ColumnsInfo;
  253. }
  254. else if (IID_ISupportErrorInfo == ifid)
  255. {
  256. *ppiuk = (void *) ((IUnknown *) (ISupportErrorInfo *) &_DBErrorObj);
  257. }
  258. else if ( IID_IConvertType == ifid )
  259. {
  260. *ppiuk = (void *) (IConvertType *) this;
  261. }
  262. #if 0 // NEWFEATURE - not implemented now.
  263. else if ( IID_IColumnsRowset == ifid )
  264. {
  265. *ppiuk = (void *) (IColumnsRowset *) &_ColumnsInfo;
  266. }
  267. #endif // 0 // NEWFEATURE - not implemented now.
  268. else if ( IID_IRowsetQueryStatus == ifid )
  269. {
  270. *ppiuk = (void *) (IRowsetQueryStatus *) this;
  271. }
  272. else if ( IID_IServiceProperties == ifid )
  273. {
  274. *ppiuk = (void *) (IServiceProperties *) this;
  275. }
  276. else if ( IID_IConnectionPointContainer == ifid )
  277. {
  278. // Watch notifications are only supported over the
  279. // bottom-most of a hierarchical rowset (the one with real rows)
  280. BOOL fWatchable = ! _pRowBufs->IsChaptered() &&
  281. (_xProperties->GetPropertyFlags() & eWatchable) != 0;
  282. if ( 0 == _pConnectionPointContainer )
  283. {
  284. TRY
  285. {
  286. XPtr<CConnectionPointContainer> xCPC(
  287. new CConnectionPointContainer(
  288. _fAsynchronous ? 3 : 1,
  289. * ((IUnknown *) (IRowsetScroll *) this),
  290. _DBErrorObj) );
  291. if (_fAsynchronous)
  292. {
  293. _pAsynchNotification =
  294. new CRowsetAsynchNotification(
  295. _rQuery, _hCursor, this, _DBErrorObj,
  296. fWatchable );
  297. _pRowsetNotification.Set( _pAsynchNotification );
  298. }
  299. else
  300. {
  301. _pRowsetNotification.Set ( new CRowsetNotification( ) );
  302. }
  303. _pRowsetNotification->AddConnectionPoints( xCPC.GetPointer() );
  304. _pConnectionPointContainer = xCPC.Acquire();
  305. }
  306. CATCH( CException, e )
  307. {
  308. sc = GetOleError( e );
  309. }
  310. END_CATCH;
  311. }
  312. if ( S_OK == sc )
  313. {
  314. Win4Assert( 0 != _pConnectionPointContainer );
  315. *ppiuk = (void *) (IConnectionPointContainer *)
  316. _pConnectionPointContainer;
  317. }
  318. }
  319. else if (! _fForwardOnly)
  320. {
  321. if ( IID_IRowsetScroll == ifid )
  322. {
  323. *ppiuk = (void *) (IRowsetScroll *) this;
  324. }
  325. else if ( IID_IRowsetExactScroll == ifid )
  326. {
  327. *ppiuk = (void *) (IRowsetExactScroll *) this;
  328. }
  329. else if ( IID_IRowsetLocate == ifid )
  330. {
  331. *ppiuk = (void *) (IRowsetLocate *) this;
  332. }
  333. else if ( IID_IRowsetIdentity == ifid )
  334. {
  335. *ppiuk = (void *) (IRowsetIdentity *) this;
  336. }
  337. else if ( IID_IChapteredRowset == ifid )
  338. {
  339. Win4Assert( (_pChapterRowbufs != 0) == _fIsCategorized );
  340. if (_pChapterRowbufs)
  341. {
  342. *ppiuk = (void *) (IChapteredRowset *) this;
  343. }
  344. }
  345. else if ( _fAsynchronous )
  346. {
  347. if ( IID_IDBAsynchStatus == ifid )
  348. {
  349. *ppiuk = (void *) (IDBAsynchStatus *) this;
  350. }
  351. else if ( IID_IRowsetAsynch == ifid )
  352. {
  353. *ppiuk = (void *) (IRowsetAsynch *) this;
  354. }
  355. else if (IID_IRowsetWatchRegion == ifid)
  356. {
  357. *ppiuk = (void *) (IRowsetWatchRegion *) this;
  358. }
  359. else if (IID_IRowsetWatchAll == ifid)
  360. {
  361. *ppiuk = (void *) (IRowsetWatchAll *) this;
  362. }
  363. }
  364. }
  365. if ( 0 == *ppiuk )
  366. {
  367. sc = E_NOINTERFACE;
  368. }
  369. return sc;
  370. }
  371. //+-------------------------------------------------------------------------
  372. //
  373. // Member: CRowset::CImpIUnknown::AddRef, public
  374. //
  375. // Synopsis: Reference the cursor.
  376. //
  377. //--------------------------------------------------------------------------
  378. STDMETHODIMP_(ULONG) CRowset::CImpIUnknown::AddRef(void)
  379. {
  380. long ref = InterlockedIncrement( &_ref );
  381. if ( ref > 0 )
  382. _rControllingQuery.AddRef();
  383. return ref ;
  384. } //AddRef
  385. //+-------------------------------------------------------------------------
  386. //
  387. // Member: CRowset::CImpIUnknown::Release, public
  388. //
  389. // Synopsis: De-Reference the cursor.
  390. //
  391. // Effects: If the ref count goes to 0 then the cursor is deleted.
  392. //
  393. //--------------------------------------------------------------------------
  394. STDMETHODIMP_(ULONG) CRowset::CImpIUnknown::Release(void)
  395. {
  396. long ref = InterlockedDecrement( &_ref );
  397. if ( ref >= 0 )
  398. _rControllingQuery.Release(); // may cause a delete of the rowset
  399. return ref;
  400. } //Release
  401. //+---------------------------------------------------------------------------
  402. //
  403. // Member: CRowset::GetProperties, public
  404. //
  405. // Synopsis: Return information about the capabilities of the rowset
  406. //
  407. // Arguments: [cPropertyIDSets] - number of property ID sets or zero
  408. // [rgPropertyIDSets] - array of desired property ID sets or NULL
  409. // [pcPropertySets] - number of DBPROPSET structures returned
  410. // [prgPropertySets] - array of returned DBPROPSET structures
  411. //
  412. //
  413. // Returns: SCODE
  414. //
  415. // Notes:
  416. //
  417. //----------------------------------------------------------------------------
  418. STDMETHODIMP CRowset::GetProperties(
  419. const ULONG cPropertyIDSets,
  420. const DBPROPIDSET rgPropertyIDSets[],
  421. ULONG * pcPropertySets,
  422. DBPROPSET ** prgPropertySets)
  423. {
  424. _DBErrorObj.ClearErrorInfo();
  425. if ( (0 != cPropertyIDSets && 0 == rgPropertyIDSets) ||
  426. 0 == pcPropertySets ||
  427. 0 == prgPropertySets )
  428. {
  429. if (pcPropertySets)
  430. *pcPropertySets = 0;
  431. if (prgPropertySets)
  432. *prgPropertySets = 0;
  433. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetInfo);
  434. }
  435. SCODE scResult = S_OK;
  436. *pcPropertySets = 0;
  437. *prgPropertySets = 0;
  438. TRY
  439. {
  440. //
  441. // Update ROWSETQUERYSTATUS property
  442. //
  443. DWORD dwStatus;
  444. _rQuery.GetQueryStatus( _hCursor, dwStatus );
  445. _xProperties->SetValLong( CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT,
  446. CMRowsetProps::eid_MSIDXSPROPVAL_ROWSETQUERYSTATUS,
  447. dwStatus );
  448. scResult = _xProperties->GetProperties( cPropertyIDSets,
  449. rgPropertyIDSets,
  450. pcPropertySets,
  451. prgPropertySets );
  452. if (FAILED(scResult))
  453. _DBErrorObj.PostHResult(scResult, IID_IRowsetInfo);
  454. }
  455. CATCH( CException, e )
  456. {
  457. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetInfo);
  458. scResult = GetOleError(e);
  459. }
  460. END_CATCH;
  461. return scResult;
  462. }
  463. //+---------------------------------------------------------------------------
  464. //
  465. // Member: CRowset::RatioFinished, public
  466. //
  467. // Synopsis: Returns the completion status of the query.
  468. //
  469. // Arguments: [pulDenominator] - on return, denominator of fraction
  470. // [pulNumerator] - on return, numerator of fraction
  471. // [pcRows] - on return, number of rows
  472. // [pfNewRows] - on return, TRUE if new rows in the table
  473. //
  474. //----------------------------------------------------------------------------
  475. STDMETHODIMP CRowset::RatioFinished(
  476. DBCOUNTITEM * pulDenominator,
  477. DBCOUNTITEM * pulNumerator,
  478. DBCOUNTITEM * pcRows,
  479. BOOL * pfNewRows) /*const*/
  480. {
  481. _DBErrorObj.ClearErrorInfo();
  482. SCODE scResult = S_OK;
  483. if (0 == pulDenominator ||
  484. 0 == pulNumerator ||
  485. 0 == pcRows ||
  486. 0 == pfNewRows)
  487. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetAsynch);
  488. TRY
  489. {
  490. *pcRows = 0;
  491. _rQuery.RatioFinished( _hCursor,
  492. *pulDenominator,
  493. *pulNumerator,
  494. *pcRows,
  495. *pfNewRows );
  496. #if CIDBG
  497. if ( _fForwardOnly )
  498. Win4Assert( *pulDenominator == *pulNumerator );
  499. else
  500. Win4Assert( *pulDenominator >= *pulNumerator );
  501. #endif // CIDBG
  502. }
  503. CATCH( CException, e )
  504. {
  505. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetAsynch);
  506. scResult = GetOleError(e);
  507. }
  508. END_CATCH;
  509. return scResult;
  510. }
  511. //+---------------------------------------------------------------------------
  512. //
  513. // Member: CRowset::AddRefRows, public
  514. //
  515. // Synopsis: Increment the ref. count of a set of row handles
  516. //
  517. // Arguments: [cRows] -- Number of row handles in rghRows
  518. // [rghRows] -- Array of HROWs to be ref. counted
  519. // [rgRefCounts] -- Remaining reference counts on rows (optional)
  520. // [rgRowStatus] -- Status for each row (optional)
  521. //
  522. // Returns: SCODE, DB_E_BADROWHANDLE if a bad row handle is passed in.
  523. //
  524. // Notes:
  525. //
  526. //--------------------------------------------------------------------------
  527. STDMETHODIMP CRowset::AddRefRows(
  528. DBCOUNTITEM cRows,
  529. const HROW rghRows [],
  530. DBREFCOUNT rgRefCounts[],
  531. DBROWSTATUS rgRowStatus[])
  532. {
  533. _DBErrorObj.ClearErrorInfo();
  534. if (0 == _pRowBufs)
  535. return _DBErrorObj.PostHResult(E_FAIL, IID_IRowset);
  536. SCODE scResult = S_OK;
  537. TRY
  538. {
  539. _pRowBufs->AddRefRows(cRows, rghRows, rgRefCounts, rgRowStatus);
  540. }
  541. CATCH( CException, e )
  542. {
  543. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset);
  544. scResult = GetOleError(e);
  545. }
  546. END_CATCH;
  547. return scResult;
  548. }
  549. //+---------------------------------------------------------------------------
  550. //
  551. // Member: CRowset::ReleaseRows, public
  552. //
  553. // Synopsis: Release a set of row handles
  554. //
  555. // Arguments: [cRows] -- Number of row handles in rghRows
  556. // [rghRows] -- Array of HROWs to be released
  557. // [rgRowOptions] -- Reserved for future use (optional)
  558. // [rgRefCounts] -- Remaining reference counts on rows (optional)
  559. // [rgRowStatus] -- Status for each row (optional)
  560. //
  561. // Returns: SCODE, DB_E_BADROWHANDLE if a bad row handle is passed in.
  562. //
  563. // Notes:
  564. //
  565. //--------------------------------------------------------------------------
  566. STDMETHODIMP CRowset::ReleaseRows(
  567. DBCOUNTITEM cRows,
  568. const HROW rghRows [],
  569. DBROWOPTIONS rgRowOptions[],
  570. DBREFCOUNT rgRefCounts[],
  571. DBROWSTATUS rgRowStatus[])
  572. {
  573. _DBErrorObj.ClearErrorInfo();
  574. if (0 == _pRowBufs)
  575. return _DBErrorObj.PostHResult(E_FAIL, IID_IRowset);
  576. // if (0 != rgRowOptions)
  577. // return E_FAIL;
  578. SCODE scResult = S_OK;
  579. TRY
  580. {
  581. BOOL fNotify = FALSE;
  582. ULONG * pRefCounts = rgRefCounts;
  583. DBROWSTATUS * pRowStatus = rgRowStatus;
  584. XArray<ULONG> xrgRefCounts;
  585. XArray<DBROWSTATUS> xrgRowStatus;
  586. if ( !_pRowsetNotification.IsNull() &&
  587. _pRowsetNotification->IsNotifyActive() )
  588. {
  589. fNotify = TRUE;
  590. if ( 0 == pRefCounts )
  591. {
  592. xrgRefCounts.Init( (unsigned) cRows);
  593. pRefCounts = xrgRefCounts.GetPointer();
  594. }
  595. if ( 0 == pRowStatus )
  596. {
  597. xrgRowStatus.Init( (unsigned) cRows);
  598. pRowStatus = xrgRowStatus.GetPointer();
  599. }
  600. }
  601. scResult = _pRowBufs->ReleaseRows(cRows, rghRows, pRefCounts, pRowStatus);
  602. if ( fNotify )
  603. {
  604. ULONG cRowsToNotify = 0;
  605. for (ULONG i=0; i<cRows; i++)
  606. if ( 0 == pRefCounts[i] && DBROWSTATUS_S_OK == pRowStatus[i] )
  607. cRowsToNotify++;
  608. if (cRowsToNotify)
  609. {
  610. XGrowable<HROW,20> xrghRows(cRowsToNotify);
  611. for (cRowsToNotify=0, i=0; i<cRows; i++)
  612. if ( 0 == pRefCounts[i] && DBROWSTATUS_S_OK == pRowStatus[i] )
  613. {
  614. xrghRows[cRowsToNotify] = rghRows[i];
  615. cRowsToNotify++;
  616. }
  617. _pRowsetNotification->OnRowChange( this,
  618. cRowsToNotify,
  619. xrghRows.Get(),
  620. DBREASON_ROW_RELEASE,
  621. DBEVENTPHASE_DIDEVENT,
  622. TRUE);
  623. }
  624. }
  625. }
  626. CATCH( CException, e )
  627. {
  628. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset);
  629. scResult = GetOleError(e);
  630. }
  631. END_CATCH;
  632. return scResult;
  633. }
  634. //+---------------------------------------------------------------------------
  635. //
  636. // Macro: CheckCrowsArgs
  637. //
  638. // Synopsis: Check common error conditions on cRows and pcRowsObtained
  639. // for GetRowsXxxx methods.
  640. //
  641. // Arguments: [cRows] -- Number of rows to return
  642. // [pcRowsObtained] -- On return, number of rows actually
  643. // fetched
  644. //
  645. // Returns: SCODE
  646. //
  647. // Notes: Needs to be a macro instead of an inline function because
  648. // it returns from the calling method.
  649. //
  650. //--------------------------------------------------------------------------
  651. #define CheckCrowsArgs(cRows, pcRowsObtained) \
  652. if (0 == pcRowsObtained) \
  653. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowset); \
  654. *pcRowsObtained = 0; \
  655. if (cRows == 0) \
  656. return S_OK;
  657. //+---------------------------------------------------------------------------
  658. //
  659. // Member: CRowset::GetRowsAt, public
  660. //
  661. // Synopsis: Fetch data starting at some starting bookmark
  662. //
  663. // Arguments: [hRegion] -- handle to watch region
  664. // [hChapter] -- Chapter in a multiset cursor
  665. // [cbBookmark] -- Size of bookmark for starting position
  666. // [pBookmark] -- Pointer to bookmark for starting position
  667. // [lRowsOffset] -- Number of row handles in rghRows
  668. // [cRows] -- Number of rows to return
  669. // [pcRowsObtained] -- On return, number of rows actually
  670. // fetched
  671. // [prghRows] -- Array of HROWs to be returned
  672. //
  673. // Returns: SCODE, E_INVALIDARG for bad parameters, DB_E_BADBOOKMARK
  674. // if the starting bookmark is invalid
  675. //
  676. // Notes:
  677. //
  678. //--------------------------------------------------------------------------
  679. STDMETHODIMP CRowset::GetRowsAt(
  680. HWATCHREGION hRegion,
  681. HCHAPTER hChapter,
  682. DBBKMARK cbBookmark,
  683. const BYTE* pBookmark,
  684. DBROWOFFSET lRowsOffset,
  685. DBROWCOUNT cRows,
  686. DBCOUNTITEM * pcRowsObtained,
  687. HROW * * prghRows
  688. ) {
  689. _DBErrorObj.ClearErrorInfo();
  690. SCODE scResult = S_OK;
  691. CheckCrowsArgs( cRows, pcRowsObtained );
  692. TRY
  693. {
  694. CI_TBL_BMK bmk = _MapBookmark(cbBookmark, pBookmark);
  695. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  696. CRowSeekAt rowSeek( hRegion, chapt, (LONG) lRowsOffset, bmk );
  697. scResult = _FetchRows(rowSeek, cRows, pcRowsObtained, prghRows);
  698. if (FAILED(scResult))
  699. _DBErrorObj.PostHResult(scResult, IID_IRowsetLocate);
  700. else if ( !_pRowsetNotification.IsNull() &&
  701. *pcRowsObtained != 0 &&
  702. _pRowsetNotification->IsNotifyActive() )
  703. {
  704. _pRowsetNotification->OnRowChange( this,
  705. *pcRowsObtained,
  706. *prghRows,
  707. DBREASON_ROW_ACTIVATE,
  708. DBEVENTPHASE_DIDEVENT,
  709. TRUE);
  710. }
  711. }
  712. CATCH( CException, e )
  713. {
  714. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate);
  715. scResult = GetOleError(e);
  716. }
  717. END_CATCH;
  718. return scResult;
  719. }
  720. //+---------------------------------------------------------------------------
  721. //
  722. // Member: CRowset::GetRowsByBookmark, public
  723. //
  724. // Synopsis: Fetch data from a set of bookmarks
  725. //
  726. // Arguments: [hChapter] -- Chapter in a multiset cursor
  727. // [cRows] -- Number of input bookmarks and rows to return
  728. // [rgcbBookmark] -- Array of bookmark sizes
  729. // [ppBookmarks] -- Array of pointers to bookmarks
  730. // [rghRows] -- Array of HROWs returned
  731. // [rgRowStatus] -- Array for per-row status (optional)
  732. //
  733. // Returns: SCODE, E_INVALIDARG for bad parameters, DB_E_BADBOOKMARK
  734. // if the starting bookmark is invalid
  735. //
  736. // Notes:
  737. //
  738. //--------------------------------------------------------------------------
  739. STDMETHODIMP CRowset::GetRowsByBookmark(
  740. HCHAPTER hChapter,
  741. DBCOUNTITEM cRows,
  742. const DBBKMARK rgcbBookmark[],
  743. const BYTE * ppBookmarks[],
  744. HROW rghRows[],
  745. DBROWSTATUS rgRowStatus[]
  746. ) {
  747. _DBErrorObj.ClearErrorInfo();
  748. SCODE scResult = S_OK;
  749. if (0 == ppBookmarks ||
  750. 0 == rgcbBookmark ||
  751. 0 == rghRows)
  752. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetLocate);
  753. if (cRows == 0)
  754. return scResult;
  755. TRY
  756. {
  757. //
  758. // Map the input bookmarks to work IDs. If we see an invalid
  759. // bookmark, it will get turned into widInvalid, and its lookup
  760. // will fail.
  761. //
  762. XArray<CI_TBL_BMK> paBmk( (unsigned) cRows );
  763. for (unsigned i=0; i < cRows; i++)
  764. {
  765. DBROWSTATUS sc = _MapBookmarkNoThrow( rgcbBookmark[i],
  766. ppBookmarks[i],
  767. paBmk[i] );
  768. }
  769. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  770. CRowSeekByBookmark rowSeek( chapt, (ULONG) cRows, paBmk.Acquire() );
  771. DBCOUNTITEM cRowsObtained;
  772. TRY
  773. {
  774. scResult = _FetchRows(rowSeek, cRows, &cRowsObtained, &rghRows);
  775. }
  776. CATCH( CException, e )
  777. {
  778. scResult = e.GetErrorCode();
  779. }
  780. END_CATCH
  781. //
  782. // Return the array of row statuses
  783. //
  784. unsigned cErrors = 0;
  785. for (i=0; i < rowSeek.GetValidStatuses(); i++)
  786. {
  787. SCODE scTemp = rowSeek.GetStatus(i);
  788. if (0 != rgRowStatus)
  789. rgRowStatus[i] = ScodeToRowstatus( scTemp );
  790. if (S_OK != scTemp)
  791. {
  792. //
  793. // The HROW array returned by _FetchRows is compressed,
  794. // skipping entries for rows that had errors. Insert
  795. // a DB_NULL_HROW entry for this row.
  796. //
  797. if ( i != cRows-1 )
  798. {
  799. memmove( &rghRows[i+1], &rghRows[i], (unsigned) ((cRows-i)-1) * sizeof (HROW));
  800. }
  801. rghRows[i] = DB_NULL_HROW;
  802. //
  803. // If the returned error is DB_E_BADBOOKMARK,
  804. // call MapBookmarkNoThrow again to distinguish
  805. // E_INVALIDARG cases.
  806. //
  807. if (DB_E_BADBOOKMARK == scTemp && 0 != rgRowStatus)
  808. {
  809. CI_TBL_BMK bmkTemp;
  810. DBROWSTATUS rsTemp = _MapBookmarkNoThrow(rgcbBookmark[i],
  811. ppBookmarks[i],
  812. bmkTemp);
  813. if (rsTemp != DBROWSTATUS_S_OK)
  814. {
  815. rgRowStatus[i] = rsTemp;
  816. }
  817. }
  818. cErrors++;
  819. }
  820. }
  821. Win4Assert( rowSeek.GetValidStatuses() == cRows );
  822. if (SUCCEEDED(scResult) && cErrors > 0)
  823. scResult = (cErrors == cRows) ? DB_E_ERRORSOCCURRED :
  824. DB_S_ERRORSOCCURRED;
  825. if (FAILED(scResult))
  826. _DBErrorObj.PostHResult(scResult, IID_IRowsetLocate);
  827. else if ( !_pRowsetNotification.IsNull() &&
  828. _pRowsetNotification->IsNotifyActive() )
  829. _pRowsetNotification->OnRowChange( this,
  830. cRows,
  831. rghRows,
  832. DBREASON_ROW_ACTIVATE,
  833. DBEVENTPHASE_DIDEVENT,
  834. TRUE);
  835. }
  836. CATCH( CException, e )
  837. {
  838. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate);
  839. scResult = GetOleError(e);
  840. Win4Assert(FAILED(scResult));
  841. }
  842. END_CATCH;
  843. return scResult;
  844. }
  845. //+---------------------------------------------------------------------------
  846. //
  847. // Member: CRowset::Compare, public
  848. //
  849. // Synopsis: Compare two bookmarks
  850. //
  851. // Arguments: [hChapter] -- chapter
  852. // [cbBookmark1] -- Size of first bookmark
  853. // [pBookmark1] -- Pointer to first bookmark
  854. // [cbBookmark2] -- Size of second bookmark
  855. // [pBookmark2] -- Pointer to second bookmark
  856. // [pdwComparison] - on return, hased value of bookmark
  857. //
  858. // Returns: SCODE, E_INVALIDARG if cbBookmark is zero or if pBookmark or
  859. // pdwComparison is NULL, DB_E_BADBOOKMARK for other invalid
  860. // bookmarks.
  861. //
  862. // Notes:
  863. //
  864. //--------------------------------------------------------------------------
  865. STDMETHODIMP CRowset::Compare(
  866. HCHAPTER hChapter,
  867. DBBKMARK cbBookmark1,
  868. const BYTE* pBookmark1,
  869. DBBKMARK cbBookmark2,
  870. const BYTE* pBookmark2,
  871. DBCOMPARE * pdwComparison) /*const*/
  872. {
  873. _DBErrorObj.ClearErrorInfo();
  874. SCODE sc = S_OK;
  875. if (0 == pdwComparison)
  876. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetLocate);
  877. TRY
  878. {
  879. ULONG dwHash1 = _MapBookmark(cbBookmark1, pBookmark1);
  880. ULONG dwHash2 = _MapBookmark(cbBookmark2, pBookmark2);
  881. //
  882. // Set to non-comparable. This is used later to see if we've
  883. // successfully determined the relative order.
  884. //
  885. *pdwComparison = DBCOMPARE_NOTCOMPARABLE;
  886. if (dwHash1 == dwHash2)
  887. {
  888. *pdwComparison = DBCOMPARE_EQ;
  889. }
  890. else if ( 1 == cbBookmark1 || 1 == cbBookmark2 )
  891. {
  892. *pdwComparison = DBCOMPARE_NE;
  893. }
  894. else
  895. {
  896. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  897. _rQuery.Compare( _hCursor,
  898. chapt,
  899. dwHash1,
  900. dwHash2,
  901. (DWORD) (*pdwComparison) );
  902. }
  903. }
  904. CATCH( CException, e )
  905. {
  906. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate);
  907. sc = GetOleError(e);
  908. }
  909. END_CATCH;
  910. return sc;
  911. }
  912. //+---------------------------------------------------------------------------
  913. //
  914. // Member: CRowset::_MapChapter, private
  915. //
  916. // Synopsis: Map a chapter mark to a ULONG internal chapter mark.
  917. //
  918. // Arguments: [hChapter] -- handle of chapter
  919. //
  920. // Returns: Chapter as an I4
  921. //
  922. // Notes: A null chapter on a categorized rowset means to operate
  923. // over the entire rowset, not an individual chapter.
  924. //
  925. //--------------------------------------------------------------------------
  926. CI_TBL_CHAPT CRowset::_MapChapter(
  927. HCHAPTER hChapter
  928. ) const
  929. {
  930. CI_TBL_CHAPT chapt = (CI_TBL_CHAPT) hChapter;
  931. Win4Assert (DB_NULL_HCHAPTER == 0);
  932. if ( !_fIsCategorized && DB_NULL_HCHAPTER != hChapter )
  933. {
  934. THROW( CException( DB_E_BADCHAPTER ));
  935. }
  936. return chapt;
  937. } //_MapChapter
  938. //+---------------------------------------------------------------------------
  939. //
  940. // Member: CRowset::_MapBookmarkNoThrow, private
  941. //
  942. // Synopsis: Return a 32 bit hash value for a particular bookmark.
  943. // Don't throw on errors.
  944. //
  945. // Arguments: [cbBookmark] -- Size of bookmark
  946. // [pBookmark] -- Pointer to bookmark
  947. //
  948. // Notes: For IRowsetLocate::Hash and IRowsetLocate::GetRowsByBookmark
  949. // which want to continue processing on bookmark errors. Unlike
  950. // _MapBookmark, DBBMK_FIRST and DBBMK_LAST are invalid.
  951. //
  952. // Returns: DBROWSTATUS, hash value (identity function, also the workid
  953. // value for the table) is returned in rBmk
  954. //
  955. //--------------------------------------------------------------------------
  956. DBROWSTATUS CRowset::_MapBookmarkNoThrow(
  957. DBBKMARK cbBookmark,
  958. const BYTE* pBookmark,
  959. CI_TBL_BMK & rBmk) const
  960. {
  961. Win4Assert( !_fForwardOnly );
  962. rBmk = widInvalid;
  963. if (0 == cbBookmark || 0 == pBookmark)
  964. return DBROWSTATUS_E_INVALID;
  965. if (cbBookmark == 1)
  966. {
  967. if (*(BYTE *)pBookmark == DBBMK_FIRST ||
  968. *(BYTE *)pBookmark == DBBMK_LAST ||
  969. *(BYTE *)pBookmark == DBBMK_INVALID)
  970. return DBROWSTATUS_E_INVALID;
  971. else
  972. return DBROWSTATUS_E_INVALID; //DB_E_BADBOOKMARK ???
  973. }
  974. else if (cbBookmark == sizeof (CI_TBL_BMK))
  975. {
  976. rBmk = *(UNALIGNED CI_TBL_BMK *) pBookmark;
  977. if (rBmk == WORKID_TBLFIRST || rBmk == WORKID_TBLLAST)
  978. return DBROWSTATUS_E_INVALID;
  979. return DBROWSTATUS_S_OK;
  980. }
  981. return DBROWSTATUS_E_INVALID; //DB_E_BADBOOKMARK ???
  982. } //_MapBookmarkNoThrow
  983. //+---------------------------------------------------------------------------
  984. //
  985. // Member: CRowset::_MapBookmark, private
  986. //
  987. // Synopsis: Convert a bookmark into an internal form.
  988. //
  989. // Arguments: [cbBookmark] -- Size of bookmark
  990. // [pBookmark] -- Pointer to bookmark
  991. //
  992. // Returns: ULONG, hash value (identity function, also the workid
  993. // value for the table)
  994. //
  995. //--------------------------------------------------------------------------
  996. CI_TBL_BMK CRowset::_MapBookmark(
  997. DBBKMARK cbBookmark,
  998. const BYTE* pBookmark) const
  999. {
  1000. Win4Assert( !_fForwardOnly );
  1001. WORKID WorkID = widInvalid;
  1002. Win4Assert( sizeof WORKID == sizeof CI_TBL_BMK );
  1003. if (0 == cbBookmark || 0 == pBookmark)
  1004. THROW(CException(E_INVALIDARG));
  1005. if (cbBookmark == 1)
  1006. {
  1007. if (*(BYTE *)pBookmark == DBBMK_FIRST)
  1008. WorkID = WORKID_TBLFIRST;
  1009. else if (*(BYTE *)pBookmark == DBBMK_LAST)
  1010. WorkID = WORKID_TBLLAST;
  1011. }
  1012. else if (cbBookmark == sizeof (CI_TBL_BMK))
  1013. {
  1014. WorkID = *(UNALIGNED CI_TBL_BMK *) pBookmark;
  1015. }
  1016. if (WorkID == widInvalid)
  1017. THROW(CException(DB_E_BADBOOKMARK));
  1018. return WorkID;
  1019. } //_MapBookmark
  1020. //+---------------------------------------------------------------------------
  1021. //
  1022. // Member: CRowset::Hash, public
  1023. //
  1024. // Synopsis: Returns an array of 32 bit hash values for bookmarks
  1025. //
  1026. // Arguments: [hChapter] -- chapter
  1027. // [cBookmarks] -- # of bmks to hash
  1028. // [rgcbBM] -- Sizes of each bookmark
  1029. // [ppBM] -- Pointers to each bookmark
  1030. // [rgHashedValues] -- on return, hashed values of bookmarks
  1031. // [rgBookmarkStatus] -- per-bookmark status (optional)
  1032. //
  1033. // Returns: SCODE, E_INVALIDARG if any cbBookmark is zero,
  1034. // DB_E_BADBOOKMARK for other invalid bookmarks.
  1035. //
  1036. //--------------------------------------------------------------------------
  1037. STDMETHODIMP CRowset::Hash(
  1038. HCHAPTER hChapter,
  1039. DBBKMARK cBookmarks,
  1040. const DBBKMARK rgcbBM[],
  1041. const BYTE * ppBM[],
  1042. DBHASHVALUE rgHashedValues[],
  1043. DBROWSTATUS rgBookmarkStatus[]
  1044. )
  1045. {
  1046. _DBErrorObj.ClearErrorInfo();
  1047. SCODE scResult = S_OK;
  1048. ULONG cErrors = 0;
  1049. if (0 == rgcbBM || 0 == ppBM || 0 == rgHashedValues)
  1050. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetLocate);
  1051. TRY
  1052. {
  1053. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  1054. for (ULONG i = 0; i < cBookmarks; i++)
  1055. {
  1056. CI_TBL_BMK bmk;
  1057. DBROWSTATUS rs = _MapBookmarkNoThrow( rgcbBM[i], ppBM[i], bmk );
  1058. rgHashedValues[i] = bmk;
  1059. if (rs != DBROWSTATUS_S_OK)
  1060. {
  1061. rgHashedValues[i] = 0;
  1062. cErrors++;
  1063. }
  1064. if (0 != rgBookmarkStatus)
  1065. rgBookmarkStatus[i] = rs;
  1066. }
  1067. if (cErrors)
  1068. scResult = (cErrors == cBookmarks) ? DB_E_ERRORSOCCURRED :
  1069. DB_S_ERRORSOCCURRED;
  1070. if (FAILED(scResult))
  1071. _DBErrorObj.PostHResult(scResult, IID_IRowsetLocate);
  1072. }
  1073. CATCH( CException, e )
  1074. {
  1075. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate);
  1076. scResult = GetOleError(e);
  1077. }
  1078. END_CATCH;
  1079. return scResult;
  1080. } //Hash
  1081. //+---------------------------------------------------------------------------
  1082. //
  1083. // Member: CRowset::GetApproximatePosition, public
  1084. //
  1085. // Synopsis: Returns the approximate position of a bookmark
  1086. //
  1087. // Arguments: [hChapter] -- chapter
  1088. // [cbBookmark] -- size of bookmark
  1089. // [pBookmark] -- bookmark
  1090. // [pulPosition] -- return approx row number of bookmark
  1091. // [pulRows] -- returns approx # of rows in cursor or
  1092. // 1 + approx rows if not at quiescence
  1093. //
  1094. // Returns: SCODE - the status of the operation.
  1095. //
  1096. //--------------------------------------------------------------------------
  1097. STDMETHODIMP CRowset::GetApproximatePosition(
  1098. HCHAPTER hChapter,
  1099. DBBKMARK cbBookmark,
  1100. const BYTE * pBookmark,
  1101. DBCOUNTITEM * pulPosition,
  1102. DBCOUNTITEM * pulRows) /*const*/
  1103. {
  1104. _DBErrorObj.ClearErrorInfo();
  1105. Win4Assert( !_fForwardOnly );
  1106. SCODE sc = S_OK;
  1107. TRY
  1108. {
  1109. DBCOUNTITEM ulNumerator, ulDenominator;
  1110. CI_TBL_BMK bmk = WORKID_TBLFIRST;
  1111. if (cbBookmark != 0)
  1112. bmk = _MapBookmark(cbBookmark, pBookmark);
  1113. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  1114. _rQuery.GetApproximatePosition( _hCursor,
  1115. chapt,
  1116. bmk,
  1117. &ulNumerator,
  1118. &ulDenominator );
  1119. if (cbBookmark)
  1120. *pulPosition = ulNumerator;
  1121. if (pulRows)
  1122. *pulRows = ulDenominator;
  1123. }
  1124. CATCH( CException, e )
  1125. {
  1126. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetScroll);
  1127. sc = GetOleError(e);
  1128. }
  1129. END_CATCH;
  1130. return sc;
  1131. }
  1132. //+---------------------------------------------------------------------------
  1133. //
  1134. // Member: CRowset::GetExactPosition, public
  1135. //
  1136. // Synopsis: Returns the exact position of a bookmark
  1137. //
  1138. // Arguments: [hChapter] -- chapter
  1139. // [cbBookmark] -- size of bookmark
  1140. // [pBookmark] -- bookmark
  1141. // [pulPosition] -- return approx row number of bookmark
  1142. // [pulRows] -- returns approx # of rows in cursor or
  1143. // 1 + approx rows if not at quiescence
  1144. //
  1145. // Returns: SCODE - the status of the operation.
  1146. //
  1147. // Notes: We don't distinguish between exact and approximate position.
  1148. // IRowsetExactScroll is implemented only because ADO 1.5
  1149. // started QI'ing for it.
  1150. //
  1151. //--------------------------------------------------------------------------
  1152. STDMETHODIMP CRowset::GetExactPosition(
  1153. HCHAPTER hChapter,
  1154. DBBKMARK cbBookmark,
  1155. const BYTE * pBookmark,
  1156. DBCOUNTITEM * pulPosition,
  1157. DBCOUNTITEM * pulRows) /*const*/
  1158. {
  1159. _DBErrorObj.ClearErrorInfo();
  1160. Win4Assert( !_fForwardOnly );
  1161. SCODE sc = S_OK;
  1162. TRY
  1163. {
  1164. DBCOUNTITEM ulNumerator, ulDenominator;
  1165. CI_TBL_BMK bmk = WORKID_TBLFIRST;
  1166. if (cbBookmark != 0)
  1167. bmk = _MapBookmark(cbBookmark, pBookmark);
  1168. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  1169. _rQuery.GetApproximatePosition( _hCursor,
  1170. chapt,
  1171. bmk,
  1172. &ulNumerator,
  1173. &ulDenominator );
  1174. if (cbBookmark)
  1175. *pulPosition = ulNumerator;
  1176. if (pulRows)
  1177. *pulRows = ulDenominator;
  1178. }
  1179. CATCH( CException, e )
  1180. {
  1181. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetScroll);
  1182. sc = GetOleError(e);
  1183. }
  1184. END_CATCH;
  1185. return sc;
  1186. }
  1187. //+---------------------------------------------------------------------------
  1188. //
  1189. // Member: CRowset::GetRowsAtRatio, public
  1190. //
  1191. // Synopsis: Fetch data starting at some ratio in the cursor.
  1192. //
  1193. // Arguments: [hRegion] -- handle to watch region
  1194. // [hChapter] -- Chapter in a multiset cursor
  1195. // [ulNumerator] -- numerator or ratio fraction
  1196. // [ulDenominator] -- denominator or ratio fraction
  1197. // [cRows] -- Number of rows to return
  1198. // [pcRowsObtained] -- On return, number of rows actually
  1199. // fetched.
  1200. // [prghRows] -- Array of HROWs to be released
  1201. //
  1202. // Returns: SCODE, E_INVALIDARG for bad parameters, DB_E_BADBOOKMARK
  1203. // if the starting bookmark is invalid
  1204. //
  1205. // Notes:
  1206. //
  1207. // History: 14 Dec 1994 Alanw Created
  1208. //
  1209. //--------------------------------------------------------------------------
  1210. STDMETHODIMP CRowset::GetRowsAtRatio(
  1211. HWATCHREGION hRegion,
  1212. HCHAPTER hChapter,
  1213. DBCOUNTITEM ulNumerator,
  1214. DBCOUNTITEM ulDenominator,
  1215. DBROWCOUNT cRows,
  1216. DBCOUNTITEM * pcRowsObtained,
  1217. HROW * * prghRows
  1218. ) {
  1219. _DBErrorObj.ClearErrorInfo();
  1220. CheckCrowsArgs( cRows, pcRowsObtained );
  1221. SCODE scResult = S_OK;
  1222. TRY
  1223. {
  1224. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  1225. CRowSeekAtRatio rowSeek( hRegion, chapt, (ULONG) ulNumerator, (ULONG) ulDenominator );
  1226. scResult = _FetchRows(rowSeek, cRows, pcRowsObtained, prghRows);
  1227. if (FAILED(scResult))
  1228. _DBErrorObj.PostHResult(scResult, IID_IRowsetScroll);
  1229. else if ( !_pRowsetNotification.IsNull() &&
  1230. *pcRowsObtained != 0 &&
  1231. _pRowsetNotification->IsNotifyActive() )
  1232. {
  1233. _pRowsetNotification->OnRowChange( this,
  1234. *pcRowsObtained,
  1235. *prghRows,
  1236. DBREASON_ROW_ACTIVATE,
  1237. DBEVENTPHASE_DIDEVENT,
  1238. TRUE);
  1239. }
  1240. }
  1241. CATCH( CException, e )
  1242. {
  1243. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetScroll);
  1244. scResult = GetOleError(e);
  1245. }
  1246. END_CATCH;
  1247. return scResult;
  1248. }
  1249. #ifdef _WIN64
  1250. //+---------------------------------------------------------------------------
  1251. //
  1252. // Member: CRowset::_ConvertOffsetsToPointers, private
  1253. //
  1254. // Synopsis: Runs through a row buffer converting offsets to pointers
  1255. //
  1256. // Arguments: [pbRows] -- Buffer with row data
  1257. // [pbBias] -- Bias for offsets to pointers
  1258. // [cRows] -- Number of rows in the buffer
  1259. // [pArrayAlloc] -- buffer to hold extra array pointers
  1260. //
  1261. // History: 2 Aug 95 dlee created
  1262. // 1 Sep 99 KLam Reinstated
  1263. //
  1264. //----------------------------------------------------------------------------
  1265. void CRowset::_ConvertOffsetsToPointers(
  1266. BYTE * pbRows,
  1267. BYTE * pbBias,
  1268. unsigned cRows,
  1269. CFixedVarAllocator *pArrayAlloc )
  1270. {
  1271. if ( !_fPossibleOffsetConversions )
  1272. return;
  1273. BOOL fAnyOffsets = FALSE;
  1274. CTableColumnSet const & rCols = _ColumnsInfo.GetColumnBindings();
  1275. unsigned cbRowWidth = _ColumnsInfo.GetRowWidth();
  1276. for ( unsigned col = 0; col < rCols.Count(); col++ )
  1277. {
  1278. CTableColumn const & rColumn = *rCols.Get( col );
  1279. // if this assert isn't true someday, add an if on this condition
  1280. Win4Assert( rColumn.IsValueStored() );
  1281. VARTYPE vt = rColumn.GetStoredType();
  1282. if ( ( CTableVariant::IsByRef( vt ) ) && ( VT_CLSID != vt ) )
  1283. {
  1284. fAnyOffsets = TRUE;
  1285. BYTE *pbRow = pbRows;
  1286. BYTE *pbData = pbRow + rColumn.GetValueOffset();
  1287. for ( unsigned row = 0;
  1288. row < cRows;
  1289. row++, pbData += cbRowWidth, pbRow += cbRowWidth )
  1290. {
  1291. // Even stat props can be null if they came from a
  1292. // summary catalog.
  1293. tbDebugOut(( DEB_TRACE,
  1294. "CRowset::_ConvertOffsetsToPointer, Bias: 0x%I64x Row: 0x%I64x Data: 0x%I64x Type: %d New Alloc: 0x%I64x\n",
  1295. pbBias, pbRow, pbData, vt, pArrayAlloc ));
  1296. if (! rColumn.IsNull( pbRow ) )
  1297. {
  1298. if ( VT_VARIANT == vt )
  1299. {
  1300. if (! rColumn.IsDeferred( pbRow ) )
  1301. ((CTableVariant *) pbData)->FixDataPointers( pbBias, pArrayAlloc );
  1302. }
  1303. else
  1304. {
  1305. Win4Assert( 0 == ( vt & VT_VECTOR ) );
  1306. * (BYTE **) pbData = pbBias + (* (ULONG *) pbData );
  1307. }
  1308. }
  1309. }
  1310. }
  1311. }
  1312. _fPossibleOffsetConversions = fAnyOffsets;
  1313. } //_ConvertOffsetsToPointers
  1314. #endif // _WIN64
  1315. //+---------------------------------------------------------------------------
  1316. //
  1317. // Member: CRowset::_FetchRows, private
  1318. //
  1319. // Synopsis: Return handles to rows in the table
  1320. //
  1321. // Effects: Rows are read from the table and buffered locally. An
  1322. // array of handles to the rows is returned.
  1323. //
  1324. // Arguments: [rSeekDesc] - seek method and parameters
  1325. // [cRows] - number of rows desired
  1326. // [pcRowsReturned] - pointer to where number of rows is returned
  1327. // [prghRows] - pointer to pointer to where row handles are
  1328. // returned, or pointer to zero if row handle
  1329. // array should be allocated
  1330. //
  1331. // Returns: error code
  1332. //
  1333. // Notes:
  1334. //
  1335. //----------------------------------------------------------------------------
  1336. SCODE CRowset::_FetchRows(
  1337. CRowSeekDescription & rSeekDesc,
  1338. DBROWCOUNT cRows,
  1339. DBCOUNTITEM * pcRowsReturned,
  1340. HROW * * prghRows
  1341. ) {
  1342. SCODE scResult = S_OK;
  1343. Win4Assert( 0 != pcRowsReturned );
  1344. if (0 == prghRows)
  1345. {
  1346. THROW(CException(E_INVALIDARG));
  1347. }
  1348. if (0 == cRows)
  1349. {
  1350. *pcRowsReturned = 0;
  1351. return scResult;
  1352. }
  1353. BOOL fFwdFetch = TRUE;
  1354. if ( cRows < 0 )
  1355. {
  1356. fFwdFetch = FALSE;
  1357. cRows = -cRows; // cRows now has its absolute value
  1358. }
  1359. Win4Assert( cRows > 0 );
  1360. BOOL fRowCountTrimmed = FALSE;
  1361. if (cRows > MAX_ROW_FETCH)
  1362. {
  1363. cRows = MAX_ROW_FETCH;
  1364. fRowCountTrimmed = TRUE;
  1365. }
  1366. XArrayOLE<HROW> ahRows;
  1367. HROW *pHRows;
  1368. if ( 0 == *prghRows )
  1369. {
  1370. ahRows.Init( (unsigned) cRows );
  1371. pHRows = ahRows.GetPointer();
  1372. }
  1373. else
  1374. {
  1375. pHRows = *prghRows;
  1376. }
  1377. DBCOUNTITEM cRowsSoFar = 0; // number of rows successfully transferred.
  1378. CRowSeekDescription * pNextSeek = &rSeekDesc;
  1379. TRY
  1380. {
  1381. XPtr<CRowSeekDescription> pRowSeekPrevious(0);
  1382. ULONG cbRowWidth = _ColumnsInfo.GetRowWidth();
  1383. do
  1384. {
  1385. XPtr<CFixedVarAllocator> xAlloc( new
  1386. CFixedVarAllocator( FALSE,
  1387. FALSE,
  1388. cbRowWidth,
  1389. 0 ));
  1390. CGetRowsParams FetchParams( (ULONG) (cRows - cRowsSoFar),
  1391. fFwdFetch,
  1392. cbRowWidth,
  1393. xAlloc.GetReference() );
  1394. // Get the row data
  1395. XPtr<CRowSeekDescription> xRowSeekOut(0);
  1396. scResult = _rQuery.GetRows( _hCursor,
  1397. *pNextSeek,
  1398. FetchParams,
  1399. xRowSeekOut );
  1400. if (FAILED(scResult))
  1401. {
  1402. #if CIDBG
  1403. if (E_FAIL == scResult)
  1404. tbDebugOut((DEB_WARN,
  1405. "CRowset::_FetchRows - E_FAIL ret'd by GetRows\n"));
  1406. #endif // CIDBG
  1407. break;
  1408. }
  1409. if ( 0 != FetchParams.RowsTransferred() )
  1410. {
  1411. Win4Assert( !xAlloc->IsBasedMemory() );
  1412. XPtr<CRowBuffer> xRowBuf ( new
  1413. CRowBuffer( _ColumnsInfo.GetColumnBindings(),
  1414. cbRowWidth,
  1415. FetchParams.RowsTransferred(),
  1416. xAlloc ));
  1417. #ifdef _WIN64
  1418. // if this is a Win64 client talking with a Win32 server
  1419. // then we need to fix the row buffer since we passed in 0
  1420. // as the base address.
  1421. if ( FetchParams.GetReplyBase() != 0 )
  1422. {
  1423. _fPossibleOffsetConversions = TRUE;
  1424. void *pvRows;
  1425. CTableColumnSet *pCol;
  1426. SCODE sc = xRowBuf->Lookup( (unsigned)cRowsSoFar,
  1427. &pCol,
  1428. &pvRows,
  1429. FALSE );
  1430. _ConvertOffsetsToPointers ( (BYTE *)pvRows,
  1431. FetchParams.GetReplyBase(),
  1432. FetchParams.RowsTransferred(),
  1433. _pRowBufs->GetArrayAlloc() );
  1434. }
  1435. #endif
  1436. _pRowBufs->Add( xRowBuf,
  1437. rSeekDesc.IsByBmkRowSeek(),
  1438. pHRows + cRowsSoFar );
  1439. cRowsSoFar += FetchParams.RowsTransferred();
  1440. }
  1441. else
  1442. {
  1443. // One row didn't fit into an fsctl buffer.
  1444. if (! ( scResult == DB_S_ENDOFROWSET ||
  1445. scResult == DB_S_STOPLIMITREACHED ||
  1446. ( scResult == DB_S_ERRORSOCCURRED &&
  1447. rSeekDesc.IsByBmkRowSeek() ) ) )
  1448. {
  1449. tbDebugOut(( DEB_WARN,
  1450. "CRowset::_FetchRows, 0 rows, sc 0x%x\n",
  1451. scResult ));
  1452. }
  1453. Win4Assert( scResult == DB_S_ENDOFROWSET ||
  1454. scResult == DB_S_STOPLIMITREACHED ||
  1455. ( scResult == DB_S_ERRORSOCCURRED &&
  1456. rSeekDesc.IsByBmkRowSeek() ) );
  1457. }
  1458. if ( 0 != xRowSeekOut.GetPointer() )
  1459. {
  1460. //
  1461. // Transfer results from the returned seek description
  1462. // (for the ByBookmark case), and update for the next
  1463. // transfer.
  1464. //
  1465. rSeekDesc.MergeResults( xRowSeekOut.GetPointer() );
  1466. delete pRowSeekPrevious.Acquire();
  1467. pRowSeekPrevious.Set( xRowSeekOut.Acquire() );
  1468. pNextSeek = pRowSeekPrevious.GetPointer();
  1469. }
  1470. Win4Assert( cRows >= 0 );
  1471. } while ( (DBCOUNTITEM) cRows > cRowsSoFar &&
  1472. 0 != pNextSeek &&
  1473. !pNextSeek->IsDone() &&
  1474. (S_OK == scResult || DB_S_BLOCKLIMITEDROWS == scResult ) );
  1475. }
  1476. CATCH( CException, e )
  1477. {
  1478. scResult = e.GetErrorCode();
  1479. #if CIDBG
  1480. if (E_FAIL == scResult)
  1481. tbDebugOut((DEB_WARN, "CRowset::_FetchRows - E_FAIL from exception\n"));
  1482. #endif // CIDBG
  1483. }
  1484. END_CATCH;
  1485. if (DB_E_BADSTARTPOSITION == scResult)
  1486. scResult = DB_S_ENDOFROWSET;
  1487. if ( fRowCountTrimmed && scResult == S_OK )
  1488. scResult = DB_S_ROWLIMITEXCEEDED;
  1489. if ( FAILED(scResult))
  1490. {
  1491. ReleaseRows(cRowsSoFar, pHRows, 0, 0, 0);
  1492. *pcRowsReturned = 0;
  1493. tbDebugOut((DEB_ITRACE, "CRowset::_FetchRows - error %x thrown\n", scResult));
  1494. QUIETTHROW( CException( scResult ) );
  1495. }
  1496. else
  1497. {
  1498. if ( ( cRowsSoFar > 0 ) && ( 0 == *prghRows ) )
  1499. *prghRows = ahRows.Acquire();
  1500. *pcRowsReturned = cRowsSoFar;
  1501. }
  1502. return( scResult );
  1503. }
  1504. //+---------------------------------------------------------------------------
  1505. //
  1506. // Member: CRowset::CreateAccessor, public
  1507. //
  1508. // Synopsis: Makes an accessor that a client can use to get data.
  1509. //
  1510. // Arguments: [dwAccessorFlags] -- read/write access requested
  1511. // [cBindings] -- # of bindings in rgBindings
  1512. // [rgBindings] -- array of bindings for the accessor to support
  1513. // [cbRowSize] -- ignored for IRowset
  1514. // [phAccessor] -- returns created accessor if all is ok
  1515. // [rgBindStatus] -- array of binding statuses
  1516. //
  1517. // Returns: SCODE error code
  1518. //
  1519. // History: 14 Dec 94 dlee Created
  1520. //
  1521. //----------------------------------------------------------------------------
  1522. STDMETHODIMP CRowset::CreateAccessor(
  1523. DBACCESSORFLAGS dwAccessorFlags,
  1524. DBCOUNTITEM cBindings,
  1525. const DBBINDING rgBindings[],
  1526. DBLENGTH cbRowSize,
  1527. HACCESSOR * phAccessor,
  1528. DBBINDSTATUS rgBindStatus[])
  1529. {
  1530. _DBErrorObj.ClearErrorInfo();
  1531. SCODE sc = S_OK;
  1532. if (0 == phAccessor || (0 != cBindings && 0 == rgBindings))
  1533. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor);
  1534. // Make sure pointer is good while zeroing in case of a later error
  1535. *phAccessor = 0;
  1536. TRY
  1537. {
  1538. XPtr<CAccessor> Accessor( CreateAnAccessor( dwAccessorFlags,
  1539. cBindings,
  1540. rgBindings,
  1541. rgBindStatus,
  1542. _fExtendedTypes,
  1543. (IUnknown *) (IRowset *)this,
  1544. &_ColumnsInfo ) );
  1545. CLock lock( _mutex );
  1546. _aAccessors.Add( Accessor.GetPointer() );
  1547. *phAccessor = (Accessor.Acquire())->Cast();
  1548. }
  1549. CATCH(CException, e)
  1550. {
  1551. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor);
  1552. sc = GetOleError(e);
  1553. }
  1554. END_CATCH;
  1555. return sc;
  1556. } //CreateAccessor
  1557. //+---------------------------------------------------------------------------
  1558. //
  1559. // Member: IsValidFromVariantType
  1560. //
  1561. // Synopsis: If DBCONVERTFLAGS_FROMVARIANT is requested, the source type
  1562. // has to be a valid VARIANT type.
  1563. //
  1564. // Arguments: [wTypeIn] -- the source type
  1565. //
  1566. // Returns: TRUE -- the type is a valid VARIANT type
  1567. // FALSE -- otherwise
  1568. //
  1569. //----------------------------------------------------------------------------
  1570. inline BOOL IsValidFromVariantType( DBTYPE wTypeIn )
  1571. {
  1572. DBTYPE wType = wTypeIn & VT_TYPEMASK;
  1573. return (! ((wType > VT_DECIMAL && wType < VT_I1) ||
  1574. (wType > VT_LPWSTR && wType < VT_FILETIME && wType != VT_RECORD) ||
  1575. (wType > VT_CLSID)) );
  1576. }
  1577. //+---------------------------------------------------------------------------
  1578. //
  1579. // Member: IsVariableLengthType
  1580. //
  1581. // Synopsis: checks to see DBCONVERTFLAGS_ISLONG is appropriate
  1582. //
  1583. // Arguments: [wTypeIn] -- the source type
  1584. //
  1585. // Returns: TRUE -- the type is variable length
  1586. // FALSE -- otherwise
  1587. //
  1588. //----------------------------------------------------------------------------
  1589. inline BOOL IsVariableLengthType( DBTYPE wTypeIn )
  1590. {
  1591. DBTYPE wType = wTypeIn & VT_TYPEMASK;
  1592. return wType == DBTYPE_STR ||
  1593. wType == DBTYPE_BYTES ||
  1594. wType == DBTYPE_WSTR ||
  1595. wType == DBTYPE_VARNUMERIC;
  1596. }
  1597. //+---------------------------------------------------------------------------
  1598. //
  1599. // Member: CRowset::CanConvert, public
  1600. //
  1601. // Synopsis: Indicate whether a type conversion is valid.
  1602. //
  1603. // Arguments: [wFromType] -- source type
  1604. // [wToType] -- destination type
  1605. // [dwConvertFlags] -- read/write access requested
  1606. //
  1607. // Returns: S_OK if the conversion is available, S_FALSE otherwise.
  1608. // E_FAIL, E_INVALIDARG or DB_E_BADCONVERTFLAG on errors.
  1609. //
  1610. // History: 20 Nov 96 AlanW Created
  1611. //
  1612. //----------------------------------------------------------------------------
  1613. STDMETHODIMP CRowset::CanConvert(
  1614. DBTYPE wFromType,
  1615. DBTYPE wToType,
  1616. DBCONVERTFLAGS dwConvertFlags )
  1617. {
  1618. _DBErrorObj.ClearErrorInfo();
  1619. SCODE sc = S_OK;
  1620. TRY
  1621. {
  1622. if (((dwConvertFlags & DBCONVERTFLAGS_COLUMN) &&
  1623. (dwConvertFlags & DBCONVERTFLAGS_PARAMETER)) ||
  1624. (dwConvertFlags & ~(DBCONVERTFLAGS_COLUMN |
  1625. DBCONVERTFLAGS_PARAMETER |
  1626. DBCONVERTFLAGS_ISFIXEDLENGTH |
  1627. DBCONVERTFLAGS_ISLONG |
  1628. DBCONVERTFLAGS_FROMVARIANT)))
  1629. {
  1630. sc = DB_E_BADCONVERTFLAG;
  1631. }
  1632. else if ( dwConvertFlags & DBCONVERTFLAGS_FROMVARIANT &&
  1633. !IsValidFromVariantType(wFromType) )
  1634. {
  1635. sc = DB_E_BADTYPE;
  1636. }
  1637. else
  1638. {
  1639. BOOL fOk = CAccessor::CanConvertType( wFromType,
  1640. wToType,
  1641. _fExtendedTypes, _xDataConvert );
  1642. sc = fOk ? S_OK : S_FALSE;
  1643. }
  1644. if (FAILED(sc))
  1645. _DBErrorObj.PostHResult(sc, IID_IConvertType);
  1646. }
  1647. CATCH(CException, e)
  1648. {
  1649. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IConvertType);
  1650. sc = GetOleError(e);
  1651. }
  1652. END_CATCH;
  1653. return sc;
  1654. }
  1655. //+---------------------------------------------------------------------------
  1656. //
  1657. // Member: CRowset::GetBindings, public
  1658. //
  1659. // Synopsis: Returns an accessor's bindings
  1660. //
  1661. // Arguments: [hAccessor] -- accessor being queried
  1662. // [dwBindIO] -- returns read/write access of accessor
  1663. // [pcBindings] -- returns # of bindings in rgBindings
  1664. // [prgBindings] -- returns array of bindings
  1665. //
  1666. // Returns: SCODE error code
  1667. //
  1668. // History: 14 Dec 94 dlee Created
  1669. //
  1670. //----------------------------------------------------------------------------
  1671. STDMETHODIMP CRowset::GetBindings(
  1672. HACCESSOR hAccessor,
  1673. DBACCESSORFLAGS * pdwBindIO,
  1674. DBCOUNTITEM * pcBindings,
  1675. DBBINDING * * prgBindings) /*const*/
  1676. {
  1677. _DBErrorObj.ClearErrorInfo();
  1678. SCODE sc = S_OK;
  1679. if (0 == pdwBindIO ||
  1680. 0 == pcBindings ||
  1681. 0 == prgBindings)
  1682. {
  1683. // fill in error values where possible
  1684. if (pdwBindIO)
  1685. *pdwBindIO = DBACCESSOR_INVALID;
  1686. if (pcBindings)
  1687. *pcBindings = 0;
  1688. if (prgBindings)
  1689. *prgBindings = 0;
  1690. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor);
  1691. }
  1692. *pdwBindIO = DBACCESSOR_INVALID;
  1693. *pcBindings = 0;
  1694. *prgBindings = 0;
  1695. TRY
  1696. {
  1697. CLock lock( _mutex );
  1698. CAccessor * pAccessor = (CAccessor *)_aAccessors.Convert( hAccessor );
  1699. pAccessor->GetBindings(pdwBindIO, pcBindings, prgBindings);
  1700. }
  1701. CATCH(CException, e)
  1702. {
  1703. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor);
  1704. sc = GetOleError(e);
  1705. }
  1706. END_CATCH;
  1707. return sc;
  1708. }
  1709. //+---------------------------------------------------------------------------
  1710. //
  1711. // Member: CRowset::AddRefAccessor, public
  1712. //
  1713. // Synopsis: Frees an accessor
  1714. //
  1715. // Arguments: [hAccessor] -- accessor being freed
  1716. // [pcRefCount] -- pointer to residual refcount (optional)
  1717. //
  1718. // Returns: SCODE error code
  1719. //
  1720. // History: 14 Dec 94 dlee Created
  1721. //
  1722. //----------------------------------------------------------------------------
  1723. STDMETHODIMP CRowset::AddRefAccessor(
  1724. HACCESSOR hAccessor,
  1725. ULONG * pcRefCount
  1726. ) {
  1727. _DBErrorObj.ClearErrorInfo();
  1728. SCODE sc = S_OK;
  1729. TRY
  1730. {
  1731. CLock lock( _mutex );
  1732. _aAccessors.AddRef( hAccessor, pcRefCount );
  1733. }
  1734. CATCH(CException, e)
  1735. {
  1736. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor);
  1737. sc = GetOleError(e);
  1738. }
  1739. END_CATCH;
  1740. return sc;
  1741. }
  1742. //+---------------------------------------------------------------------------
  1743. //
  1744. // Member: CRowset::ReleaseAccessor, public
  1745. //
  1746. // Synopsis: Frees an accessor
  1747. //
  1748. // Arguments: [hAccessor] -- accessor being freed
  1749. // [pcRefCount] -- pointer to residual refcount (optional)
  1750. //
  1751. // Returns: SCODE error code
  1752. //
  1753. // History: 14 Dec 94 dlee Created
  1754. //
  1755. //----------------------------------------------------------------------------
  1756. STDMETHODIMP CRowset::ReleaseAccessor(
  1757. HACCESSOR hAccessor,
  1758. ULONG * pcRefCount )
  1759. {
  1760. _DBErrorObj.ClearErrorInfo();
  1761. SCODE sc = S_OK;
  1762. TRY
  1763. {
  1764. CLock lock( _mutex );
  1765. _aAccessors.Release( hAccessor, pcRefCount );
  1766. }
  1767. CATCH(CException, e)
  1768. {
  1769. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor);
  1770. sc = GetOleError(e);
  1771. }
  1772. END_CATCH;
  1773. return sc;
  1774. } //ReleaseAccessor
  1775. //+---------------------------------------------------------------------------
  1776. //
  1777. // Member: CRowset::GetData, public
  1778. //
  1779. // Synopsis: Returns row data using an accessor
  1780. //
  1781. // Arguments: [hRow] -- handle of row whose data is returned
  1782. // [hAccessor] -- accessor used to retrieve the data
  1783. // [pData] -- where the data is written
  1784. //
  1785. // Returns: SCODE error code
  1786. //
  1787. // History: 14 Dec 94 dlee Created
  1788. //
  1789. //----------------------------------------------------------------------------
  1790. STDMETHODIMP CRowset::GetData(
  1791. HROW hRow,
  1792. HACCESSOR hAccessor,
  1793. void* pData) /*const*/
  1794. {
  1795. _DBErrorObj.ClearErrorInfo();
  1796. SCODE sc = S_OK;
  1797. // NOTE: Null accessors are not supported, so don't need to worry about
  1798. // special casing for that.
  1799. if ( 0 == pData )
  1800. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowset);
  1801. TRY
  1802. {
  1803. CLock lock( _mutex );
  1804. CAccessor * pAccessor = (CAccessor *)_aAccessors.Convert( hAccessor );
  1805. Win4Assert( pAccessor->IsRowDataAccessor() );
  1806. pAccessor->GetData(hRow, pData, *_pRowBufs, _rQuery, _ColumnsInfo, _xDataConvert );
  1807. }
  1808. CATCH(CException, e)
  1809. {
  1810. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset);
  1811. sc = GetOleError(e);
  1812. }
  1813. END_CATCH;
  1814. return sc;
  1815. }
  1816. //+---------------------------------------------------------------------------
  1817. //
  1818. // Member: CRowset::GetNextRows, public
  1819. //
  1820. // Synopsis: Return row data from the table
  1821. //
  1822. // Arguments: [hChapter] -- chapter to start at
  1823. // [cRowsToSkip] -- # of rows to skip
  1824. // [cRows] -- # of rows to try to return
  1825. // [pcRowsObtained] -- returns # of rows obtained
  1826. // [prghRows] -- returns array of rows
  1827. //
  1828. // Returns: SCODE error code
  1829. //
  1830. // Notes:
  1831. //
  1832. //----------------------------------------------------------------------------
  1833. STDMETHODIMP CRowset::GetNextRows(
  1834. HCHAPTER hChapter,
  1835. DBROWOFFSET cRowsToSkip,
  1836. DBROWCOUNT cRows,
  1837. DBCOUNTITEM * pcRowsObtained,
  1838. HROW * * prghRows
  1839. )
  1840. {
  1841. _DBErrorObj.ClearErrorInfo();
  1842. SCODE scResult = S_OK;
  1843. BOOL fNotified = FALSE;
  1844. CheckCrowsArgs( cRows, pcRowsObtained );
  1845. if (_fForwardOnly && cRowsToSkip < 0)
  1846. return _DBErrorObj.PostHResult(DB_E_CANTSCROLLBACKWARDS, IID_IRowset);
  1847. if (_fForwardOnly && cRows < 0 )
  1848. return _DBErrorObj.PostHResult(DB_E_CANTFETCHBACKWARDS, IID_IRowset);
  1849. TRY
  1850. {
  1851. if (! _fHoldRows)
  1852. _pRowBufs->CheckAllHrowsReleased();
  1853. CI_TBL_CHAPT chapt = _MapChapter(hChapter);
  1854. if ( !_pRowsetNotification.IsNull() &&
  1855. _pRowsetNotification->IsNotifyActive() )
  1856. {
  1857. scResult = _pRowsetNotification->OnRowsetChange(
  1858. this,
  1859. DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  1860. DBEVENTPHASE_OKTODO,
  1861. FALSE);
  1862. if ( S_FALSE == scResult )
  1863. THROW(CException(DB_E_CANCELED));
  1864. fNotified = TRUE;
  1865. }
  1866. CRowSeekNext rowSeek( chapt, (LONG) cRowsToSkip );
  1867. scResult = _FetchRows(rowSeek, cRows, pcRowsObtained, prghRows);
  1868. if ( fNotified )
  1869. {
  1870. if (SUCCEEDED(scResult))
  1871. {
  1872. if ( *pcRowsObtained != 0 )
  1873. _pRowsetNotification->OnRowChange( this,
  1874. *pcRowsObtained,
  1875. *prghRows,
  1876. DBREASON_ROW_ACTIVATE,
  1877. DBEVENTPHASE_DIDEVENT,
  1878. TRUE);
  1879. _pRowsetNotification->OnRowsetChange( this,
  1880. DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  1881. DBEVENTPHASE_DIDEVENT,
  1882. TRUE);
  1883. }
  1884. }
  1885. if (FAILED(scResult))
  1886. _DBErrorObj.PostHResult(scResult, IID_IRowset);
  1887. }
  1888. CATCH( CException, e )
  1889. {
  1890. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset);
  1891. scResult = GetOleError(e);
  1892. }
  1893. END_CATCH;
  1894. if ( fNotified && FAILED(scResult) )
  1895. _pRowsetNotification->OnRowsetChange( this,
  1896. DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  1897. DBEVENTPHASE_FAILEDTODO,
  1898. TRUE);
  1899. Win4Assert( cRowsToSkip != 0 ||
  1900. DB_E_BADSTARTPOSITION != scResult );
  1901. return scResult;
  1902. }
  1903. //
  1904. // IRowsetIdentity methods
  1905. //
  1906. SCODE CRowset::IsSameRow ( HROW hThisRow, HROW hThatRow )
  1907. {
  1908. _DBErrorObj.ClearErrorInfo();
  1909. SCODE scResult = S_OK;
  1910. TRY
  1911. {
  1912. CTableColumnSet *pRowBufferColumns;
  1913. BYTE *pbSrc;
  1914. //
  1915. // Lookup the HROWs to validate them
  1916. //
  1917. _pRowBufs->Lookup( hThisRow,
  1918. &pRowBufferColumns,
  1919. (void **) &pbSrc );
  1920. _pRowBufs->Lookup( hThatRow,
  1921. &pRowBufferColumns,
  1922. (void **) &pbSrc );
  1923. if (hThisRow != hThatRow)
  1924. scResult = S_FALSE;
  1925. }
  1926. CATCH( CException, e )
  1927. {
  1928. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetIdentity);
  1929. scResult = GetOleError(e);
  1930. }
  1931. END_CATCH;
  1932. return scResult;
  1933. }
  1934. //
  1935. // IRowsetWatchAll methods
  1936. //
  1937. SCODE CRowset::Acknowledge ( )
  1938. {
  1939. _DBErrorObj.ClearErrorInfo();
  1940. SCODE scResult = S_OK;
  1941. TRY
  1942. {
  1943. // Just use Refresh to acknowledge the notification.
  1944. _rQuery.Refresh();
  1945. }
  1946. CATCH( CException, e )
  1947. {
  1948. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchAll);
  1949. scResult = GetOleError(e);
  1950. }
  1951. END_CATCH;
  1952. return scResult;
  1953. }
  1954. SCODE CRowset::Start ( )
  1955. {
  1956. _DBErrorObj.ClearErrorInfo();
  1957. SCODE scResult = S_OK;
  1958. TRY
  1959. {
  1960. _rQuery.StartWatching(_hCursor);
  1961. }
  1962. CATCH( CException, e )
  1963. {
  1964. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchAll);
  1965. scResult = GetOleError(e);
  1966. }
  1967. END_CATCH;
  1968. return scResult;
  1969. }
  1970. SCODE CRowset::StopWatching ( )
  1971. {
  1972. _DBErrorObj.ClearErrorInfo();
  1973. SCODE scResult = S_OK;
  1974. TRY
  1975. {
  1976. _rQuery.StopWatching(_hCursor);
  1977. }
  1978. CATCH( CException, e )
  1979. {
  1980. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchAll);
  1981. scResult = GetOleError(e);
  1982. }
  1983. END_CATCH;
  1984. return scResult;
  1985. }
  1986. //
  1987. // IRowsetWatchRegion methods
  1988. //
  1989. SCODE CRowset::ChangeWatchMode (
  1990. HWATCHREGION hRegion,
  1991. DBWATCHMODE mode)
  1992. {
  1993. _DBErrorObj.ClearErrorInfo();
  1994. if (hRegion == watchRegionInvalid)
  1995. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);;
  1996. SCODE scResult = S_OK;
  1997. TRY
  1998. {
  1999. _rQuery.SetWatchMode(&hRegion, mode);
  2000. }
  2001. CATCH( CException, e )
  2002. {
  2003. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion);
  2004. scResult = GetOleError(e);
  2005. }
  2006. END_CATCH;
  2007. return scResult;
  2008. }
  2009. SCODE CRowset::CreateWatchRegion (
  2010. DBWATCHMODE mode,
  2011. HWATCHREGION* phRegion)
  2012. {
  2013. _DBErrorObj.ClearErrorInfo();
  2014. SCODE scResult = S_OK;
  2015. *phRegion = watchRegionInvalid;
  2016. TRY
  2017. {
  2018. _rQuery.SetWatchMode(phRegion, mode);
  2019. }
  2020. CATCH( CException, e )
  2021. {
  2022. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion);
  2023. scResult = GetOleError(e);
  2024. }
  2025. END_CATCH;
  2026. return scResult;
  2027. }
  2028. SCODE CRowset::DeleteWatchRegion (
  2029. HWATCHREGION hRegion)
  2030. {
  2031. _DBErrorObj.ClearErrorInfo();
  2032. if (hRegion == watchRegionInvalid)
  2033. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);
  2034. SCODE scResult = S_OK;
  2035. TRY
  2036. {
  2037. _rQuery.ShrinkWatchRegion (hRegion, 0, 0, 0);
  2038. }
  2039. CATCH( CException, e )
  2040. {
  2041. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion);
  2042. scResult = GetOleError(e);
  2043. }
  2044. END_CATCH;
  2045. return scResult;
  2046. }
  2047. SCODE CRowset::GetWatchRegionInfo (
  2048. HWATCHREGION hRegion,
  2049. DBWATCHMODE * pMode,
  2050. HCHAPTER * phChapter,
  2051. DBBKMARK * pcbBookmark,
  2052. BYTE ** ppBookmark,
  2053. DBROWCOUNT * pcRows)
  2054. {
  2055. _DBErrorObj.ClearErrorInfo();
  2056. if (hRegion == watchRegionInvalid)
  2057. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);;
  2058. SCODE scResult = S_OK;
  2059. // test pointers and prepare for failure
  2060. *phChapter = 0;
  2061. *pcbBookmark = 0;
  2062. *ppBookmark = 0;
  2063. *pcRows = 0;
  2064. TRY
  2065. {
  2066. CI_TBL_CHAPT chapter;
  2067. CI_TBL_BMK bookmark;
  2068. _rQuery.GetWatchInfo( hRegion, pMode, &chapter, &bookmark, (DBCOUNTITEM *)pcRows);
  2069. if (chapter != 0)
  2070. {
  2071. *phChapter = (HCHAPTER)chapter;
  2072. }
  2073. if (bookmark != 0)
  2074. {
  2075. XArrayOLE<CI_TBL_BMK> pOutBookmark (1);
  2076. *pcbBookmark = sizeof CI_TBL_BMK;
  2077. memcpy ( pOutBookmark.GetPointer(), &bookmark, sizeof CI_TBL_BMK);
  2078. *ppBookmark = (BYTE*) pOutBookmark.Acquire();
  2079. }
  2080. }
  2081. CATCH( CException, e )
  2082. {
  2083. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion);
  2084. scResult = GetOleError(e);
  2085. }
  2086. END_CATCH;
  2087. return scResult;
  2088. }
  2089. SCODE CRowset::ShrinkWatchRegion (
  2090. HWATCHREGION hRegion,
  2091. HCHAPTER hChapter,
  2092. DBBKMARK cbBookmark,
  2093. BYTE * pBookmark,
  2094. DBROWCOUNT cRows )
  2095. {
  2096. _DBErrorObj.ClearErrorInfo();
  2097. if (hRegion == watchRegionInvalid)
  2098. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);;
  2099. SCODE scResult = S_OK;
  2100. TRY
  2101. {
  2102. CI_TBL_BMK bookmark = _MapBookmark(cbBookmark, pBookmark);
  2103. CI_TBL_CHAPT chapter = _MapChapter(hChapter);
  2104. _rQuery.ShrinkWatchRegion ( hRegion, chapter, bookmark, (LONG) cRows);
  2105. }
  2106. CATCH( CException, e )
  2107. {
  2108. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion);
  2109. scResult = GetOleError(e);
  2110. }
  2111. END_CATCH;
  2112. return scResult;
  2113. }
  2114. SCODE CRowset::Refresh (
  2115. DBCOUNTITEM* pCount,
  2116. DBROWWATCHCHANGE** ppRowChange )
  2117. {
  2118. _DBErrorObj.ClearErrorInfo();
  2119. SCODE scResult = S_OK;
  2120. TRY
  2121. {
  2122. // prepare the buffers
  2123. // fetch the script and
  2124. // a bunch of rows.
  2125. // If not all rows fit in
  2126. // the buffer, call again.
  2127. _rQuery.Refresh();
  2128. *pCount = 0;
  2129. scResult = DB_S_TOOMANYCHANGES;
  2130. }
  2131. CATCH( CException, e )
  2132. {
  2133. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion);
  2134. scResult = GetOleError(e);
  2135. }
  2136. END_CATCH;
  2137. return scResult;
  2138. }
  2139. //+---------------------------------------------------------------------------
  2140. //
  2141. // Member: CRowset::GetStatus, public
  2142. //
  2143. // Synopsis: Return query status
  2144. //
  2145. // Arguments: [pdwStatus] -- pointer to where query status is returned
  2146. //
  2147. // Returns: SCODE error code
  2148. //
  2149. // Notes:
  2150. //
  2151. //----------------------------------------------------------------------------
  2152. STDMETHODIMP CRowset::GetStatus(
  2153. DWORD * pdwStatus
  2154. ) {
  2155. _DBErrorObj.ClearErrorInfo();
  2156. SCODE scResult = S_OK;
  2157. TRY
  2158. {
  2159. *pdwStatus = 0;
  2160. _rQuery.GetQueryStatus( _hCursor, *pdwStatus );
  2161. }
  2162. CATCH( CException, e )
  2163. {
  2164. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetQueryStatus);
  2165. scResult = GetOleError(e);
  2166. }
  2167. END_CATCH;
  2168. return scResult;
  2169. }
  2170. //+---------------------------------------------------------------------------
  2171. //
  2172. // Member: CRowset::GetStatusEx, public
  2173. //
  2174. // Synopsis: Return query status
  2175. //
  2176. // Arguments: [pdwStatus] - returns query status
  2177. // [pcFilteredDocuments] - # of documents filtered
  2178. // [pcDocumentsToFilter] - # of docsuments yet to filter
  2179. // [pdwRatioFinishedDenominator] - ratio finished denominator
  2180. // [pdwRatioFinishedNumerator] - ratio finished numerator
  2181. // [cbBmk] - # of bytes in pBmk
  2182. // [pBmk] - bookmark for piRowBmk
  2183. // [piRowBmk] - returns index of bookmark in table
  2184. // [pcRowsTotal] - current # of rows in table
  2185. //
  2186. // Returns: SCODE error code
  2187. //
  2188. // Notes:
  2189. //
  2190. //----------------------------------------------------------------------------
  2191. STDMETHODIMP CRowset::GetStatusEx(
  2192. DWORD * pdwStatus,
  2193. DWORD * pcFilteredDocuments,
  2194. DWORD * pcDocumentsToFilter,
  2195. DBCOUNTITEM * pdwRatioFinishedDenominator,
  2196. DBCOUNTITEM * pdwRatioFinishedNumerator,
  2197. DBBKMARK cbBmk,
  2198. const BYTE * pBmk,
  2199. DBCOUNTITEM * piRowBmk,
  2200. DBCOUNTITEM * pcRowsTotal )
  2201. {
  2202. _DBErrorObj.ClearErrorInfo();
  2203. SCODE scResult = S_OK;
  2204. TRY
  2205. {
  2206. *pdwStatus = 0;
  2207. CI_TBL_BMK bmk = WORKID_TBLFIRST;
  2208. if ( cbBmk != 0 )
  2209. bmk = _MapBookmark( cbBmk, pBmk );
  2210. _rQuery.GetQueryStatusEx( _hCursor,
  2211. *pdwStatus,
  2212. *pcFilteredDocuments,
  2213. *pcDocumentsToFilter,
  2214. *pdwRatioFinishedDenominator,
  2215. *pdwRatioFinishedNumerator,
  2216. bmk,
  2217. *piRowBmk,
  2218. *pcRowsTotal );
  2219. }
  2220. CATCH( CException, e )
  2221. {
  2222. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetQueryStatus);
  2223. scResult = GetOleError(e);
  2224. }
  2225. END_CATCH;
  2226. return scResult;
  2227. }
  2228. //+---------------------------------------------------------------------------
  2229. //
  2230. // Member: CRowset::GetReferencedRowset, public
  2231. //
  2232. // Synopsis: Return the related rowset for a hierarchical query.
  2233. //
  2234. // Arguments: [iOrdinal] -- ordinal of column for bookmark
  2235. // [riid] -- IID of desired interface
  2236. // [ppReferencedRowset] -- interface pointer returned here
  2237. //
  2238. // Returns: SCODE error code
  2239. //
  2240. // Notes:
  2241. //
  2242. //----------------------------------------------------------------------------
  2243. STDMETHODIMP CRowset::GetReferencedRowset(
  2244. DBORDINAL iOrdinal,
  2245. REFIID riid,
  2246. IUnknown ** ppReferencedRowset
  2247. ) /*const*/ {
  2248. _DBErrorObj.ClearErrorInfo();
  2249. if (0 == ppReferencedRowset)
  2250. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetInfo);
  2251. *ppReferencedRowset = 0;
  2252. if ( iOrdinal > _ColumnsInfo.GetColumnCount() ||
  2253. (0 == _pRelatedRowset && 0 == iOrdinal && _fForwardOnly))
  2254. return _DBErrorObj.PostHResult(DB_E_BADORDINAL, IID_IRowsetInfo);
  2255. if ( 0 == _pRelatedRowset && 0 != iOrdinal )
  2256. return _DBErrorObj.PostHResult(DB_E_NOTAREFERENCECOLUMN, IID_IRowsetInfo);
  2257. //
  2258. // If it's the bookmark column, it's like a QI on this rowset.
  2259. //
  2260. if (0 == iOrdinal)
  2261. return QueryInterface( riid, (void **)ppReferencedRowset );
  2262. //
  2263. // Make sure the column is a valid chapter column.
  2264. //
  2265. const DBCOLUMNINFO & rColInfo = _ColumnsInfo.Get1ColumnInfo( (ULONG) iOrdinal );
  2266. if ( (rColInfo.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) == 0 ||
  2267. (rColInfo.dwFlags & DBCOLUMNFLAGS_ISROWID) != 0 )
  2268. return _DBErrorObj.PostHResult(DB_E_NOTAREFERENCECOLUMN, IID_IRowsetInfo);
  2269. return _pRelatedRowset->QueryInterface( riid, (void **)ppReferencedRowset );
  2270. }
  2271. //+---------------------------------------------------------------------------
  2272. //
  2273. // Member: CRowset::RestartPosition, public
  2274. //
  2275. // Synopsis: Set up CRowset so next GetNextRows will restart from beginning
  2276. //
  2277. // Arguments: [hChapter] -- chapter which should restart
  2278. //
  2279. // Returns: SCODE error code
  2280. //
  2281. // Notes:
  2282. //
  2283. // History: 16-Apr-97 emilyb wrote
  2284. //
  2285. //----------------------------------------------------------------------------
  2286. STDMETHODIMP CRowset::RestartPosition(
  2287. HCHAPTER hChapter
  2288. ) {
  2289. _DBErrorObj.ClearErrorInfo();
  2290. SCODE scResult = S_OK;
  2291. BOOL fNotified = FALSE;
  2292. TRY
  2293. {
  2294. if (! _fHoldRows)
  2295. _pRowBufs->CheckAllHrowsReleased();
  2296. CI_TBL_CHAPT chapter = _MapChapter(hChapter); // is chapter valid?
  2297. if ( !_pRowsetNotification.IsNull() &&
  2298. _pRowsetNotification->IsNotifyActive() )
  2299. {
  2300. scResult = _pRowsetNotification->OnRowsetChange(
  2301. this,
  2302. DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  2303. DBEVENTPHASE_OKTODO,
  2304. FALSE);
  2305. if ( S_FALSE == scResult )
  2306. THROW(CException(DB_E_CANCELED));
  2307. fNotified = TRUE;
  2308. }
  2309. _rQuery.RestartPosition(_hCursor, chapter);
  2310. if ( fNotified )
  2311. _pRowsetNotification->OnRowsetChange( this,
  2312. DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  2313. DBEVENTPHASE_DIDEVENT,
  2314. TRUE);
  2315. }
  2316. CATCH( CException, e )
  2317. {
  2318. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset);
  2319. scResult = GetOleError(e);
  2320. if (E_NOTIMPL == scResult)
  2321. {
  2322. scResult = DB_E_CANNOTRESTART;
  2323. }
  2324. }
  2325. END_CATCH;
  2326. if ( fNotified && FAILED(scResult) )
  2327. _pRowsetNotification->OnRowsetChange( this,
  2328. DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  2329. DBEVENTPHASE_FAILEDTODO,
  2330. TRUE);
  2331. return scResult;
  2332. }
  2333. //
  2334. // IDbAsynchStatus methods
  2335. //
  2336. //+---------------------------------------------------------------------------
  2337. //
  2338. // Member: CRowset::Abort, public
  2339. //
  2340. // Synopsis: Cancels an asynchronously executing operation.
  2341. //
  2342. // Arguments: [hChapter] -- chapter which should restart
  2343. // [ulOperation] -- operation for which status is being requested
  2344. //
  2345. // Returns: SCODE error code
  2346. //
  2347. // Notes:
  2348. //
  2349. // History: 09 Feb 1998 AlanW Created
  2350. //
  2351. //----------------------------------------------------------------------------
  2352. STDMETHODIMP CRowset::Abort(
  2353. HCHAPTER hChapter,
  2354. ULONG ulOperation
  2355. ) {
  2356. _DBErrorObj.ClearErrorInfo();
  2357. SCODE scResult = S_OK;
  2358. if ( DBASYNCHOP_OPEN != ulOperation )
  2359. {
  2360. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IDBAsynchStatus);
  2361. }
  2362. TRANSLATE_EXCEPTIONS;
  2363. TRY
  2364. {
  2365. CI_TBL_CHAPT chapter = _MapChapter(hChapter); // is chapter valid?
  2366. _rQuery.StopAsynch(_hCursor);
  2367. }
  2368. CATCH( CException, e )
  2369. {
  2370. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IDBAsynchStatus);
  2371. scResult = GetOleError(e);
  2372. if (E_NOTIMPL == scResult)
  2373. {
  2374. scResult = DB_E_CANTCANCEL;
  2375. _DBErrorObj.PostHResult(scResult, IID_IDBAsynchStatus);
  2376. }
  2377. }
  2378. END_CATCH;
  2379. UNTRANSLATE_EXCEPTIONS;
  2380. return scResult;
  2381. }
  2382. //+---------------------------------------------------------------------------
  2383. //
  2384. // Member: CRowset::GetStatus, public
  2385. //
  2386. // Synopsis: Returns the status of an asynchronously executing operation.
  2387. //
  2388. // Arguments: [hChapter] -- chapter which should restart
  2389. // [ulOperation] -- operation for which status is being requested
  2390. //
  2391. // Returns: SCODE error code
  2392. //
  2393. // Notes:
  2394. //
  2395. // History: 09 Feb 1998 AlanW Created
  2396. //
  2397. //----------------------------------------------------------------------------
  2398. STDMETHODIMP CRowset::GetStatus(
  2399. HCHAPTER hChapter,
  2400. DBASYNCHOP ulOperation,
  2401. DBCOUNTITEM * pulProgress,
  2402. DBCOUNTITEM * pulProgressMax,
  2403. DBASYNCHPHASE * pulAsynchPhase,
  2404. LPOLESTR * ppwszStatusText
  2405. ) {
  2406. _DBErrorObj.ClearErrorInfo();
  2407. SCODE scResult = S_OK;
  2408. if ( DBASYNCHOP_OPEN != ulOperation )
  2409. {
  2410. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IDBAsynchStatus);
  2411. }
  2412. TRANSLATE_EXCEPTIONS;
  2413. TRY
  2414. {
  2415. // NOTE: we don't support getting the status of chapters
  2416. // independently.
  2417. // CI_TBL_CHAPT chapter = _MapChapter(hChapter); // is chapter valid?
  2418. if (DB_NULL_HCHAPTER != hChapter)
  2419. THROW( CException( DB_E_BADCHAPTER ));
  2420. DBCOUNTITEM ulNumerator = 0;
  2421. DBCOUNTITEM ulDenominator = 0;
  2422. DBCOUNTITEM cRows;
  2423. BOOL fNewRows;
  2424. _rQuery.RatioFinished( _hCursor,
  2425. ulDenominator,
  2426. ulNumerator,
  2427. cRows,
  2428. fNewRows );
  2429. if (pulProgress)
  2430. *pulProgress = ulNumerator;
  2431. if (pulProgressMax)
  2432. *pulProgressMax = ulDenominator;
  2433. if (pulAsynchPhase)
  2434. *pulAsynchPhase = (ulDenominator == ulNumerator) ?
  2435. DBASYNCHPHASE_COMPLETE :
  2436. DBASYNCHPHASE_POPULATION;
  2437. if (ppwszStatusText)
  2438. *ppwszStatusText = 0;
  2439. #if CIDBG
  2440. if ( _fForwardOnly )
  2441. Win4Assert( ulDenominator == ulNumerator );
  2442. else
  2443. Win4Assert( ulDenominator >= ulNumerator );
  2444. #endif // CIDBG
  2445. }
  2446. CATCH( CException, e )
  2447. {
  2448. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IDBAsynchStatus);
  2449. scResult = GetOleError(e);
  2450. }
  2451. END_CATCH;
  2452. UNTRANSLATE_EXCEPTIONS;
  2453. return scResult;
  2454. }
  2455. //+---------------------------------------------------------------------------
  2456. //
  2457. // Member: CRowset::GetSpecification, public
  2458. //
  2459. // Synopsis: Return the session or command object used to create this rowset
  2460. //
  2461. // Arguments: [hChapter] -- chapter which should restart
  2462. //
  2463. // Notes:
  2464. //
  2465. // History: 01-28-98 danleg Created
  2466. //
  2467. //----------------------------------------------------------------------------
  2468. STDMETHODIMP CRowset::GetSpecification(
  2469. REFIID riid,
  2470. IUnknown ** ppvSpecification
  2471. ) {
  2472. _DBErrorObj.ClearErrorInfo();
  2473. if ( 0 == ppvSpecification )
  2474. return _DBErrorObj.PostHResult( E_INVALIDARG, IID_IRowsetInfo );
  2475. SCODE sc = S_OK;
  2476. TRANSLATE_EXCEPTIONS;
  2477. TRY
  2478. {
  2479. *ppvSpecification = 0;
  2480. if ( _xUnkCreator.IsNull() )
  2481. return S_FALSE;
  2482. sc = _xUnkCreator->QueryInterface( riid, (void ** )ppvSpecification );
  2483. if ( FAILED(sc) )
  2484. THROW( CException(sc) );
  2485. }
  2486. CATCH( CException, e )
  2487. {
  2488. sc = _DBErrorObj.PostHResult( e, IID_IRowsetInfo );
  2489. }
  2490. END_CATCH;
  2491. UNTRANSLATE_EXCEPTIONS;
  2492. return sc;
  2493. }
  2494. //
  2495. // IServiceProperties methods
  2496. //
  2497. //+---------------------------------------------------------------------------
  2498. //
  2499. // Method: CRowset::GetPropertyInfo, public
  2500. //
  2501. // Synopsis: Get rowset properties
  2502. //
  2503. // Arguments: [cPropertySetIDs] - number of desired properties or 0
  2504. // [rgPropertySetIDs] - array of desired properties or NULL
  2505. // [pcPropertySets] - number of property sets returned
  2506. // [prgPropertySets] - array of returned property sets
  2507. // [ppwszDesc] - if non-zero, property descriptions are
  2508. // returneed
  2509. //
  2510. // History: 16 Nov 95 AlanW Created
  2511. //
  2512. //----------------------------------------------------------------------------
  2513. SCODE CRowset::GetPropertyInfo(
  2514. const ULONG cPropertySetIDs,
  2515. const DBPROPIDSET rgPropertySetIDs[],
  2516. ULONG * pcPropertySets,
  2517. DBPROPINFOSET ** prgPropertySets,
  2518. WCHAR ** ppwszDesc)
  2519. {
  2520. _DBErrorObj.ClearErrorInfo();
  2521. if ( (0 != cPropertySetIDs && 0 == rgPropertySetIDs) ||
  2522. 0 == pcPropertySets ||
  2523. 0 == prgPropertySets )
  2524. {
  2525. if (pcPropertySets)
  2526. *pcPropertySets = 0;
  2527. if (prgPropertySets)
  2528. *prgPropertySets = 0;
  2529. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);
  2530. }
  2531. SCODE sc = S_OK;
  2532. *pcPropertySets = 0;
  2533. *prgPropertySets = 0;
  2534. if (ppwszDesc)
  2535. *ppwszDesc = 0;
  2536. TRANSLATE_EXCEPTIONS;
  2537. TRY
  2538. {
  2539. sc = _PropInfo.GetPropertyInfo( cPropertySetIDs,
  2540. rgPropertySetIDs,
  2541. pcPropertySets,
  2542. prgPropertySets,
  2543. ppwszDesc );
  2544. // Don't PostHResult here -- it's a good chance it's a scope
  2545. // property that we're expecting to fail. Spare the expense.
  2546. // The child object will post the error for us.
  2547. }
  2548. CATCH( CException, e )
  2549. {
  2550. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IServiceProperties);
  2551. sc = GetOleError(e);
  2552. }
  2553. END_CATCH;
  2554. UNTRANSLATE_EXCEPTIONS;
  2555. return sc;
  2556. }
  2557. //+---------------------------------------------------------------------------
  2558. //
  2559. // Method: CRowset::SetRequestedProperties, public
  2560. //
  2561. // Synopsis: Set rowset properties via IServiceProperties (not supported)
  2562. //
  2563. // Arguments: [cPropertySets] - number of property sets
  2564. // [rgProperties] - array of property sets to be set
  2565. //
  2566. // History: 16 Nov 95 AlanW Created
  2567. //
  2568. //----------------------------------------------------------------------------
  2569. SCODE CRowset::SetRequestedProperties(
  2570. ULONG cPropertySets,
  2571. DBPROPSET rgPropertySets[])
  2572. {
  2573. _DBErrorObj.ClearErrorInfo();
  2574. if ( 0 != cPropertySets && 0 == rgPropertySets)
  2575. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);;
  2576. return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IServiceProperties);;
  2577. }
  2578. //+---------------------------------------------------------------------------
  2579. //
  2580. // Method: CRowset::SetSuppliedProperties, public
  2581. //
  2582. // Synopsis: Set rowset properties via IServiceProperties (not supported)
  2583. //
  2584. // Arguments: [cPropertySets] - number of property sets
  2585. // [rgProperties] - array of property sets to be set
  2586. //
  2587. // History: 16 Nov 95 AlanW Created
  2588. //
  2589. //----------------------------------------------------------------------------
  2590. SCODE CRowset::SetSuppliedProperties(
  2591. ULONG cPropertySets,
  2592. DBPROPSET rgPropertySets[])
  2593. {
  2594. _DBErrorObj.ClearErrorInfo();
  2595. if ( 0 != cPropertySets && 0 == rgPropertySets)
  2596. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);;
  2597. return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IServiceProperties);;
  2598. }
  2599. //+---------------------------------------------------------------------------
  2600. //
  2601. // Method: CRowset::AddRefChapter, public
  2602. //
  2603. // Synopsis: Increment the ref. count to a chapter
  2604. //
  2605. // Arguments: [hChapter] - handle to chapter
  2606. // [pcRefCount] - pointer to chapter ref. count
  2607. //
  2608. // Notes: Chapter references are obtained via an accessor from the
  2609. // parent rowset, but they are addref'ed in the child rowset.
  2610. //
  2611. // History: 15 Mar 99 AlanW Created
  2612. //
  2613. //----------------------------------------------------------------------------
  2614. STDMETHODIMP CRowset::AddRefChapter(
  2615. HCHAPTER hChapter,
  2616. ULONG * pcRefCount
  2617. ) {
  2618. tbDebugOut(( DEB_TRACE, "CRowset::AddRefChapter called!\n" ));
  2619. _DBErrorObj.ClearErrorInfo();
  2620. if (0 == _pChapterRowbufs)
  2621. return _DBErrorObj.PostHResult(E_FAIL, IID_IChapteredRowset);
  2622. if (DB_NULL_HCHAPTER == hChapter)
  2623. return _DBErrorObj.PostHResult(DB_E_BADCHAPTER, IID_IChapteredRowset);
  2624. SCODE scResult = S_OK;
  2625. TRANSLATE_EXCEPTIONS;
  2626. TRY
  2627. {
  2628. _pChapterRowbufs->AddRefChapter(hChapter, pcRefCount);
  2629. }
  2630. CATCH( CException, e )
  2631. {
  2632. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IChapteredRowset);
  2633. scResult = GetOleError(e);
  2634. }
  2635. END_CATCH;
  2636. UNTRANSLATE_EXCEPTIONS;
  2637. return scResult;
  2638. }
  2639. //+---------------------------------------------------------------------------
  2640. //
  2641. // Method: CRowset::ReleaseChapter, public
  2642. //
  2643. // Synopsis: Decrement the ref. count to a chapter
  2644. //
  2645. // Arguments: [hChapter] - handle to chapter
  2646. // [pcRefCount] - pointer to chapter ref. count
  2647. //
  2648. // Notes: Chapter references are obtained via an accessor from the
  2649. // parent rowset, but they are released in the child rowset.
  2650. //
  2651. // History: 15 Mar 99 AlanW Created
  2652. //
  2653. //----------------------------------------------------------------------------
  2654. STDMETHODIMP CRowset::ReleaseChapter(
  2655. HCHAPTER hChapter,
  2656. ULONG * pcRefCount
  2657. ) {
  2658. tbDebugOut(( DEB_TRACE, "CRowset::ReleaseChapter called!\n" ));
  2659. _DBErrorObj.ClearErrorInfo();
  2660. if (0 == _pChapterRowbufs)
  2661. return _DBErrorObj.PostHResult(E_FAIL, IID_IChapteredRowset);
  2662. if (DB_NULL_HCHAPTER == hChapter)
  2663. return _DBErrorObj.PostHResult(DB_E_BADCHAPTER, IID_IChapteredRowset);
  2664. SCODE scResult = S_OK;
  2665. TRANSLATE_EXCEPTIONS;
  2666. TRY
  2667. {
  2668. _pChapterRowbufs->ReleaseChapter(hChapter, pcRefCount);
  2669. }
  2670. CATCH( CException, e )
  2671. {
  2672. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IChapteredRowset);
  2673. scResult = GetOleError(e);
  2674. }
  2675. END_CATCH;
  2676. UNTRANSLATE_EXCEPTIONS;
  2677. return scResult;
  2678. }
  2679. STDMETHODIMP CRowset::Stop( )
  2680. {
  2681. SCODE scResult = S_OK;
  2682. TRY
  2683. {
  2684. _rQuery.StopAsynch(_hCursor);
  2685. }
  2686. CATCH( CException, e )
  2687. {
  2688. scResult = GetOleError(e);
  2689. }
  2690. END_CATCH;
  2691. return scResult;
  2692. }